コード : 変数の直接アクセス

Kent Beck の書籍から。

ガレージのドアを制御するプログラムを書く場合、どれが読みやすいか?

doorRegister = 1 ;

doorOpen() ;

door.Open() ;

もちろん、下に行くほど「やりたいこと」をうまく表現している。
制御ビットに1を立てるという実装の詳細より、ドアを開ける、という意図を表明したコードの方が読みやすい。
もちろん、実装方法の変更にも強い。

基本は、直接アクセスより、メソッドで間接アクセスにして、メソッド名に意図を表す名前をつけるのが良い。

どの範囲で x=1 という直接アクセスの記述をOKとするか、いろいろ選択肢がある。

・アクセサメソッドの内部とコンストラクタの内部に限定する (最も限定するパターン)
・クラス内はOK
・サブクラスまでOK
・パッケージ内はOK
...

Kent Beck は、「一般的なルールはない。自分で考え、まわりと議論し、勉強しろ! それがプロになっていくということ」と書いていますね。 ( Implementation Patterns p.46 )

私は、できるだけ制限する最初のパターンがベストだと思っていました。
同じクラス内でも、アクセサ以外は、アクセサを使うというパターンですね。

でも、ドメイン駆動を勉強するようになってから、わりと小さなクラスを作るようになり、「クラス内は直接アクセスOK」派に転向しました。

x=1 式の記述は、直接的で分かりやすい。同じクラス内で、わざわざアクセサを使うより、理解も速いし、まちがいが少ないと思います。でも、小さなクラス限定です。

大きなクラスを、意図が明確な複数のクラスに分割していくリファクタリングでアクセサを活用しています。
でも最終形は、クラス内では直接アクセスにする。

1.アクセッサメソッド式にして、できるだけ間接アクセスにする。
2.関連が強いフィールドとアクセサをまとめて小さなクラスに抽出する。
3.抽出したクラスに割り当てることが適切なメソッドを、そちらに移動する。
4.移動したメソッド内でアクセサを使っていたら、フィールドの直接アクセスにインライン化

という感じです。

変更率 ( Rate of Change )

Kent Beck の 読みやすいコードの6原則の最後。

同じタイミングで変更するデータ、関連するロジックは、いっしょにすべき。

具体例:(書籍から)

金額を通貨単位といっしょに扱う例ですね。

setAmount( int value, String currency )
{
 this.value = value ;
 this.currency = currency ;
}

value と currency はいつもセットだからいっしょにすると分かりやすい。
Money オブジェクトを作る。

setAmount( int value, String currency )
{
 this.value = new Money( value, currency ) ;
}

パラーメータも2つはいっしょなので Money オブジェクトを使う。

setAmount( Money value )
{
 this.value = value ;
}

最初のサンプルコードでは、value と currency の関連性は、人間が判断する。コード上はばらばらに見える。

最後のサンプルコードでは、value と currency を Money にカプセル化し、かつ、詳細を情報隠蔽している。

int value
String currency

がコードに散在していたのを

Money value

にひとまとめにする。

これで、
・意図が明確になった (コードが業務つまり問題領域の用語になった)
・あちこちに同じコードを書かなくてよくなった
・通貨に関する知識を Money オブジェクトローカルにカプセル化できた

Kent Beck の「読みやすいコード」の原則とその具体例です。

調和 (Symmetry)

Kent Beck が 「実装のパターン」(Implementation Patterns) の中であげている六つの原則の一つが「調和 (symmetry)」。

本の中の具体例:

void process()
{
 input();
 count++;
 output();
}

このコードの真ん中の行だけが、他の行より具体的になっている。これは調和がとれていない、良くないパターン。

改善案は、真ん中の行もメソッド呼び出しにする。これでバランスがとれる(調和する)。

void process()
{
 input();
 incrementCount();
 output();
}

でも、これでは Kent Beck は満足しない。 incrementCount() は、「何をしているか」の説明で、「何をしたいか」という意図を表現できていない。

最終案は、

void process()
{
 input();
 tally();
 output();
}

// tally は「集計する」という意味

これで、全体が調和する。

このサンプルコードで変更した箇所は真ん中の行だけ。

count++;
incrementCount();
tally()

どれが一番読みやすいコードか?

Kent Beck は、 tally() が一番良いといっている。意図を的確に表現しているから。

count++ も、incrementCount() も、プログラミング、手続きの視点。

tally() は、業務の視点、つまりこのソフトウェアが実現すべき機能を表している。

これが一番良いコード、読みやすいコードだというのが Kent Beck の価値観なわけです。

私は、ドメイン駆動の視点からも、tally() が問題領域の言葉としてもっとも適切だと思う。

将来、業務上、 tally() つまり集計のルールが変わっても、変更箇所が明確で安全にかつ簡単に変更できそう。

Implementation Patterns (Addison-Wesley Signature)

評価:
Kent Beck
Addison-Wesley Pub (Sd)
¥ 4,960
(2007-11-15)
読みやすいコードを書くための最高の教科書だと思います。

JUnit の開発者の Kent Beck の考え方・価値観を、具体例をまじえて説明している。
英語ですけど、見出しとコードの例は、プログラムを書く人にはなじみのある単語ばかりなので、英語バリバリでなくても参考になると思います。

読みやすいコードを書くには、この本と、マーチンファウラーの「リファクタリング」の2冊を読むことが必要だし、また十分だと思います。

calendar
     12
3456789
10111213141516
17181920212223
24252627282930
31      
<< March 2024 >>
システム設計日記を検索
プロフィール
リンク
システム開発日記(実装編)
有限会社 システム設計
twitter @masuda220
selected entries
recent comment
recent trackback
categories
archives
others
mobile
qrcode
powered
無料ブログ作成サービス JUGEM