レガシーコード改善ガイドを読了したので、読書メモです。
- レガシーコード改善ガイド - マイケル・C・フェザーズ
分厚い本だけれども、とても良書だった。挫けそうだった時に読んだので、心に染み入るように文章が心に響いた。
もっとも、自分は仕事ではC言語のレガシーコードと戦っているのて、オブジェクト思考的な手法は使えない。そういう部分は読み飛ばした。
いろいろと心に残ったことはあるけれども、抜粋して書き出します。
整合部・形容点
以下、書籍から定義を引用します。
接合部
接合部(seam)とは、その場所を直接参照しなくても、プログラムの振る舞いを変えることのできる場所である。
許容点
どの接合部も許容点(enabling point)を持つ。許容点では、どの振る舞いを使うかを決定できる。
この2つの概念は大事。どんなコードも、依存関係を排除できる可能性があるということ。諦めてはいけいなということ。鋭い感性で、ズバッと許容点を探しだすスキルを磨くことが大事だ。
スプラウトメソッド
スプラウトメソッドとは、新規追加する機能は関数として抜き出して(スプラウトして)実装する方法。関数の呼び出しもとは、ドロドロの依存関係でテストがかけないれども、できたてホヤホヤの関数ならばテストがかけるはず。
if文のリファクタリングによく使う。こんなの。
if( (hogehoe && uhauha) ||
(iyaiya) ||
((mouiya) && (dameda)) )
場合によっては、ファイル自体をテストハネースに組み入れることができない。そんなときは、新しいファイルを新規作成して、機能を独立させて実装する(これをしたら怒られたけどれも)
ラップメソッド
ラップメソッドはスプラウトメソッドの逆。既存の処理は、関数として独立させて追い出す。汚い部分は追い出す。SmelllCodeをラップする。臭いものには、クレラップ。
if(smell){
/* 500 Step*/
}
ここに機能を追加しないといけないときは、ラップ関数を作成して、追い出す。
void lap(void) {
if(smell){
/* 500 Step*/
}
return 0;
}
あとは、きれいな関数たちでコードを書く。
seiketu();
lap();
プリプロセッサ接合部
このテクニックを知ったことは、一番の収穫かもしれない。プリプロセッサ接合部、便利すぎる!というか、すごいぞ!
例えば、コードの中にあるunko()が邪魔でしょうがない時は、プリプロセッサで消してしまえば良い。
#define unko{retrn 0}
スパイしたり、フェイクしたいときだって、置き換えは簡単。インクルードファイルを冒頭に書いてその先で後方置換してしまう。こんな風に、スパイだって自由自在だ。
hogehoge.c
#ifdef DEBUG
#include "Mock_unko.h"
#endif
Mock_unko.h
static int last_un;
static int last_ko;
void unko_Spy(int un, int ko)
{
last_un = un;
last ko = ko;
}
...
#define unko unko_Spy
多用し過ぎるとプロダクトコードがごっちゃになるとかで推奨されていないようだが、便利すぎるのでついつい使ってしまう。
仕様化テスト
振る舞いを維持するためには、テストが必要。しかし、その振る舞いすらよくわからないことがある。よく
いわれるのが
「仕様書を信じるナ!実機に聞け!」
実際の動作のみが唯一正しい真実なのだ。
この振る舞いを壊さないために、テストして明文化することでで、振る舞いを維持する。そのテストが仕様化テスト。
正直、今目の前にあるコードをテストで覆うのは無理!なので、既存処理に対する単体テストは諦めてる。とてもそんな工数はないし、コストパフォーマンスもない。そうではなくて、機能テストで覆うことに心の重点がシフトし始めている。それが、Fitnesseだったりする。