概要
『オブジェクト指向入門 第2版:原則・コンセプト』を読破したので、その感想まとめです。
オブジェクト指向を学ぶための良著・名著として紹介されることが多いですが、
900ページを超えるため手を出しにくい人もいるかと思います。
購読判断に迷った際の材料の1つにしていただけると幸いです。
https://amzn.asia/d/0fwWpAs
前提:読破時点での筆者のスキル感(2024年8月)
本書の理解度合いは経験量により、大きく変わる印象です。
どんな人は読んだ方がよい等、おすすめすることは難しいと感じたので、
どんなスキル感の人が読んで、どんな感想を得たのかを記録として残します。
・エンジニア4年目(年齢28歳)
・業務系基幹システムの開発が主で、
基本設計~製造~結合テストまでを担当することが多いです。
・資格:JavaSilver SE11、応用情報技術者試験 合格
・主使用言語:VB.NET
・経験ありor自宅学習:C#, C++, Java, Python, C言語
(エンジニア1年目で本書を購入しましたが、それから3回ほど途中で挫折しました)
感想
・本書は、第1版が1990年、第2版が2007年に発行されています。
オブジェクト指向が現在ほど浸透していない状況で、オブジェクト指向のメリットを述べ、その実現のためにどのようなメカニズムを利用すると効果的かの提案を行っています。
・オブジェクト指向での開発方法を学ぶだけであれば、本書を読むのはタイパが非常に悪いです。
未経験新卒エンジニアが受ける研修教本やJavaSilverテキストの方が、オブジェクト指向ではどんな仕組みを利用できるのかがわかりやすいです。(クラスとは何か、継承の考え方など)
・ただ、2024年現在のわかりやすいオブジェクト指向での開発方法が生まれるまでに、どのような検討がなされたか、その経緯を理解できます。単にルールとしてしか実践していなかった手法について、その狙いを理解できたことは価値のあることだったと思います。
(新卒(2021年)で学習し始めた時には当たり前に使用していることは、昔は当たり前ではなかったのかとしみじみ)
・また、言語供給・ライブラリ供給側へ意識が向くようになりました。ライブラリ利用者(顧客)が、クラスや関数を柔軟にアクセス・再利用できるのは、ライブラリ供給側がよく設計してくれているおかげだと感じるようになりました。
・総称性の話題まわりで学びが多かったです。
今まではジェネリクスよくわからん…もっと簡単にできるやろ…と思ってましたが、
再利用性と可読性を高め、効率的な開発に寄与してくれていることに気づけました。
・表明と、事前条件・事後条件の定義は、今まで明確に認識できていなかったので、これから意識的に利用して定着させたいと思いました。
・オブジェクト指向での開発をしたことがない人は、内容の吸収がかなり難しいと思います。開発中に、うまくいかなかったこと・レビュー指摘があったことの経験に当てはめながら読むことで、理解できたように思います。継承・抽象クラスのルールがよくわかってない場合には理解が厳しいシーンが多い気がします。
・ページ数が多く、翻訳が少しわかりづらい部分もあるので、読んでいて苦痛を感じることは割とあります。しかし、11章からなぜか読みやすくなったので、今序盤を読んでいて苦しんでる人は、そこまでは踏ん張ってください。
・少しひねくれた考えかもしれませんが、読み切ったことで仕様理解力が高まったと思います。エンジニアをやっていれば少なからず、新旧ドキュメントが入り混じっている状況に遭遇すると思います。本書ではこう書かれているけど、最新手法ではこうなっているのではと調査・比較しながら読み、腑に落とす塩梅がうまくなった気がします。
・現状、後編である『方法論・実践』は読む予定はありません。
やはり、タイムパフォーマンスが悪い。
読書中メモ
※ 本書内容の抜粋と筆者の感想が混在しています。ご了承ください。
メモopen
<3.2.5 情報隠蔽>
○モジュール属性の公開・非公開の基準(p.65)
・公開する部分の中には、そのモジュール機能の仕様が含まれているべきである
・その機能の実装に関係するものは全て非公開にし、
後に実装の決定がひっくり返っても他のモジュールをその影響から保護できるようにすべき。
※曖昧な部分を残した説明なので注意
○よくある誤解(p.66)
「情報隠蔽」は、機密保護制限を意味しない。
顧客モジュールの作者が供給者モジュールの内部テキストにアクセスすることを許される。
※「プロジェクト管理に」よって制限されることはあるが、それは情報隠蔽の原則から導かれるものではない。
同義語、カプセル化の方が情報隠蔽の原則が目指すところをよりわかりやすく示しているかもしれない。
<3.3.1 言語としてのモジュール単位>
・モジュールは個別にコンパイルできなければならない。
<5.2.4>
現実のシステムにはトップは存在しない。
トップ仕様は変わりゆく。
<5.2.10>
数学の定義のように、最適な解法が定まっている場合は、トップダウンは有効だが、現実はそううまくはいかない。
<5.4 オプジェクト指向によるソフトウェア構築>
システムがなにをするかを最初に考えるな。
その対象を考えよ!
<5.5.1>
オプジェクト指向の特徴が端的に記述されている。
何度も読んでも良い内容に思う。
<6.4.9>
aximous 公理
preconditions 事前条件
がよくわからんまま。
<6.5.7.>
システムはクラスの集合である。
その中には責任を持つもの、トップやメインプログラムは存在しない。
<7.4 一様な型体系>
基本的な型を(も)クラスとして定義することによって、継承と総称性というオプジェクト指向の要素に、これらの型を参加させることができる。
<8.1.10 実行時のオプジェクト構造を覗いてみよう>
オブジェクト指向によるシステムの実行時オブジェクト構造が大きく、複雑にならないようにするのは、多くの場合不可能である。〜(中略)〜ソフトウェア工学の極めて重要な目標は、そのインスタンスが単純でないときも、ソフトウェアは単純にすることなのである。
<8.2>
当座の目的に適したものを選び、それ以外のものは捨てただけのことなのだ。モデル化するとは、棄てることである。
<11.2 ソフトウェアの正しさについて>
正しさの問題は、ソフトウェア要素に適応するのではなく、ソフトウェア要素と仕様書からなるペアに対して適用すべき。
正しさは相対的な概念である。
<11.6.2 ソフトウェア信頼性の禅とアート:検査が少ないほど保証は大きい。>
【事前条件がしっかり定義されていることによって、供給者が得られる恩恵が大きいことに強く共感した】
冗長な検査はハードウェアでは標準的な技術である。ハードウェアシステムでは、ある時点では正しい状態にあるとわかっていたものが、後に、他のシステムからの妨害、(中略)外的作用によって完全性が損なわれてしまうことがある。
(中略)ソフトウェアではそういった現象は起こらない。
<11.6.4 表明は制御構造にあらず>
事前条件違反は顧客側にバグがある証拠である。
事後条件違反は供給者側にバグがある証拠である。
<11.6.5 エラー、欠陥、その他、モゾモゾ這い回るやつ>
エラー(error)とは、ソフトウェアシステムの開発中になされた誤った決定である。
欠陥(defect)とは、意図した振る舞いからシステムが逸れてしまう原因となるソフトウェアシステムの特性である。
フォルト(fault)とは、何らかの実行中に意図した振る舞いから逸れてしまうソフトウェアシステムのイベント。
因果関係
エラー→欠陥発生→フォルト発生
「バグ」は欠陥の意味を持つことが多い。が、
エラー、フォルトの意味でも使われることがある。(非公式な議論)
<11.7.2 命令的であることと適用的であること>
命令は、指示的で、「どのように(how)」を記述し、実装の一部である。コンピュータの操作。
表明は、記述的で、「何を(what)」を記述し、仕様の一要素である。数学的類推
<11.7.4. 事前条件の設計:保護型か?要求型か?>
ルーチン作者は顧客より賢くあろうとはしてはいけない。
<11.10.1 ただの関数の集合ではない>
事前条件と公理は関数の意味的特性を示すもの
操作名が示すもの以外の意味を持たなければ、「スタック」の表記はただの空っぽの貝殻に過ぎない
<11.11 表明命令>
特定の事前条件を持つルーチンを呼ぶ前に、check命令を加える(if文とは異なる)
ただし、呼び出しは事前条件を満たしているが、コンテクストからすぐにそれがわからないと確信した場合に使うこと。→表明
意図的に保護していないことを表明する場合は、check not命令を加える。
ソフトウェアの構成要素への一般的なアプローチでは、呼び出しやその他の操作は、正しさのためのさまざまな仮定に基づいてなされていることが多いが、これらの仮定は主として暗黙的である。(中略)開発者は自分自身を納得させており、(中略)しばらくすると、論理的な根拠は消え去り、残っているのはテキストだけとなる。
コンパイルオプションを使って、check命令を実行可能に変えることができる。偽となれば、例外処理をして実行を停止する。
p.524 ポストスクリプト
バージョンアップ時の例外発生による損害例。バージョンアップ前の仕様分析は正しかったが、バージョンアップ後にも気づいて修正できるように、表明メカニズムを入れておくべきであった。
<12.1.1 失敗>
ルーチンが契約を満たす状態で実行を終えた場合、そのルーチンコールは「成功」。
成功しなければ、「失敗」。
<12.1.2 例外>
ルーチンコールの失敗を引き起こす可能性のある実行時イベントが「例外」。
※例外発生→ルーチンコールの失敗
全ての失敗は例外から起こるが、
全ての例外が失敗を引き起こすわけではない。
<12.1.3 例外の原因>
p.529 に一覧あり
<12.1.4 失敗の原因>
ルーチンの実行中に例外が起き、
ルーチンがその例外から回復しない場合に、
ルーチンコールは失敗となる。
<14.5.7>
表明技術のおかげで、実装が全く記述されていなくても、暫定クラスは有益で意味深いものとなる。
<15.4. 反復継承>
読み飛ばした
<15.1.1 改名を使用したら多重継承は使いやすくなる。>(p.721-p.722)
多重構築関数といった、その言語で他に選択の余地のない場合以外には、構文的(クラス内)多重定義を全く使わない方がよい。
「クラス内では、全ての特定が名前を持ち、それぞれの名前が1つ1つの特性を指す」という規則を貫くべきである。
<16.1 継承と表明>
継承が本当はどういうものかは、契約による設計の原則を通して理解するしかない。
<16.1.9 言語規則>
事前条件 αはα or γに含まれる
事後条件 βはβ and δに含まれる
結果的に、事前条件をより強める
γが事前条件となり、
事後条件をより弱めると、
δが事後条件となる。
<16.3 凍結型特性>
子孫で再定義させないための、特性の凍結は役立つ。cloneやequal等、矛盾を生まないために、必要になることもある。
<16.4 制約付き総称性>
全体を通して、総称性の意味・使い方について知見が深まった。
また読み返したい章の一つ。
<16.8 継承と情報隠蔽について>
公開範囲についての記述
<17.2.5 型付けと束縛:混同しないように>(p.794-p.795)
「型付けの質問」は多相性から生じる。
「束縛の質問」は再宣言から生じる。
どちらの場合も、実行中を意味する動的と、実行前を意味する静的にあたる解があり得る。
魅力的な解答として、静的型付けと動的束縛が導かれる。
ある特性が存在することがわかるのはいつか?
→出来るだけ早期に(コンパイル時に)。
どの特性を使うか?
→正しい特性を(オブジェクトの型に直接適合する特性)
<17.3.6 現実的な視野>(p.805)
(前節までで、クラス妥当性・システム妥当性のエラーを検証していた)
システム妥当性エラーは極端にまれである。一方、クラスレベルの妥当性規則違反は日常的に発生する(コンパイラによって発見される)
※p.805-p.822は、初見時はスキップ推奨
<18.7>
列挙型を否定する理由はわからなくはないが、浸透しているしそれほど使いづらくもない
まとめ
参考になる考え・内容はたくさんありました。
この観点が得られただけでも、読んだ価値があった!
と感動したシーンは5回ほどあったと思いますが、修行感はぬぐえません。
達成感もありますが、誰にでもおすすめする書籍ではないです。