オブジェクト指向設計からの学び

https://qiita.com/advent-calendar/2018/goodpatch 23日目

Goodpatchでは、Prottというプロトタイピングツールを内製しており、そこのバックエンドを主に担当しています。

ProttではAPIサーバーをRailsで構築しています。なので普段業務では、Rubyを中心に開発をしています。Prottチームで開発をはじめて早半年が経過しました。その中で最近私の関心事である設計というところで自分の中での整理も含め、文字に起こそうと思います。

オブジェクト指向に対する自分の考え

ここはオブジェクト指向設計において言われている基本的な思想に完全に同意しています。

前提として、一般的に変更をしないサービスというものは存在しないと思っています。一回作って終わりではなく、何度も変更を重ねることでサービスを成長させていくフローが一般的だと思います。このような一般的なアプリケーション開発の中の変更という部分に対して、設計というものががとても力を発揮します。

オブジェクト指向設計では、変更を予測するのではなく、将来変更されうる余地・選択肢を残しておくような設計をすることが基本的な設計思想になってきます。

その中でも実現場でのチームでの開発を通して、最近設計フェーズでとても良く考えることがあります。それは、そのクラス・メソッド・オブジェクトの責務についてです。

責務とはその名のとおり、対象が担う責任のことです。

オブジェクト指向言語では、オブジェクト同士のやり取りをメッセージングを通して行います。その中の一つの振る舞いが複数の責任を持っていた場合、そのふるまいを呼び出すオブジェクトはその振る舞いの中のことまで知らないといけないことになります。
小さいアプリケーションかつ一人で開発している状況であれば問題はさほど大きくならないですが、チーム開発をし、アプリケーションが大きくなるにつれ、そのような複数の責務を担っている振る舞いを持っている構造はオブジェクト同士の関係を密結合にし、振る舞いの再利用性、変更容易性に対して悪影響をもたらします。
例えば、振る舞いの変更で予期せぬ部分でバグが発生することによる開発効率の低下、ソースコード自体の可読性の低下、似たような振る舞いが定義されているメソッドが大量に発生するなどです。

そのため正しく責務を分離することができている振る舞いは、結果としてオブジェクト同士の関係や振る舞いが疎結合になります。

ここで責務を正しく分離することのメリットとしていかがあると思っています。

  • 再利用性の向上
  • コードの可読性の向上
  • 変更容易性の向上

これらはチームで開発をする上ではとても重要な要素になってくると思います。

責務の分離を普段から意識するために

開発では、機能改善とともに新機能の開発も活発に行っています。

責務の分離を意識することは、

  • 既存の機能改善: リファクタリングの方針を導く鍵になる
  • 新機能開発では、コードの健康状態を保ったまま機能追加をすることができる

があると思っています。

また責務の分離を考えるときに自分が一番大事だと思っていることがあります(これは私自身とても苦手な領域なので、これからも精進していきたいところです。)。

それは命名です。少し命名に関して思っていることを書きます。

命名を考えることは、すなわち責務を考えることである。

正直これに尽きるかなと思っています。これは、クラス名、メソッド名、モジュール名と開発をする上では避けては通れない道です。命名の難しいところは、良くない命名でもシステム的には動いてしまうという点にあると思っています。命名が悪いですというシステムエラーはないので、命名は実装者の裁量によってしまいがちです。命名に関しては、その都度開発者が意識し続けなければいけない問題であり、アンチパターンはありますが、正解というものが明確に定義されていないものです。

開発者が常に接する命名というものに対して責務のつながりがあるとするならば、命名を考えることで責務を日常的に意識して設計をすることができるといえます。

早すぎる最適化

早すぎる最適化はオブジェクト指向設計や責務の分離などを考える際に自分がよく陥ってしまうところになります。

オブジェクト指向設計に慣れていない場合、いつの間にか推測で最適化をしてしまっているケースがあります。これは、私が最初に述べた変更を予測するのではなく、将来変更されうる余地・選択肢を残しておくような設計をするに反しています。ただ設計の担当者になるとどこまでがもともと知っている情報で、どこからが担当者が実装をする上で暗黙的に理解している内容なのかの線引をするのはとてもむずかしいと思います。

まだ将来的にどうなるかわからない責務の分離に関しては、分離させやすいように実装しておき、分離をするための要件があがってきたときに初めてそこの責務の分離を関心事として捉えるべきだと思っています。

まとめ

上記のような考察は誰でもくぐる道だと思っています。プログラミング言語やフレームワークの知識をつけることもとても大事です。しかし設計の思想を知らず知識だけがついていった場合は、プログラミング言語の魔法のような力に頼った実装をしてしまいがちだと思います。一人で開発、運用をしていくサービスならそれもいいと思いますが、チームで開発をする以上サービスに対しても一緒に働いている他のエンジニアの人に対しても親切なコードを書くために設計はとても大事なものだと思っています。

まだまだ未熟ものではありますが、設計とプログラミング言語やフレームワークなどの知識を両方兼ね備えてエンドユーザにもチームのエンジニアに対しても親切な設計と開発をすることができるようになりたいと思っています。

ありがとうございました 。