【読書感想文】レガシーソフトウェア改善ガイド
最近ビジネス本ばかりだったのでたまにはエンジニアらしく。
だらだら書き綴ってしまいました…
上手にまとめるって難しいですね。

Author
クリス・バーチャル 著
吉川邦夫 翻訳
Date
2017.8.19
Highlighted & Summary
コードがレガシーに(というのは、大ざっぱに言って、保守が困難に)なるほとんどの原因は、技術ではなく人間に関係している。
つまり、技術的に改善すれば、ソフトウェアの改善されるとは限らないということ。
第1章 レガシープロジェクトの難題を理解する
ドキュメントを残す。
- (自分を含めた)後にメンテナンスする人が、保守しやすい形で。
- READMEかもしれないし、コード上、テストなど。複数のフォーマットがあると思うが、どの場に適したドキュメントを残し続ける。
レガシーソフトウェアは、たいがい大きく、古く、誰か他の人から受け継いだもので、ろくなドキュメントがない。
常にテストしやすい設計を。
- テストをしやすい設計できません。
- テストを書くことで、最終的な成果物の保証はある程度できるようになりましたが、あくまでそれは最終的なものなので、内容を精錬させていきたい。
レガシーソフトウェアは、しばしばテストが抜けているし、テストするのが困難だ。テストが困難ならば、実行されるテストも少ないはずで、その逆も真である。
コードベースに現在わずかなテストしかなければ、たぶんテストしにくい設計を含んでいるはずであり、そのために新しいテストを書くことが難しくなっているのだ。
レガシーコードは、しばしば柔軟性が乏しい。つまり、単純な変更を加えるのにも大量の仕事が必要になる。この状況は、リファクタリングによって改善できるだろう。
レガシーソフトウェアは、何年も累積された技術的負債によって、動きが取れなくなっている。
環境の整備も忘れない。
- 自動化することで環境毎の差異をなくすこと。
コードが実行される基盤(インフラストラクチャ)には、開発者のマシンから製品まで、注意を向けるべきである。
改善によるメリットを最初に明文化しておく。
- リファクタリングは確かに大事な作業だと思いますが、現状だと(最悪リファクタリングしなくても)動作しているため短期的には、メリットが少ない。
- なので、単に「レガシーだったので、改善しました。」ではダメで、“なぜその部分の改善が必要なのか。’’・“改善によって、どのようなメリットがあるのか。”を周知しておく必要があると思います。
ソフトウェアを保守するチームのカルチャーが、改善を妨害する場合がある
第2章 スタート地点を見つける
“未知への恐れ”を克服する最良の方法は、そのコードをいじくり回すこと。
- そうすることで心理的な障害は取り去られていくはず。
- 心理的な障害を取り去って、改善のメリットが見えたら、あとはテストしやすいサイズにリファクタリングする。
レガシーコードベースに対して、あなたが合理的に取り組むのを邪魔するような心理的障壁を自覚しよう。
計測基盤をつくることが、リファクタリングの効果を高める。
- 改善の前後での品質を確認できる状態にしておくべき。
リファクタリングを始める前に、そのガイドとなる計測の基盤を作ろう。
データを活用して、どこに努力を集中させればよいかを認識し、どれほど進捗したかを計測しよう。
ソフトウェアの品質を数値化し、その数値が、時間の経過に従って、どのように変化したかを示す。
リファクタリングの次のターゲットを選択する基準とするため。そのターゲットは、(何らかの指標に従って)他のコードよりも品質が劣る部分か、あるいは、その部分をリファクタリングすることによってチームが大きな価値を得られるような部分だ(チームの開発者たちがバグ修正や新機能を実装するとき、しばしば触れるクラスなら、その候補となるだろう)。
第3章 リファクタリングの準備
自戒を込めて…
リファクタリングは常に、組織の目標を念頭に置いて行う必要がある。
言い換えると、誰があなたに給料を払っているのかを忘れてはいけない。
リファクタリングは、それがビジネスに長期的な価値をもたらすと、あなたが証明できるときにだけ行うべきだ。
リファクタリングは、それを目的として行うことができない。
ビジネス的な価値を提供して、関係者の全員から合意を得る必要がある。
また、いつ終了し、成功したのか、誰でもわかるように、プロジェクトは明白なゴールを掲げるべきだ。
コミュニケーションを取り続ける。
レガシーコードベースの改造はチームワークで行う必要がある。
作業を開始する前に、あなたのチームが円滑にコミュニケーションをして、共通の目標に向かって協力するように気を付けるべきだ。
なぜリファクタしないといけないのか。リファクタによって得られるメリットはなにか。それらをきちんと把握してそれを共有する。
他の人々が書いたコードに、過度のリファクタリングやリライトを行うと、技術的な影響だけでなく、人間関係にも思わぬ影響があるかも知れない。
自分たちが書いたコードを、急進主義者が情け容赦なく見境なしに書き換えているのを見たら、他の開発者たちが憤慨し、チームの雰囲気が険悪になりそうだ。
彼らは急進主義者と会話するのが、ますます嫌になって、チーム内で共有される知識も減ってしまう。
リファクタリングの優先度を意識する。
コードベースの中で、よく更新される部分を改善する(つまり読みやすくし、保守と拡張を容易にする)リファクタリングは、どのみち置き換えが予定されているコードのリファクタリングよりも価値が高い。
すべてのリファクタリングが平等なわけではない。
ほとんどのリファクタリングは、価値(value)、難度(difficulty)、リスク(risk)の3 つの軸によって、いくつかのカテゴリーに分類できる。
必ず、その価値と難度とリスクによって評価すべきである。
経験則として、選択肢は次の順に考慮すべきだ
1. 置き換え
2. リファクタリング
3. リライト
20%ルールを適応する。
- 言わずと知れた“20% ルール”を使って、品質の向上に貢献する。
- 20%は1日の業務時間を8時間とすると、1時間30分ほど。(夕方の集中力が途切れがちな時間にでも…)
最初に許可を求めることなく、リファクタリングの作業を開始する。 作業は少しずつ行い、ほかの仕事を妨げるほどの時間は費やさない(これが20%の意味である。消費するのは自分の時間の2 割までにすること)。
シェアに値する結果を得たら、秘密を明かす。
あなたの仕事をチームに公開してレビューしてもらう。
「よくやった」とチームメイトに賞めてもらう。
彼らのフィードバックに基づいて、チーム全体が品質に満足するまで改善する。
機能を細かく分離して、徐々に改善を進める。
- 結果として、テストしやすいコードにも繋がることになるので、機能を最小単位で切ることを意識する。
大きな変更は、コードベース全体をいっぺんにアタックするのではなく、そのソフトウェアを分割した各部のひとつひとつに対してインクリメンタルに行うのがよい。
第4章 リファクタリング
リファクタリングをするときは、それだけに集中する。
リファクタリングを成功させるには規律が必要だ。リファクタリングは、組織化された方法で実行し、他の仕事と混ぜるのを避けよう。
できるところからリファクタリングを進める。
古いコードや質の悪いテストを削除するのは、リファクタリングを進める優れた手段だ。
リファクタリングの対象となるようなコードはそもそも書かない。
null 参照やヌルポインタを使うのは、どんな言語でも、ごく一般的なバグの元である。
状態は、ミュータブル(可変)よりイミュータブル(変更不可能)が望ましい。
標準的なデザインパターンを使うことで、ビジネスロジックと実装の詳細を分離することも、複雑なビジネスロジックを、より管理しやすく組み合わせやすいコンポーネントにすることもできる。
複雑なロジックをアプリケーションのビューレイヤーから外すには、ビューアダプター(View Adapter)のパターンを使おう。
ユニットテストは銀の弾丸ではない。
- テストが考慮されてないレガシーコードをリファクタするときは、外側から始める。つまり、テストを書いてからだんだんと可能な限り内部に入っていく。
テストは、複数の抽象レベルで行って、リファクタリングによるリグレッションを防衛しなければならない。
ユニットテストだけでなく、できるだけ多くのテストを自動化しよう
第5章 リアーキテクティング
モノリスなコード
- すべてのソースコードが1つのディレクトリ内で管理され、1つのバイナリファイルとしてビルドされるコードベース。
モジュール・コンポーネント
- アプリケーションのソースコードの一部で、別々のフォルダで管理され、別々のバイナリファイルとしてビルドされるもの。
- モジュールは、他のモジュールにインターフェイスを提供するだけで、互いの実装について何も知らない。
モノリスなアプリケーション
- 全体が、1 台のマシン上で、1 個のプロセス内で実行されるアプリケーション。
サービス
- アプリケーションの他の部分から隔離され、(HTTPなどの)ネットワークプロトコルによるメッセージを介してのみ通信できるソフトウェア。
- 言語に依存しないフォーマット(たとえばJSON やXML など)を使って、メッセージの送受信を行うのが普通である。
- サービス指向アーキテクチャ(service-oriented architecture:SOA)と呼ばれることも。
マイクロサービス
- とくに結合度が低く、境界のあるコンテクストを持つ、サービス指向アーキテクチャ(SOA)
モノリスからの脱却
サイトをモノリス的なアプリケーションとして実行するのは、タマゴを全部同じ袋に入れるようなものだ
モノリス的なアプリケーションを実行する場合、どのような変更にもアプリケーション全体をダウンさせるリスクがある。このために、組織が変更を恐れ、テストに時間をかけすぎることがあるかも知れない。
- モノリスなコードベースを複数のモジュールに分けるときは、モジュール間の依存関係を明確に定義する必要に迫られるので、コードを理解しやすくなる。
- モノリスなアプリケーションからの脱却のメリット・デメリットを自分が取り組むプロダクトに落とし込んで、理解する。
メリット
いったんコードベースをモジュール化したら、それらのモジュールを自由な方法で組み合わせることができる。
- 全部をモノリス的な方法で実行する
- 個々のモジュールを別々なマイクロサービスとして実行する
- 一部のモジュールを破棄して他のモジュールに担当させる
などなど。
デメリット
大きなアプリケーションを分割することで得られるモジュール性は、一般によいことではあるが、弱点を生む可能性もある。
元のモノリス的なアプリケーションと比べて、個々のモジュールは小さくて自己完結しているから、ソースコードの複雑さは減少するはずだが、そのソースコードの管理は、より複雑になる。
SOA・マイクロサービスを導入するにあたって。
それぞれのサービスは、あるサービスの新バージョンを、いつでも他のサービスに影響を与えることなく配置できるように、互いに結合を断たれていなければならない。
したがって、次のようになるはずだ。 API の他に、サービス間でコミュニケーションを行う手段が存在しない。
API の約束を破る変更は、どんな犠牲を払ってでも防止しなければならない。
モノリスから脱却を絶対に達成しないといけないわけではない…?
あなたのアプリケーションのためにアーキテクチャを選ぶ際は、技術的にも組織的にも、数多くのトレードオフがある。
たとえばモノリスの代わりにマイクロサービスを選ぶとしたら、要求のレイテンシが高まる結果になるかも知れない(要求をサービスするのに複数のネットワークホップが発生する可能性があるから)。
けれどもチームは、より大きな自立性を持ち、市場に出すまでの時間を短くすることが可能になるだろう。
SOA・マイクロサービス化によるサービスの分離は、チーム間のコミュニケーションがより必要になる。
チームをサービスごとに分けると、それらのチームに自立性が与えられ、たいがい仕事を素早く終わらせることができるが、チーム間の協調が必要になると、大きく遅滞する可能性がある。
第6章 ビッグ・リライト
大規模なソフトウェアプロジェクトは、範囲を文書化すべきだ。
リライトは、できるだけインクリメンタルにすべきだ(たとえ、それによって全体の労力が増えたとしても、リスクを軽減するために)。
既存の実装を「究極の真実のソース」として扱いたい、という誘惑に抵抗しよう。価値あるリファレンスとして扱うべきで、そこから新しい仕様を派生させるのを許そう。
第7章 開発環境を自動化する
効果的なドキュメント
- README!
README ファイルをソースコード用リポジトリのルートフォルダに置くのが、最も効果的なドキュメンテーションだ。
README はリポジトリで最も重要なファイルだ。
- とは言っても適材適所があるので、ドキュメントの場所は適切な場所に配置する。
あなたのソフトウェアについては、もっと詳しいドキュメントを書きたくなるかも知れない。
たとえばアーキテクチャの説明とか、製品で何か問題が生じたときのトラブルシューティングなどだ。
けれども、それらはREADME に入れるべきではない。
追加の文書は、wiki に書けばよいだろう(そしてリンクをREADME に入れておく)。あるいは、リポジトリにdocs フォルダを作り、その中で別のMarkdown ファイルを書くのもよい。
第8章 テスト、ステージング
環境の差異によって発生するバグは、絶滅させる。
TEST 環境とPROD 環境の間、あるいは、ある環境の個々のマシンの間に「ばらつき」があるのは、バグが生じやすい危険な状態である。
- プロビジョニングの自動化が必要
プロビジョニングの自動化は、インフラストラクチャに対する変更に、制御と追跡管理をもたらす。これは、ソースコードにバージョン管理システムを導入するのと、よく似ている。
DEV 環境では、すべてを1 個のVM に詰め込みたいが、TEST 環境は、可能な限りPROD 環境に近づけたい。
同じAnsible スクリプト群を、すべての環境に使おう。それには、環境毎の設定を、変数とインベントリファイルによってコード化する。
第9章 レガシーソフトウェアの開発
知識の共有はドキュメントによって解決できる。
- と言っても注意は必要!(ドキュメントはメンテナンスの必要があるので)
手作業のステップを記述するメモがREADME ファイルにあるだけでも、非常に有効な場合がある。
けれどもドキュメンテーションの問題点は、必ず更新されるという保証がないことだ。もっと微妙な問題もある。
開発者はドキュメントが正しくメンテナンスされているとは信じられず、最初から疑ってかかる傾向があるのだ。
たとえあなたがREADME ファイル内の記述を几帳面にメンテナンスしていても、それを読む人は最悪のケースを想定するだろう
ツールを使って、プロセスをコード化することで様々なプロセスの自動化を進める。
- このコードはドキュメントとしても使用できるので、ドキュメントがメンテナンスされていないという自体は避けられる。
手作業で行うデプロイのプロセスは、時が経つと簡単に失われる知識だが、そのプロセスを自動化すれば、将来アプリケーションをデプロイできなくなるリスクが軽減される。
複雑なデプロイタスクを自動化するには、Fabric のようなツールを使える。そのスクリプトは、プロセスのさまざまなステップを示すドキュメントとしての役割も果たす
第10章 レガシーコードを書くのはやめよう!
ソフトウェアプロジェクトの成功の要因とは?
- ソースコードの高い品質
- ユーザーにとってより良い価値の提供
- コミュニケーション
- 開発効率
- 障害対策
ソフトウェア事業の成功に必要な組織的な要因とは?
よいドキュメンテーションがあること
開発チームの中での(また、チーム間での)コミュニケーションを増やすこと
チームの外にいる人がソフトウェアに貢献しやすくすること
ソフトウェアの品質を尊ぶカルチャーを組織全体に育んで、開発者がビジネスの他の部分からの圧力にさらされることなく十分な時間を品質の維持に費やせるようにすること
情報を共有し続けること。
自分が今何をやっているか。
何に困っているか。
何を学んだのかを言語化することは大事なこと。
- 有益なドキュメントを残すことを意識する。
技術的なドキュメントは、開発者から同時代の同僚たちに、また、将来の保守担当者たちに情報を渡す素晴らしい手段となり得る。
ただし価値あるドキュメントにするには、次の条件が必須だ。
有益である(つまり、ただコードが何をしているかを述べるだけでなく、なぜ、どのように行っているかを知らせる)。
-書きやすい。
-見つけやすい。
- 読みやすい。
- 信頼できる。
- ドキュメント以外の方法ある。
コードレビュー
いまどき、その是非を論じるまでもない。コードへの変更は、すべて、少なくとも1 人の他の開発者によってレビューされなければならない。
コードに間違いがないかをチェックし、スタイルの問題を議論できるだけでなく、他の開発者の仕事について、より多く学ぶことができる。
あなたのチームに適したコードレビューのシステムを見つけるために、時間を割くべきだ。誰かのIDE を囲むのがよいかも知れず、GitHub のようなオンラインサービスを使うのがよいかも知れない。
ペアプログラミング
これは開発者にとって論争の的になる。
ある人々は大好きであり、ある人々は大嫌いだ。
私は、まずは数週間やってみることを勧める(最初の気持ち悪さを開発者が乗り越えるのには、それだけあれば十分だ)。
それから、まだ続けたいか、続けるならどういう方法がよいかを、皆で決めてもらう。
目標は、頼まれなくても開発者が自発的にペアリングを始めるような状況を作ることだ。
テックトーク
私が勤務したことのある2 つの会社では、金曜日の午後にテックトーク(tech talk)を開催していた。
それはしばしば私にとって、週の山場になった。
テックトークは、プレゼンターにとって、自分のスキルや作ったものを披露する機会であり、聴衆にとっては、他の人々がいま何をやっているのかを学ぶ機会になる。
定期的なコードレビュー
- 継続してやっていかないといけないことがたくさんあるので、インクリメンタルに仕事をし続ける。
割れた窓はすぐに直す
まずは、コードベースの「割れ窓」を、2 週間にひとつでも直すことを、あなたの個人的な目標にしよう。
そして、その努力が他の開発者たちからも見えるようにしよう。コードレビューは、口づてに話を広めるのによいツールだ
よりよいプロジェクトのために…!
- よりよりコミュニケーションを。
よいテクニカルドキュメンテーションの価値は非常に高い。けれども、ドキュメンテーションが不要なくらいのコミュニケーションがチームにあれば、もっとよい。
メンバーがチームを離れるときに知識が失われるのを防ぐために、ドキュメントは必要である。
けれども、開発者がドキュメントを参照するより、互いに質問するほうを好むなら、それは健康的なチームの証しだ。

