オブジェクト指向設計実践ガイド(POODR) 感想 & 第1章 まとめ

はじめに

はじめまして、Hikaruと申します。

私はいまプログラミングスクール フィヨルドブートキャンプ(以下FBC)でWeb開発を学んでいます。

そんな中FBCのカリキュラムとは別に、Practical Object-Oriented Design, An Agile Primer Using Ruby (POODR、オブジェクト指向設計実践ガイド原著の第2版)の輪読会を2022年1月から10月までおよそ10ヶ月かけて敢行しました。  

そして原著に加えて初版の邦訳版『オブジェクト指向設計実践ガイド』も読んでみました!この記事ではその感想と第1章のまとめを紹介していきたいと思います。

残りの章は今後何回かに分けて投稿していこうと思っています(本当は全部まとめて投稿するつもりでしたが、体調不良で寝込んでいたため予定変更です...)。

後述しますが日本語版と英語版では内容に大きな差はないので、英語版に限らずこれから日本語版を読もうとしている方でも参考にできると考えています!


この記事は...

これは「フィヨルドブートキャンプ Part 1 Advent Calendar 2022」の12日目の記事です。
Part2はFBCのメンターのcafedomancerさんが担当してくださってます!
ちなみにcafedomancerさんは前述のPOODR輪読会メンバーでもありました。その節はお世話になりました...ありがとうございました🙇‍♂️

昨日はHiromi Sugieさんの「Ruby初心者がAtCoderの過去問から多くの学びを得るために工夫していること」でした。
Part2はhirano-vm4(けだま)さんの「FBCと仕事の両立とふりかえり&卒業後は?」でした。


感想

POODRは一足飛びに完成形を示して「これが正解」とするのではなく、初心者がやりがちな失敗などを経ながら徐々ににコードを発展させていくので、理解が置いてけぼりにならずに済みました。
なぜこの設計がいけないのか、この設計に足りない視点はなにか、を踏まえつつ次に進むことでオブジェクト指向設計が達成しようとしていることに対する理解が自然に深まっていったように思います。

また、静的型付け言語と動的型付け言語を比較して説明を展開するパートもあったのですが、その部分は静的型付け言語の経験や知識がないとわかりづらかったように思います。
僕は静的型付け言語での開発経験はありませんが、『良いコード/悪いコードで学ぶ設計入門 保守しやすい成長し続けるコードの書き方』(通称ミノ駆動本)を同時並行で読んでいて、こちらは静的型付け言語であるJavaをサンプルとして使いながら設計について解説しているので、この二冊を読み合わせることで静的型付け言語と動的型付け言語の違いやそれぞれの良さをある程度理解することができたかなと感じています。

POODRを読んで良かったと思う点として、読み終わった後も「あ、これはPOODRに出てきたあのパターンだ!」とか「たしかこれについてPOODRで説明されていたな」と思い出しながら勉強することができたことがあります。
この本には本当に役立つ実践的な知識が詰まっていて、他の本やコードと知識がリンクするんですよね。 某ゼミじゃないですが、POODRを読む前と読んだ後ではプログラミング学習の楽しさが変わったような、そんな実感があります。

英語のレベルは?

僕の英語レベルは普通くらいだと思っていますが、べらぼうに難しかったです笑
特に単語のレベルが半端ではなく、英検準1級・1級レベルの単語が当然のように出てくるので、スラスラ読めるという感じではなかったですね。 英文自体もしっかりしていて、一文一文が日本語で言うところの重複文になっているので、これを読み終えた時は英文読解力が爆上がりしました笑
POODR輪読会を完走できたことが自信になり、現在はもっと英語ができるようになりたいと思えているのでその意味では頑張ってよかったなと思います。
明らかにひとりでは読み切ることができなかったので、一緒に輪読会をしてくれた英語に堪能なメンバーに感謝したいです。

日本語版(初版)との違いは?

