オブジェクト指向設計実践ガイド
Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方

書籍の概要

この本の概要

オブジェクト指向設計の名著として名高い“Practical Object-Oriented Design in Ruby”,待望の翻訳版!使いこなせるようになるととても便利なオブジェクト指向ですが,「なんとなく」の理解で使っていると,大きな罠にかかってしまいます。本書は,保守性を上げて運用コストを下げるアプリケーションをつくるために,クラス設計から基本概念,継承のテクニック,ダックタイプ,そしてテスト設計まで,幅広くカバーしています。オブジェクト指向言語を使用するすべての人におすすめの1冊です。

こんな方におすすめ

  • オブジェクト指向プログラミングをしたことがある人
  • オブジェクト指向設計に悩んでいる人

著者の一言

だれしも自身のベストを尽くしたいものであり,また意味のあることに取り組みたいと思うものです。さらに,ほかの条件が一切変わらないのであれば,その過程を楽しみたいと思うでしょう。

ソフトウェアを書くことを仕事とする私たちは,信じられないほどに恵まれています。ソフトウェアをつくることはこのうえない喜びです。物事を完成させるために自らの想像力を注げるのですから。私たちは,一石二鳥の仕事を選んだのです。書いたコードが役に立つという確信のもとに,純粋にコードを書く行為を楽しめます。生み出すものには価値があります。私たちは,今日の現実をつくる仕組みを構築する,現代の職人なのです。建築士や土木技術者に負けず劣らず,自分たちの業績に胸を張ることができます。

これはすべてのプログラマーが共有することです。とても情熱的な新人から,見るからに疲れはてた年長者,あるいはスタートアップで働くプログラマーから,盤石な企業で働くプログラマーまで共通します。プログラマーはだれしも自身のベストを尽くしたいのです。意味のあることに取り組みたいのです。過程を楽しみたいのです。

そのため,ソフトウェアがうまくいかないと,とりわけ困ってしまいます。質の悪いソフトウェアはプログラマーの目的を阻害し,また,プログラマーの幸福を妨げます。かつての生産性は損なわれ,速かったものは遅くなり,満足していた心は不満でいっぱいになるでしょう。

この不満は,物事を終わらせるためのコストが高くなりすぎたときに現れます。私たちの内面にある計算機は常に動いており,達成した総量とそこに費やされた努力の総量を絶えず比較しています。仕事のコストがその価値を上回れば,努力が無駄になったように感じます。プログラミングが楽しいとすれば,それは自身を有能にしてくれるからです。反対に,苦痛であるときは,自分はもっとできる,いや,すべきであると感じているのではないでしょうか。プログラマーの喜びは仕事の足取り次第です。

この本の題材は,オブジェクト指向ソフトウェアの設計です。アカデミックな重い本ではなく,1人のプログラマーが書いた,コードをいかに書くかという話です。今日の生産性が翌月も翌年も持続するようなソフトウェアをいかに構成するかを教えます。現時点で成果をあげ,それでありながら将来へも適応できるアプリケーションの書き方を示します。この本を読むことで自身の生産性を高め,そして,アプリケーションの運用コストを最初から最後まで下げられるようになるでしょう。

この本は,プログラマーの良い仕事をしたいという欲求を信じ,プログラマーにとって必要で,最も役立つ道具を授けます。この本はまったく実践的ですので,その核心では,楽しさをもたらすコードを書く方法についての本であるとも言えます。

この書籍に関連する記事があります!

オブジェクト指向設計の名著,待望の日本上陸!
ソフトウェア開発において,要件が一定であることはありえません。

目次

第1章 オブジェクト指向設計

1.1 設計の賞賛

  • 設計が解決する問題
  • 変更が困難な理由
  • 設計の実用的な定義

1.2 設計の道具

  • 設計原則
  • 設計(デザイン)パターン

1.3 設計の行為

  • 設計が失敗する原因
  • 設計をいつ行うか
  • 設計を判断する

1.4 オブジェクト指向プログラミングのかんたんな導入

  • 手続き型言語
  • オブジェクト指向言語

1.5 まとめ

  • 第2章 単一責任のクラスを設計する

2.1 クラスに属するものを決める

  • メソッドをグループに分けクラスにまとめる
  • 変更がかんたんなようにコードを組成する

2.2 単一の責任を持つクラスをつくる

  • アプリケーション例:自転車とギア
  • なぜ単一責任が重要なのか
  • クラスが単一責任かどうかを見極める
  • 設計を決定するときを見極める

2.3 変更を歓迎するコードを書く

  • データではなく,振る舞いに依存する
  • あらゆる箇所を単一責任にする

2.4 ついに,実際のWheelの完成

2.5 まとめ

  • 第3章 依存関係を管理する

3.1 依存関係を理解する

  • 依存関係を認識する
  • オブジェクト間の結合(CBO:Coupling Between Objects)
  • ほかの依存関係

3.2 疎結合なコードを書く

  • 依存オブジェクトの注入
  • 依存を隔離する
  • 引数の順番への依存を取り除く

3.3 依存方向の管理

  • 依存関係の逆転
  • 依存方向の選択

