オブジェクト指向設計実践ガイド4章を読んだ感想

4章読み終えた。この章は「柔軟なインターフェースを作る」話。今回もかなり読み応えがあって、特に 4.3のパブリックインターフェースを見つける、のところはすごく勉強になった。また読み返したい。特に勉強になったところは、オブジェクト指向を考えるとき、オブジェクト同士が、どうメッセージのやりとりするかを考えると、より柔軟なアプリケーショを書けけるようになると述べられてた部分で、これができるようになると、設計者のキャリアとしても転機が起きてることがいえるらしく、すごく重要な考えなんだと思った。

内容的には、この本で挙げられてる例を踏まえると、一応わかった気にはなるのだけど、実際にこのメッセージ的な設計の考えを、今やってる開発(Laravel)とかで当てはめようとすると、いまいちピンとこなかった。いまいちピンとこなかったところとしては、この本でオブジェクトのメッセージについて説明している例(Tripクラスが、自転車の準備状態のチェックを、Mechanicクラスにメッセージを送って確認するっていう例)を、コントローラやモデル、サービスクラスなどで、どんな感じで当てはめたらいいのかわからず、難しいというような感じ。そもそも、どういうクラスが必要で、各クラスたちにどういう責任を持たせておくべきか、みたいなとこから考え切れてないので、そういうとこも原因の一つだと思うけど、それでもむずそう。頑張って理解していけるようにする。

あと、メッセージに基づく設計の方が、柔軟性があるアプリになる理由を少し考えてみた。オブジェクト同士のメッセージって、依存関係が発生するような場所になりやすそうな感じなので、そこを中心にするってことは、依存関係の管理とかをより中心的に見れるようになり、それでより柔軟性のあるアプリになる感じなのかなと思ったりした。概念はわかったので、あとは実践していけるようにする。実践していくにあたり、オブジェクト間のメッセージを見つけることもすごく重要で、シーケンス図を使って探すのがめちゃめちゃ良さそう。なので、シーケンス図もっと使っていけるようにする。設計初心者がたどる「オブジェクト」指向なコードの動きを表した図が紹介されてて、そこでの設計初心者の状態を早く抜けれるよう頑張りたい

以外、本読んで、気になったところや重要そうだと思ったところ抜粋

4.1 インターフェースを理解する

  • 丸は、オブジェクトを表してる
  • 上記図の左側のやつは、いろんなものを明らかにしすぎてて、いろんなとこにアクセスできてる。上記図の右側のやつは、制約をつけてるので、特定のとこにしかアクセスできないようになってる
  • 左側のやつは、もはや再利用不可能。依存性注入や、単一責任などをちゃんと設計できててても、このような状態になる可能性があって、大事なポイントとしては、クラスが何を「する」かではなく、何を「明らかにする」かを設計しないといけない
  • 設計で考慮したいこと(明らかにしたいこと)

    • オブジェクトが何を知っているのか(責務)
    • オブジェクトが誰を知っているのか(依存関係)
    • オブジェク同士がどうやって会話するのか(メッセージをやりとりするのか)
      • オブジェクトの会話は、オブジェクトの「インターフェース」を介して行われる
  • オブジェクトにアクセスする際に必要なのがインターフェース。インターフェースの概念は色々あるけど、この章では、クラス「内」にあるインターフェースの話

    • クラス内にあるインターフェース
      • クラスは、メソッドを実装し、そのうちいくつかは他のオブジェクトから使われることが意図されている。
      • それらのメソッドがそのクラスのパブリックインターフェースを構成する
    • クラス内にあるインターフェース、以外にもインターフェースの概念はいくつかあって、例えば、複数クラスにまたがって、どの単一のクラスからも独立してるもの、があげられたりする
      • これは5章のダックタイピングでコストを削減するのところで話す

4.2 インターフェースを定義する

  • インターフェースとは、オブジェクトにアクセスするための入り口
  • レストランで例えると、メニューはパブリックなインターフェースと書いてあるのがわかりやすかった(お客さんは、選んだメニューがどうやって作られるかは知らなくていい)
  • パブリックインターフェースを作るメソッドによって、クラスが外の世界に顔をだす
  • パブリックインターフェースの特性
    • クラスの主要な責任を明らかにする
    • 外部から実行されることが想定される
    • 気まぐれに変更されない
    • 他者がそこに依存しても安全
    • テストで完全に文書化されてる
  • プライベートインターフェースの特性
    • 実装の詳細に関わる
    • 他のオブジェクトから送られてくることは想定されていない
    • どんな理由でも変更されえる
    • 他者がそこに依存するのは危険
    • テストでは言及されないこともある