オブジェクト指向設計に関わる部分では違いはありませんでした(気付いてないだけかも?)。初版で取り上げたRubyの機能のうち、第2版までにアップデートがあればそこを差し替えた、くらいの印象でした。
著者のSandi Metzさんも公式サイトで、「(新しい)Rubyの機能を使うようにいくつかの推奨事項をアップデートしていますが、細かい変更になるので単に初版を現代化しただけだと思っていただいて大丈夫です。すでに初版を読んでいるなら新たに購入していただく必要はありません」(抜粋、意訳)としているので内容的に大きな改訂はないということで大丈夫そうです。
余裕があれば(気づくことができたら)各章のまとめで初版と第2版の違いについても紹介したいなと思います。

読むと自転車に詳しくなれるって本当?

本当です。が、初見では少々イメージしづらいところがあったので、自転車のギアがどんな部品から成り立っているのかくらいは知っておくと楽に読めると思います。

オブジェクト指向設計実践ガイド 第1章 まとめ

1章は本の内容全体に対する導入のような位置づけでした。

1.1 設計の賞賛(In Praise of Design)

1.1.1 設計が解決する問題(The Problem Design Solves)

アプリケーションの仕様や要件は常に変化する。これは避けることができない。
なのでアプリケーションが変更しやすいようになっているとエンジニアにとってはハッピー。設計はそのために必要なもの。

1.1.2 変更が困難な理由(Why Change Is Hard)

そもそも変更がなぜ大変かというと、アプリケーションがうまく設計されていないと変更の影響が他の箇所へ延々と波及していってしまうからだ。
オブジェクト指向アプリケーションは、オブジェクトというパーツがそれぞれメッセージを送り合うことによって成り立っている。正しい相手に正しくメッセージを送るためには相手のことを知っていなければならないが、これが依存という形でアプリケーションの変更を難しくしてしまう。
オブジェクト指向設計はこの依存関係をうまく扱うためのもの、つまりオブジェクトが変更に耐えられるように依存関係を調整するコーディングのテクニックである。

1.1.3 設計の実用的な定義(A Practical Definition of Design)

設計は画一的な解決法が存在するようなものではなく、匠の技(an art:技術、芸術)のようなところがある。
数多ある手法の中からニーズとコスト/利益のバランスを勘案して、現在と将来の両方においてコスパの良いコードの配置(アプリケーションの構造)を考えなければならない。
設計の目的は設計を後からでもできるように対処法を残しておくことであり、その目標は変更のコストを小さくすることにある。

1.2 設計の道具(The Tools of Design)

1.2.1 設計原則(Design Principles)

オブジェクト指向設計者は原則とパターンという二つの道具を使って設計をしていくらしい。
原則については、5つのソフトウェア開発の原則の頭文字を取ったSOLIDというものがある。

  • 単一責任(Single Responsibility)
  • オープンクローズド(Open-Closed)
  • リスコフの置換(Liskov Substitution)
  • インターフェース分離(Interface Segregation)
  • 依存性逆転(Dependency Inversion)

その他に、DRY(Don't Repeat Yourself)やデメテルの法則(LoD:Law of Demeter)がある。 この先々で説明するよ!

1.2.2 設計(デザイン)パターン(Design Patterns)

パターンというのはいわゆるGang of FourGoF)のデザインパターンのこと。GoFオブジェクト指向アプリケーションに見られる共通の問題に名前をつけて、共通の手法で解決できると示したところがすごい!
デザインパターンは乱用したり誤用したりせずに正しく使うことが大事。

1.3 設計の行為(The Act of Design)

設計のための良い道具を揃えていても、それを使いこなして良いアプリケーションを作ることができるかは結局プログラマーの経験によるところが大きい。

1.3.1 設計が失敗する原因(How Design Fails)

Rubyのような扱いやすい言語には、設計をせずともある程度のものは作れてしまうという問題がある。そのような(ちゃんと設計されていない)アプリケーションは、機能追加しようとするとバグが発生したり思わぬ箇所が壊れたりするようになっていく。
設計について多少の知識があると、今度は逆に設計を作り込みすぎてしまうという過ちを犯してしまうことがある。緻密に作り込みすぎているので後から機能追加できないという状況に陥ってしまう。
設計フェーズと実装フェーズが離れすぎていても失敗する。設計は実装からのフィードバックを受けて改善していくイテレーティブなプロセスなので、設計がフィードバックを受けられないとニーズとかけ離れたものが出来上がる危険性がある。