3.4 まとめ

  • 第4章 柔軟なインターフェースをつくる

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

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

  • パブリックインターフェース
  • プライベートインターフェース
  • 責任,依存関係,そしてインターフェース

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

  • アプリケーション例:自転車旅行会社
  • 見当をつける
  • シーケンス図を使う
  • 「どのように」を伝えるのではなく「何を」を頼む
  • コンテキストの独立を模索する
  • ほかのオブジェクトを信頼する
  • オブジェクトを見つけるためにメッセージを使う
  • メッセージを基本とするアプリケーションをつくる

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

  • 明示的なインターフェースをつくる
  • ほかのパブリックインターフェースに敬意を払う
  • プライベートインターフェースに依存するときは,注意深くコンテキストを最小限にする

4.5 デメテルの法則

  • デメテルを定義する
  • 法則を違反することによる影響
  • 違反を回避する
  • デメテルに耳を傾ける

4.6 まとめ

  • 第5章 ダックタイピングでコストを削減する

5.1 ダックタイピングを理解する

  • ダックを見逃す
  • 問題を悪化させる
  • ダックを見つける
  • ダックタイピングの影響

5.2 ダックを信頼するコードを書く

  • 隠れたダックを認識する
  • ダックを信頼する
  • ダックタイプを文書化する
  • ダック間でコードを共有する
  • 賢くダックを選ぶ

5.3 ダックタイピングへの恐れを克服する

  • 静的型付けによるダックタイプの無効化
  • 静的型付けと動的型付け
  • 動的型付けを受け入れる

5.4 まとめ

  • 第6章 継承によって振る舞いを獲得する

6.1 クラスによる継承を理解する

6.2 継承を使うべき箇所を識別する

  • 具象クラスからはじめる
  • 複数の型を埋め込む
  • 埋め込まれた型を見つける
  • 継承を選択する
  • 継承関係を描く

6.3 継承を不適切に適用する

6.4 抽象を見つける

  • 抽象的なスーパークラスをつくる
  • 抽象的な振る舞いを昇格する
  • 具象から抽象を分ける
  • テンプレートメソッドパターンを使う
  • すべてのテンプレートメソッドを実装する

6.5 スーパークラスとサブクラス間の結合度を管理する

  • 結合度を理解する
  • フックメッセージを使ってサブクラスを疎結合にする

6.6 まとめ

  • 第 7 章 モジュールでロールの振る舞いを共有する

7.1 ロールを理解する

  • ロールを見つける
  • 責任を管理する
  • 不必要な依存関係を取り除く
  • 具体的なコードを書く
  • 抽象を抽出する
  • メソッド探索の仕組み
  • ロールの振る舞いを継承する

7.2 継承可能なコードを書く

  • アンチパターン
  • 抽象に固執する
  • 契約を守る
  • テンプレートメソッドパターンを使う
  • 前もって疎結合にする
  • 階層構造は浅くする

7.3 まとめ

  • 第 8 章 コンポジションでオブジェクトを組み合わせる

8.1 自転車をパーツからコンポーズする

  • Bicycleクラスを更新する
  • Parts階層構造をつくる

8.2 Partsオブジェクトをコンポーズする

  • Partをつくる
  • Partsオブジェクトをもっと配列のようにする

8.3 Partsを製造する

  • PartsFactoryをつくる
  • PartsFactoryを活用する

8.4 コンポーズされたBicycle

8.5 コンポジションと継承の選択

  • 継承による影響を認める
  • コンポジションの影響を認める
  • 関係の選択

8.6 まとめ

  • 第9章 費用対効果の高いテストを設計する

9.1 意図を持ったテスト

  • テストの意図を知る
  • 何をテストするかを知る
  • いつテストをするかを知る
  • テストの方法を知る

9.2 受信メッセージをテストする

  • 使われていないインターフェースを削除する
  • パブリックインターフェースを証明する
  • テスト対象のオブジェクトを隔離する
  • クラスを使って依存オブジェクトを注入する
  • ロールとして依存オブジェクトを注入する

9.3 プライベートメソッドをテストする

  • テスト中ではプライベートメソッドを無視する
  • テスト対象クラスからプライベートメソッドを取り除く
  • プライベートメソッドのテストをするという選択

9.4 送信メッセージをテストする

  • クエリメッセージを無視する
  • コマンドメッセージを証明する

9.5 ダックタイプをテストする

  • ロールをテストする
  • ロールテストを使ったダブルのバリデーション

9.6 継承されたコードをテストする

  • 継承されたインターフェースを規定する
  • サブクラスの責任を規定する
  • 固有の振る舞いをテストする

9.7 まとめ

著者プロフィール

Sandi Metz(サンディ・メッツ)

成長と変化を乗り越え存続してきたプロジェクトに取り組んできた30年間の経験を持つ。ソフトウェア ・ アーキテクトとして,デューク大学にて毎日コードを書いている。デューク大学のチームでは,15年以上進化しつづけてきた大規模なオブジェクト指向アプリケーションを抱える顧客の,実際の問題を一丸となって解決している。全力で取り組んでいることは,有用なソフトウェアを極めて実践的な方法によって世に出すこと。本書は,何年にも及ぶホワイトボード上での議論を凝集したものであり,オブジェクト指向設計についての生涯にわたる会話から導き出された理論の集大成となっている。Ruby Nation,Gotham Ruby User's Conferenceにおいて過去数回発表を行った。現在,ノースカロライナのダーラム在住。


髙山泰基(たかやまたいき)

株式会社Misoca勤務。西日暮里.rbのメンバー。