オブジェクト指向設計実践ガイドを読む No.4【柔軟なインターフェースをつくる】その 2
こんばんは、sasumasa です。
前回投稿した「オブジェクト指向設計実践ガイド」の第 4 章「柔軟なインターフェースをつくる」の続きを書いていきます。
前回はオブジェクト指向設計にはメッセージ(以下メソッド)が重要であること、そしてその理由についてまとめました。その理由とは以下の 3 つです。
1. 外部に晒すメソッドの管理をすることはクラス同士の依存関係の管理につながるから
2. クラス内のメソッドの責務を管理することは柔軟なメソッドを作り出すだけでなく、クラスの責務を明確に表すから
3. メソッド同士のやりとりに注目することで、必要なクラスを導き出せるから
この理由のうち、1 と 2 については上記の記事で少しだけ触れました。今日は 3 について考えていきたいと思います。
ユースケースからクラスを導き出す
皆さんは日頃コードを書くとき、どうやってユースケースから必要なクラスを導き出しているでしょうか?
Rails エンジニアであれば必要なクラスのいくつかは DB のテーブルと対応してることが多いと思います。users テーブルがあれば User クラスは作成すると思います。
今回の趣旨でいう「クラス」とは、そういったモデル以外のクラスです。具体的なビジネスロジックを持ち、アプリケーションの中で何らかの計算や処理、外部 API とのやりとり、場合によっては DB への CRUD 処理などをするオブジェクトです。
人によっては、経験からそういったクラスの存在に気づく方もいると思います。僕もある程度のロジックであれば、そこまで特別なことはしなくても必要なクラスを考えてコードを書くことはできます。
しかし、全く 0 から必要なクラスが簡単には想像がつかない場合にはどうしたらいいでしょうか?
その時に本書では UML (Unified Modeling Language) を利用します。UML は実際僕も業務で利用したことがあるので、経験も踏まえながら説明していきたいと思います。
UML とシーケンス図
UML は設計などを考える時に使われる記述方法です。詳しい説明は他のサイトを参考にしてみます。
UMLとはUnified Modeling Languageの略語です。日本語では「統一モデリング言語」と呼ばれています。複雑なシステム開発をグラフィカルに表現し、記述方法を統一することで設計書の読みやすさやコミュニケーションの効率アップに役立ちます。
つまり、設計やコミュニケーションの効率を上げるために記述方法を統一する際に使われる言語です。
本書ではオブジェクト指向設計を考える際に、ユースケースに対してどんなクラスが必要かを考える時に UML を使っています。
そして、この UML を使ったシーケンス図こそが必要なクラスを見つけ出すのに役に立ちます。シーケンスずとは UML を利用してその名の通りシーケンス(一連の流れ)を示す図のことです。これは、あるユースケースが達成されるまでの流れを示します。
このシーケンス図がなぜ設計に役立つのでしょうか?
シーケンス図が設計に役立つ理由
具体的なシーケンス図はこんな感じのものです。
まず矢印を上から見てみると、Alice から Bob へ「Authentication Request」という文字とともに矢印が伸びています。Alice が Bob に認証リクエストを送った、という意味です。
次に Bob はそれを考えて(thinks about it)、最後にレスポンスとして認証レスポンス(Authentication Response)を返します。これが一連のシーケンスというわけです。
実際のサービス(例えば Rails)では Alice は Client だったり、Bob は Controller だったり Model だったりするわけですが、要領は同じです。このようにシーケンス図を書くことで見えてくることがあります。そのメリットをまとめると以下のようになります。
1. 設計を言語化する機会を得られる
2. メッセージ(メソッド)を中心とした思考に切り替えることができる
3. 時間がかかる具体的な実装よりも前に、設計について簡単にまとめることができる
言語化する機会を得られる
見ての通り、シーケンス図は設計者の思考を具現化したものです。「ログイン機能を作って」と言われた時に設計者の中で浮かぶ「A が必要だな、B はどうすればいいんだろう、C もしなきゃな・・・」といった考えをシーケンスとして示すことになります。それは同時に考えていることを言語化する必要に迫られるということです。
言語化することで自分の漠然としていた考えが明らかになりより設計を詰めることができます。シーケンス図を使うことによって言語化の機会が得られることは大きなメリットの 1 つと言えるでしょう。
メソッドを中心にした設計を考えられる
このシーケンスですが、上の例でいう Bob や Alice の存在に気づかなくとも書くことができます。ログイン機能の例では「とにかく認証リクエストと認証レスポンスがあるな」とわかっていれば矢印は書くことができるのです。すると書いていくうちに気づくことも出てきます。「認証リクエストが何度も失敗したらロックする必要はあるんじゃないか?」とか「5 回失敗したらそのセッションからのリクエストは 15 分間拒否しよう」などです。そしたらリクエストするオブジェクトとレスポンスをするオブジェクトの他に別のオブジェクトが必要だというのがわかります。
このように、送るべきメソッドに集中することによって隠れたオブジェクトに気づき、良い設計について気づくことができるというのがシーケンス図を書くメリットとして挙げられます。
設計ファーストを実現できる
シーケンス図を書くことに慣れると、自然と設計から始めることが当たり前になります。
僕のようなまだキャリアの浅いエンジニアの方は特に共感してくれると思うのですが、スケジュールや実装に焦っている時ほど設計からしっかり考えることをすっ飛ばしてコードを書き始めてしまいます。
それは吉と出る時もあれば凶と出る時もあるでしょう。その凶を避けるための魔除けとして、このシーケンス図は活用できると思います。
理想を言えばまだ慣れていない間はほとんどの場合においてシーケンス図を書くことがいいのですが、現実的な答えとしては自分が設計をミスったら問題になりそうな機能の実装ではシーケンス図の作成を選択肢に入れるのが妥当と言えるでしょう。例えば納期が近い中で複雑な機能を実装することになったとか、後から作り直しをするコストが大きすぎる、などです。
今回はここまでです。オブジェクト指向設計実践ガイドの第 4 章「柔軟なインターフェースをつくる」をざっくりまとめました。設計においてはわかりやすい「クラス」だけでなく、インターフェース、つまりメソッドについて考えることも重要です。
ユースケースを達成するためにどんなメソッドが必要になるのか、そのメソッドはどこまでを外部に晒し、どこは内部に隠すのか。これらを考えることで、そのメソッドの変更容易性や拡張性を確保するだけでなく隠れていたクラスの存在まで浮き彫りにすることができます。
Discussion