1.3.2 設計をいつ行うか(When to Design)

オブジェクト指向設計ではアジャイルに開発を進める。設計もイテレーティブに行う。
アジャイル開発では「はっきりしたことは作ってみないとわからない」ということを前提としているので、あらかじめ詳細設計をするやり方には意味がないというのがその立場!
詳細設計書は最初こそアプリケーション開発のために作られるが、最終的には誰の責任で限られた期間に何をどこまでやるのかという顧客と開発者の対立の道具にしかならない。
アジャイル開発ではそのようなことはなく、顧客と協業して小さくソフトウェアを作っていく。

1.3.3 設計を判断する(Judging Design)

オブジェクト指向設計にどれだけ沿っているかを計測するソフトウェアやライブラリがある。これらのメトリクスはバイアスなしに現在のコードの状態についてのヒントを出してくれるという点で有用。 だが、メトリクスがどんなに良くてもそのアプリケーションの変更が容易になっているとは限らない。なぜなら事前に想定していない変更のコストは依然として高いままだからだ。
逆に将来的なコストがかかったとしても今すぐに実装するべき機能もある。これは技術的負債として将来のコストを前借りしているということだ。
ある機能をすぐに実装するか否かは、スキルとタイムフレームによって決めると良い。

1.4 オブジェクト指向プログラミングのかんたんな導入(A Brief Introduction to Object-Oriented Programming)

1.4.1 手続き型言語(Procedural Languages)

あらかじめ組み込まれたデータ型とそれに対する操作を利用してプログラミングする。そして振る舞い(メソッド)とデータの間に断絶がある。データは振る舞いに渡されて処理されるだけで、データと振る舞いは完全に別のものとして存在する。

1.4.2 オブジェクト指向言語(Object-Oriented Languages)

オブジェクト指向言語はオブジェクトの中に振る舞いとデータを持たせている。
オブジェクトは他のオブジェクトとメッセージを送ったり受け取ったりすることで振る舞いを呼び出したり実行したりしている。そしてオブジェクトは自分のデータをカプセル化していて、データに向けて外部から何がどれくらいアクセス可能かを決めている。
Rubyのようなクラスベースのオブジェクト指向言語は、クラスというオブジェクトの構造の設計書を定義できる。クラスの中にはメソッド(振る舞い)と属性(データ)を定義できる。
一度クラスを定義すればインスタンスを繰り返し作ることができる。あるクラスから作られたそれぞれのインスタンスは同じメソッドを持っているので同じように振る舞う。メソッドと同様にインスタンスは同じ名前の属性を持っているが、その中身はそれぞれのインスタンスのデータになっている。違うデータを持っているのでそのインスタンスは異なるものを表現している。手続き型言語と同じように、オブジェクトの型によってどのような振る舞いをするかがわかる。
オブジェクト指向言語はそれ自身がオブジェクトでできており、どんなクラスもClassクラスのインスタンスである。なのでプログラマーが新しい型を自分で定義できる。オブジェクト指向言語はこのようにして使われる領域に特化した独自の言語になっていく。

まとめ

いかがでしたか?設計とはアプリケーションの変更のコストを最小化するために、将来の変更容易性を確保することなんですね〜。
要約するにあたって大幅に内容を削ったり統合したりしたため原文のニュアンスとは異なる表現になってしまっている部分があるかもしれません。何かお気づきの方はご指摘くださいますと幸いです。

明日はガラムマサラさんが何か書いてくれるみたいです!楽しみですね〜
ちなみにPart2はsasaboさんです!こちらも楽しみ!

アドベントカレンダーとしてはここでバトンをお渡ししますが、このブログでは今後もオブジェクト指向設計実践ガイドのまとめを投稿していく予定です。気になる方は是非チェックしてくださいね。

さて、2022年も残すところあと僅かとなりました。今年はどんな一年だったでしょうか?来年はどんな年にしたいですか?
皆さまにとって2023年が実りある素敵な年になりますように!

ここまで読んでいただきありがとうございます。Hikaruでした。
Merry Christmas!