TOP > プログラマ2.0日報 > プログラミング文章読本~インターフェイスの「読みやすさ」

あすなろBlogger

このエントリーを含むはてなブックマーク このエントリーをはてなブックマークに追加 この記事をクリップ! livedoorclip ユーザー数 BuzzurlにブックマークBuzzurlにブックマーク この記事をtweetする

プログラミング文章読本~インターフェイスの「読みやすさ」

2009.02.11

仕事で出くわした他人のソースから。

private void sub( MyObj obj, int a, String b ) {
  SomeClass sc = new SomeClass();
  sc.setA( obj, 8 );
  sc.setB( obj, a );
  sc.setC( obj, b );
}

実はですね、このコード見たとき、私

あれ??何をこのコードはやっているんだろう???

と、処理の意味が少しも理解できなかったのですね。だって、

  1. 1. setter ではインスタンス sc に対する副作用として、「sc のプロパティに値がセットされる」はずだ。
  2. 2. setter の引数である obj は、実質 final であって、SomeClass#setA() などの後も、変更がないはずだ。
  3. 3. だから、この sub() を呼ぶ前と、呼ぶ後で、計算上の「状態」は実質的に何も変わっていないはずだ...(変わったインスタンス sc は単に捨てられている)

と「インターフェイスから」推論しちゃったわけです。

勿論、このコードについては私の推論が誤ってます: SomeClass#setA() などは、標準的なセッタの前提に従っておらず、引数を加工しちゃう副作用を持ちます。つまり、このコードの書き方は、

誤解を招く、非常に判りづらいコード

なのですね。じゃあ、何が悪いんでしょう?

それはですね、副作用をコードとして明示する、という観点を大きく欠いている、という点なのです。たとえば、こういうコードだったら、何も混乱しません。

private MyObj sub( MyObj obj, int a, String b ) {
  SomeClass sc = new SomeClass();
  obj = sc.buildA( obj, 8 );
  obj = sc.buildB( obj, a );
  obj = sc.buildC( obj, b );
  return obj;
}

こっちのコードでは、引数に渡したのと同じ変数で、sc.buildA() などの戻り値を受けています。ですから、引数と戻り値で何か状態が変わっている、ということがコードに明示されているわけです。まあ勿論 setter じゃないのに「値がセットされるから setA()」なんてネーミングはやめましょうね。

その考え方でいけば、この sub() というメソッドも、同様に呼び元から見た場合、副作用があるメソッドです。ですから、ちゃんと引数として渡された obj を返す戻り値ありのメソッドに変更されています。

このように「副作用を明示するインターフェイスを作ること」という原則は、非常に重要なものと私は考えています。要するに標準的なセッタでは、

引数には何も副作用がないから、void を返すのだ

と逆に捉えなおしてもいいくらいではないか?などと思います。また、

今までは引数に値を直接セットしても良かったけども、それがまずくなって、コピーしたものをもらえるようにしたい...

と前提が変わったとしてもインターフェイスを何も直さなくてもOKですよね! 実際戻り値を捨てても動作は変わらないのですが、戻り値をあえて受けることで、メソッドの実装詳細(戻り値は引数と同じインスタンスか違うか?)を抽象化できることに結果としてなるわけです...

また、多分こういうケースでは、buildA() によって、SomeClass のインスタンス sc 自体は、何も影響を受けていないことがほとんどでは?とも思われます。つまり、これは

private MyObj sub( MyObj obj, int a, String b ) {
  obj = SomeClass.buildA( obj, 8 );
  obj = SomeClass.buildB( obj, a );
  obj = SomeClass.buildC( obj, b );
  return obj;
}

として良いケースが多いでしょう。インスタンスへの副作用がなくても、継承上書きの都合で、インスタンスメソッドであって欲しいこともあるでしょうが、こういうケースでも

public MyObj buildA( MyObj obj, int n ) {
  return SomeClass.buildA(obj, n);
}

とstatic メソッドを覆ってやるくらいのことをしてもいいでしょうね....

つまりですね、

まったく同じように動くコードであっても、ちょっとした書き方の違いで、メンテのしやすさ・判りやすさが極端に変わる....

わけで、現実問題として今は

どう動くかコンピュータに伝えるコストよりも、同僚に「どう動くか」伝えるコストの方がずっと決定的

な時代なのです。ですから「読みやすいインターフェイス」を心がけることは重要ですよ!

投稿者 : 杉浦 こずえ | 投稿日時 : 2009.02.11 16:53

あすなろBLOGのトラックバック・コメントは承認制になっています。
すぐにブログに反映されませんので、ご了承ください。

トラックバックURL


コメントの送信








関連記事

カレンダー

<< 2009年02月

1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28

最新のエントリー

最新のトラックバック

最新のコメント

Tag

バックナンバー