4.3 パブリックインターフェースを見つける

  • パブリックインターフェースを見つけて定義する
    • クラスの主要な責任を見つけて定義する
    • パブリックインターフェースの設計が良いと、変更に対するコストが下がる
      • なぜ?
  • アプリケーションを新規で作成するときに、いい感じのインターフェースを発見する方法
    • ツールを使う
      • シーケンス図
      • ユースケース(要件)を満足させるために、必要なオブジェクトとメッセージの両方を検討する際、まずコードを書かなくても良い
    • ドメインオブジェクト
      • アプリケーションの性質から、なんとなくどんなクラスが必要なのか検討をつくものがある
      • それはデータと振る舞いの両方を兼ね揃えた名詞だったりする。これをドメインオブジェクトという
      • ドメインオブジェクトは、最終的にデータベースに表されるものだといえる
      • ドメインオブジェクトは簡単に見つけられるけど、設計するときに中心になるものではない。注意を向けるべきなのは、オブジェクト間で交わされるメッセージ
        • なぜ?
  • シーケンス図
    • シーケンス図を使うことで、オブジェクト間がどんなメッセージを交わすかわかりやすくなる
    • ユースケースでの名詞は、オブジェクトになる
    • ユースケースでのアクションは、メッセージになる
    • オブジェクトは、パブリックインターフェースを介してのみ、お互いに交信すべきなので、シーケンス図を書くことで、パブリックインターフェースを明らかにできる
    • シーケンス図を書くことによって、議論が逆転する
      • クラスに基づく設計からメッセージに基づく設計へ
      • 「このクラスが必要なのは、知ってるけど、これは何をすべきなんだろう」から「このメッセージを送る必要があるけど、誰が応答すべきなんだろう」へ
  • 適切に定義されたパブリックインターフェースをもつ再利用可能なクラスを作るポイント
    • 「送り手の望みを頼むメッセージ」と「受け手にどのように振る舞うかを伝えるメッセージ」の違いを考える
    • メッセージをやりとりする際の「何を」対「どのように」の重要性
      • オブジェクト間でメッセージのやりとりをするとき、「どのように」の部分まで、振る舞いを知っている必要はなくて、「何を」の部分だけにできると、依存関係が小さくなっていよい。オブジェクト同士は、お互いをあまり知りすぎないほうが、コードのメンテナス性や柔軟性が向上する
  • 図4.5から4.7は、設計初心者がたどる「オブジェクト」指向なコードの動き
  • 図4.5では、TripはMechanicに「私は自分が何を望んでいるかを知っているし、あなたがそれをどのようにやるかも知ってるよ」と伝える

  • 図4.6では、TripはMechanicに「私は自分が何を望んでいるかを知っていて、なあなたが何をするかも知っているよ」

  • 図4.7では、TripはMechanicに「私は自分が何を望んでいるかを知っているし、あなたがあなたの担当部分をやってくれると信じているよ」

  • まだ、定義されていないオブジェクトが必要である認識を得るための方法

    • シーケンス図を使う
    • Consumerから発信されるメッセージ(適切な旅行を見つけるためのメッセージ)、を受け取るオブジェクトが定義されていない
      • 適切な旅行を見つける責任を持ったオブジェクト
      • 適切な旅行を見つける振る舞いをするオブジェクト

4.4 一番良い面(インターフェース)を表に出すコードを書く

  • 明示的なインターフェースを作る。パブリックインターフェースに含まれるメソッドは、次のようなものであるべき
    • 明示的にパブリックインターフェースだと特定できる
    • 「どのように」よりも「何を」になっている
    • 名前は、考えられる限り、変わり得ないものである
    • オプション引数として、ハッシュをとる

4.5 デメテルの法則

  • デメテルの法則とは
    • オブジェクトを疎結合にするためのコーディング規則の集まり
    • 列車事故を除去する方法で、委譲を使う方法がある
      • 列車事故は、異なる型のオブジェクトを複数繋げて、メッセージを送ること
      • 委譲とは、他のオブジェクトにメッセージを渡すこと
      • 委譲を実現する方法はいろいろあって、forwardable.rbとか使ったりする
      • これらは、それぞれオブジェクトが自身に送られたメッセージを自動的に捉え、どこか他のところへ送り直すのを簡単にするために存在してる
    • 参考
    • 委譲サンプルコード
  • デメテルの法則は、委譲をたくさん使っていこう、という話ではなくて、長いメソッドチェーンで繋がってて、欲しい振る舞いがかなり遠くにいるのがよくないって話
  • なので、もっと近くでメッセージをやりとりできるよう、新しくオブジェクトを作る
  • デメテルの法則違反(メソッドチェーンで連なった列車事故)は、パブリックインターフェースが足りてなくて、発生するので新しくパブリックインターフェすを作る際のヒントにできる

全体的な感想

  • むずいけど、少しづつわかってきた感もあるので、引き続き頑張る
  • この考え方を元に、実際にコードをかけることが重要なので、取り入れていけるよう頑張る