レガシーコード改善ガイドが面白かったので、その内容をメモしてみる。様々なテクニックが紹介されていたが、それをひとつひとつ書いていると長くなってしまうので、概要やコンセプトをメインに書こうと思う。
レガシーコードの変更手順
レガシーコードの変更手順は以下の様なものだ。これを基本として、様々な手法や例を交えて、章が進んでいく。
- 変更箇所を特定する
- テストするべき事柄を把握する
- 依存関係を排除する
- テストを書く
- 変更、修正(リファクタ)を行う
テストの重要さ
一貫して、テストを書かないコードこそレガシーコード、テストがなければどんなにきれいに書いても意味がない、Edit and Pray
ではなくCover and Modify
、ということを言っている。
正しいことを確認するだけでなく、変更を検知するためのテスト(リグレッションテスト)が書けるとよく、それがないのであれば、いかなる変更も安全とはいえないとのことが書いてある。
引用
- To me, legacy code is simply code without tests. I’ve gotten some grief for this
- Code without tests is bad code. It doesn’t matter how well written it is
- Working with care doesn’t do much for you if you don’t use the right tools and techniques.
- Cover and Modify is a different way of making changes. The idea behind it is that it is possible
- Do you want your feedback in a minute or overnight? Which scenario is more efficient?
- The beginnings of those iterations are terrible. People feel that they aren’t getting all the work done that they need to. But slowly, they start to discover that they are revisiting better code. Their changes are getting easier,
- The way to win is to concentrate effort on not putting bugs into code in the first place.
- In general, automated tests should specify a goal that we’d like to fulfill or attempt to preserve behavior that is already there.
- they(=リグレッションテスト) just sit there documenting what pieces of the system really do.
- The only problem is, if you don’t have tests, this can be pretty hazardous business. How do you know that you aren’t breaking anything when you do all of this refactoring to understand the code?
ユニットテストの利点
コンポーネントが結合された状態でのテストが巨大になるといくつか問題がある。
- エラーがどこで起きているのかパッと見でわからない
- 実行速度の増加
- カバレッジが下がる。コンポーネントが結合された状態だけではすべてをテストするのは難しい。
ユニットテストは結合テストではできないことをカバーできると述べている。ユニットテストの利点としては以下がある。
- 実行速度が早い
- エラーの特定が容易
逆に、ユニットテストがこれらをみたせていない時は、テスト自体を見直したほうがいいと述べている。
引用
- (ユニットテストであっても)Some tests are larger, and they use several classes together. In fact, they may seem to be little integration
- Over time, the test might end up taking as long as 1/10th of a second to execute.
- When you start to notice that your tests are too large, you should break down the class that you are testing, to make smaller independent pieces that can be tested more easily.
単一責任の原則(SRP)
単一責任の原則(SRP)について述べている。とある複雑なクラスに、実は複数の責任が押し付けられていることをコードを交えて説明がされる。複雑なクラスはテストができないし、テストのし易い単位でSRPに従ってコンポーネントをつくっていくことがレガシーコードの改善につながる。クラスやメソッドの責任が何であるかを見分ける方法を、多くのパターンによって説明している。
実装する際も「いま何をしている?」と聞かれてひとつの答えにならなければ、それは考え直した方がいいということを言っている。また、必然的にシンプルな問題をとくことや、ビルドの速さなどから、それが実装速度にも直結すると述べている。
引用
- What are the problems with big classes? The first is confusion.
- The first issue to confront when we have big classes is this: How can we work without making things worse?
- The key questions I asked were “Why is this method here?” and “What is it doing for the class?” Then I grouped them into lists, putting together methods that had a similar reason for being there.
- Learning to see responsibilities is a key design skill, and it takes practice.
- if you have the urge to test a private method, the method shouldn’t be private
- The way to really get better at identification is to read more. Read books about design patterns.
- More important, read other people’s code. Look at open-source projects, and just take some time to browse and see how other people do things.
- I’m working: “Programming is the art of doing one thing at a time.”
- I always ask my partner to challenge me on that, to ask me “What are you doing?” If I answer
- Frankly, it’s just faster.
- When I first started using these techniques, it was tempting to do too much. When I needed to extract
Seam
この本で出てくる重要なことばとしてSeam
というものがある。定義としては、その場所を直接編集しなくても、プログラムの振る舞いを変えることができる場所
というものだ。このSeam
を意識しながら、依存関係を排除していく例が詳しく示されている。
Seam
にはいくつか種類があり、実装パターンによって、どのように依存関係を排除していくかが説明されている。
引用
- One of the biggest challenges in getting legacy code under test is breaking dependencies.
- When you have a seam, you have a place where behavior can change.
- In general, object seams are the best choice in object-oriented
- Preprocessing seams and link seams can be useful at times but they are not as explicit as object seams. In addition, tests that depend upon them can be hard to maintain. I like to reserve preprocessing seams and link seams for cases where dependencies are pervasive and there are no better alternatives.
Sprout Method
テクニックのほんの一例だがSprout Methodを紹介しようと思う。
Sprout Methodは、テストのないレガシーコードに追加で機能開発をする際に、新しくテスト済みのコードを実装して、徐々にカバレッジをふやしていく(レガシーコードをそれ以上増やさない)実装である。手順としては以下の様なものだ。
- どこを変更するのか明らかにする。
- 既存ソースの修正したい箇所をコメントアウトする(コメントアウトしておくと、開発中にすぐに戻れる点が良い)。
- 引数や戻り値を確認する。
- TDDを用いながら、新しく別の場所にメソッドを実装する。
- コメントアウトした箇所で、新しいメソッドを呼び出すよう置き換える。
メソッドだけでなく、Sprout Classの手法も紹介されていた。このように、既存のコードを壊さずに新しくテストされたコードを追加していくのが本書では重要だとされていた。
依存関係の図化
テストのないコードでは、時に人力で、その依存関係や影響範囲を調べる必要がある。そのために、依存関係を図化することが重要とされていた。手順としては以下の様なものだ。この依存関係の洗い出しは、他の手法にも多々応用されている。
- 変更をあたえるメソッドを明らかにする。
- そのメソッドに戻り値があるのなら、メソッドの呼び出し先も確認する。
- メソッドが変更する値がひとつでもあれば確認する。その値を使用するメソッド、また、その先があればさらに確認する。
- クラスの継承元やインスタンスも確認する。
- パラメータがどこから来ているのかを確認する。
- グローバルな値や静的なデータが変更されていないか確認する。
引用
- How do we know that these are the right methods to use? In this case, the problem is simple. When we’ve identified those as the points of change, we can start to sketch effects.
- Try to analyze effects in code whenever you get a chance.
- it’s important to know what can be affected by the changes we are making.
- Extract Method is a core technique for working with legacy code. You can use it to extract duplication, separate responsibilities, and break down long methods.
ちょっといい話
引用
- For some people, it is a paycheck, and there isn’t anything wrong with that—we all have to make a living. But there really ought to be some other reason why you are programming.
- it really doesn’t matter what kind of system you are working on. You can do neat things with it.
- The key to thriving in legacy code is finding what motivates you.
- TDD some code outside of work. Program for fun a little bit. Start to feel the difference between the
まとめ
少々ストレートすぎる言い回しが多いと感じたが、その分モチベーションはあがるし、勉強になる点、今後取り入れていきたい点も非常に多い書籍だった。JavaやC++でのサンプルもいい勉強になった(面白かった)と思う。既存のレガシーコードへの向き合い方だけでなく、どうすればレガシーコードにならないか、綺麗なコードを保てるかという側面も大きいので、直近でレガシーコード開発案件がない人にもオススメだと思った。
以上、レガシーコード改善ガイドの内容メモでした。