続 setter/getter は不要

友人との議論で、掲題について質問をもらった。質問に答える過程で、さらに深く考えることができたので、続きを書く。

そもそものエントリはsetter/getter は不要である。このエントリにおいて、次のような趣旨の主張をした。

  • 単にフィールドにアクセスするだけの getter/setter の例を見かける。これらは不要である。
  • 処理に有意なラベル付けがされていれば、たとえ処理が単純なgetter/setterであっても有意義である。
  • あるクラスの属性が、フィールドなのかgetter/setterなのかというのは、クラスの内部設計である。これらがソースコード上の差異として表面化してしまうJavaという言語は不完全である。この点、C#のプロパティは優れている。

議論の場が飲み会だったこともあり、友人とは多少不完全な情報共有のまま議論したが、おおよそ次のような反論をもらった。要は「レビュアーとしてはC#構文はやっかいだ」ということらしい。

  • setterの役割は、フィールドにアクセスするだけではない。妥当性チェックも重要な処理である。
  • しかしながら、世の中のプログラマには、妥当性チェックを省いてしまう人が多い。合理的判断に基づく省略ではなく、「処理抜け」として省いてしまう。これは一種のバグであるから、発見されなくてはならない。これを効果的に検出できるのはコードレビューである。
  • しかるに、C#のプロパティ構文は、この検出を困難にする。Javaにおいては、属性へのアクセスがsetterに依っているのであれば、妥当性チェックが実装されていることが期待できる。悪くても、後から処理を追加することができる。しかしC#の構文では、本来隠蔽されるべきフィールドがpublicに書かれているという最悪ケースを構文から発見することができない。したがって、スキルレベルが混交するチーム開発において、C#構文はデメリットである。

なるほど、一理ある。レビュアーという立場であれば、バグ誘因を効率的に見つけ出す必要があり、そのサインとしてフィールドなのかgetter/setterなのかというポイントを活用できるということだろう。

飲み会の場では次のようにgdgdに反論してしまった。これらは正しいが、空論だった。反省している。

  • そのポリシーは「契約による設計 (DbC: Designed by Contract)」と「カプセル化」に違反している。
  • DbCによれば、クラスが公開(public)するものは、実装に依らずに契約(contract)が定められる。したがって、その値の妥当性チェックが必要かどうかは、契約にどう定義されているかによる。なんでもかんでもgetter/setterにすべきというのは原理主義である。
  • どうせ、setterとしてメソッド化したところでチェックは省略できてしまうので、setter強制の利点は限定的である。
  • 後から修正しやすいという点については、修正が他のコードに影響しないという点で、C#構文が勝っている。

 

私がエントリで主張したかった真意は、いま改めて考えるに、setter という存在そのものが異常だ、ということだったように思う。

オブジェクト指向では、メソッド(メッセージ)は、クラスに対する“依頼”のようなものである。であるから、Car.moveTo とか、Document.print などといったように、モノ・コト+動詞として解釈できるような抽象度でメソッドが定義される。

しかしながら、getter/setter というのは、乱暴なまでに開けっぴろげである。setX なんて、Xという変数に値を設定する、というふうにしか読めないし、getXもしかりだ。これは本来は、setXによって達成される某かの効用を取り出してメソッドとするべきではないか。たとえば、car.setSpeed(car.getSpeed() + 10) とするのなら、car.accelerate(10) が適切かもしれない。

このような理由により、私は getter/setter という存在そのものをいぶかしく思っている。そのようなメソッドが設計に存在する時点で、洗練されたカプセル化が行われていない兆候として受け取ってしまう。たとえ各種チェックがあろうとなかろうと、内部のフィールドが意味の抽象化なしに公開されている時点で、何か妙だと思う。(余談だが、改めて思い起こすと、私の各プログラムにはsetterはほとんど存在しないし、getter は readonly であることがおおい。)

 

なお、setter が必要な場合も当然ある。たとえば、アプリケーションの設定(settings)を扱うクラスにはsetterがたくさんあって当然だろう。私は、そのような必然性がある場合まで否定しているわけではないことに注意されたい。