達人プログラマー:業界に大きな影響を及ぼした名著の2020年版
とても有名な本ですが出版から20年、フィードバックを得て内容も再構成した第2版が出ました。電子版が出るまでしばらく待っていたのですがじっくり読むことができました。
内容はそれぞれ独立したセクションにTipsやエッセイ、名句の引用も含め、プログラマーの姿勢を様々に論じた本となっています。ところどころで演習問題と、正解のない「チャレンジ」問題があるのが良いですね。
翻訳は「達人」となっており原著では Pragmatic Programmer
。実用本位、実際的、実践的。技も思想も現場で実践する熟達したプログラマー……といった感じで「達人」という訳を当てているのでしょう。
- 作者:David Thomas,Andrew Hunt
- 発売日: 2021/01/18
- メディア: Kindle版
第1章 達人の哲学 A Pragmatic Philosophy
最初のTipsは自らの技術に関心を持つこと、あなたの仕事について考えること、そして継続は力なり…とはじまっていきます。
1 あなたの人生
あなたはあなたの人生を生きており、現状を打破する力がある。不平不満を言うだけではなく、自分から行動して変化を受け入れていこう、チャンスを掴んでいこうという話。
ハイまったくその通りです……という話。本書ではテクノロジーを追うための自分への投資なら勤務時間「外」にやろうと書いていますね。
2 猫がソースコードを食べちゃった
もしコードが損失したらそんな苦しい弁解をしないで、代わりに対策を用意しよう。自分以外の何かのせいにしないで自分の仕事に責任を持ち、周囲を信頼してやっていこうという話。
Uncle Bob御大のCleanシリーズにもこうしたプロフェッショナルの職人としての在り方的なところが書いてありますが、似た印象です。
Clean Code アジャイルソフトウェア達人の技 (アスキードワンゴ)
- 作者:Robert C.Martin,花井 志生
- 発売日: 2017/12/28
- メディア: Kindle版
- 作者:Robert C.Martin
- 発売日: 2018/07/27
- メディア: 単行本
3 ソフトウェアのエントロピー
有名な『割れ窓理論』の話。悪い設計や意志決定、コードなど悪しきものを放置しておくと、そのままでよいんだという気持ちがプロジェクトに伝染してあっという間に腐ってしまう。見つけたらすぐ直すか何かアクションを取って、クリーンな状態を常に保とうという話。
この『割れ窓理論』はソフトウェアエンジニアリングのいろんな名著によく出てきますね。
4 石のスープとゆでガエル
村人から野菜をうまく引き出してみんなで美味いスープを飲んだ兵士の訓話から、誰もが自分の側に固執するようなシーンでは自分から働きかけて状況を変えていこうという話。
ゆっくり温度を上げていく鍋の中にいるカエルは気付かずに茹で上がってしまう(らしい)という話を元に、周囲で起こる小さな変化に気付こう、大きな構想を忘れずに行こうという話。
ここでCOBOL
言語の母のグレース・ホッパー女史の名言「許可を得るより謝罪せよ」(本書では「許可を得るより赦しを請う方が簡単である」)が登場するのがアツい。
ゆでガエルの訓話は日本語の諺ならカエル繋がりで「井の中の蛙大海を知らず」が近いでしょうか。そうならないために自分も社外と接点を持ってWebから情報を摂取しているぜ...と思いました。
5 十分によいソフトウェア
バグがゼロの完璧なソフトウェアは作り出せない。ユーザや保守担当、作った本人たちにとって十分によい(good enough)
レベルで品質要求を満たしていればよい。それより大事なことがある状況もある。トレードオフで秤にかけ、止め時の頃合いを知ること。完璧なものはない。
アメリカ人より高いサービス品質を提供しがち(らしい)日本人的には「過剰品質」のキーワードでしょうか。
6 あなたの知識ポートフォリオ
金融の投資と同じで、定期的に投資する。様々な分野の知識を知って多様化する。将来廃れてしまう技術もあるので1つに集中させすぎずリスク管理。将来注目されそうな技術を予めて知っておくと後で儲けになることもある。複数の分野に投資して配分も見直す。
毎年1つの言語を学習する。月1冊技術書を読み、それ以外の本も読む。講習やコミュニティに参加してみる。OSなど異なった環境にも慣れてみる。最先端に留まり続ける。とにかく定期的に続けるのが大事。
学習の機会を活かし続け、批判的な考え方で分析することを学ぶ。その技術のメリットの役に立つ背景は、いつどこで役に立ち、誰の得になるのか?
よくキャリア関連の話題でなるあたり。最初は無名で後から有名になったテクノロジーにJava
が上げられていて、そうだったな……と懐かしくなりました。
TDDで有名なt-wadaさんの講演によく出てくる話題の源泉の一つが本書のここですね。自分は毎年1つの言語はだめでも2年に1度ぐらいは満たしてるかな? 技術書は月1冊は確実に読んでいるのでセーフであります。
こちらも名著の『Code Complete』にも似たような話はありました。
【電子合本版】Code Complete 第2版 完全なプログラミングを目指して
- 作者:Steve McConnell
- 発売日: 2016/04/14
- メディア: Kindle版
「批判的な考え方を学ぶ」の話を読んでいると、声の大きいベンダーが声高に語るパッケージ製品とか大統一理論とか、二項対立になりがちな話題とか、日本以外でも同じなのだなあと思います。
検索エンジンの真っ先に返してきたものが最適な選択であると思うな……という下りを読むと、まさにググるとプログラミングスクールの低品質な情報が最上位に来てしまう今の状況が思い起こされます。
7 伝達しよう!
プログラマーでも人にものを伝える機会はある。母国語をプログラム言語だと思ってやってみる。聞き手がどんな人かを考え、言いたいことを整理する。タイミングや伝え方のスタイル、ドキュメントの見栄えも影響する。相手からのフィードバックを受ける。自分も聞き手になり、相手の立場に立って想像してみる。
また達人プログラマーにはドキュメントは重要なパーツである。コードのコメントにはWhy
(目的とゴール)を書く。How
はコード自体に書いてあるのでDRY原則に反する。
経験を積むと自然と育ってきそうなスキルではありますが、やはりこの辺のコミュニケーションスキルが弱いプログラマーさんは海外でもいるのだろうなあと思います。
ワタクシはコードのコメントは多少冗長でも詳しめに書く派、仕事のドキュメントも丁寧に書く方(たぶん)なので、最後のドキュメントの話は同意したい……!
第2章 達人のアプローチ A Pragmatic Approach
開発時に意識しておくとよい基本原則を上げ、達人としての仕事へのアプローチを語った章。
8 よい設計の本質
よい設計は悪い設計より変更しやすいという事。Easier To Change
でETC
原則と呼ぶ。結合の最小化、単一責務原則、名付けによるコードの可読性の向上、すべてこれに繋がる。
ルールではなく価値であり、何かした時にこれは変更しやすくなったのか?しにくくなったのか?を自問するとよい。
ETC原則という名前はあまり他では聞かないので本書独特の用語っぽいですが、言われてみると確かに……今我らは真理に触れた!という気持ちになります。
9 DRY 原則 - 二重化の過ち
スキルの足りない人はメンテナンスとはバグ修正や機能拡張だと思っているが、そうではなくてコードは常にメンテナンスされていくものである。すべての知識はシステム内で、単一かつ明確かつ信頼できる表現になっていなければならない。これがDon't Repeat Yourself
。
たまたま別のものごとの規則が完全に同じで別関数同士がたまたま同じコードになったとしても、これはDRY適用対象ではない。
このDRY原則の考え方はコード本体以外にも適用できる。
- 関数コメントには、関数本体でやっていることとまったく同じ説明は不要。
- 外からのアクセス時にアクセサメソッドで結果を返せるなら、別途メンバ変数で二重に定義しない。
- APIの定義をコードとドキュメントで二重表現せず、ツールで出力したり。
- 構造が外部で定義されているデータ構造をクラスで二重に定義せず、キー/バリュー型で表現する。
- プロジェクト内で同じ機能を別の人が何回も作らないよう、活発で頻繁なコミュニケーションで回避。再利用しやすいようにする。
データソースの二重化のところがちょっと分からなかったのですが、DRY原則は最重要……!
10 直交性
幾何学から借りてきた用語で、2つのもの同士の結合度が低く、独立していること。線が直角に進んでいるイメージ。直交していると利点がある。
- 生産性が向上する:他に影響がないので短い時間で開発でき、小さな規模のテストで済む。再利用しやすく、組み合わせやすくなる。
- リスクの軽減:バグがあってもそこを隔離でき、修正範囲も少なく、テストもしやすい。ベンダー製品等との結びつきを減らせる。
- 設計:ある箇所を変更したらどれだけ他のモジュールに影響するか?を考えると良い。
- ライブラリ類:例えばオブジェクトを永続化する仕組みがあったとしたら、本来関係ないはずのコードにどれだけ変更が発生するかを考えてみる。
Java
のアノテーションは良くできている。 - コーディング時:『デメテルの法則』を試して、モジュール間の結合を避ける。グローバル変数を避ける。似たような機能があったらデザインパターンの
Strategy
パターンを考える。 - テスト:直交性を保っていれば結合テストでなく小規模なユニットテストで済んだり、テストもしやすくなる。
- ドキュメント:実は直交性が適用できる。テキスト本体と見た目の装飾を切り離したり。
「直交性」と日本語で言われるとパッとは分かりにくいので「独立性」あたりの方が馴染みやすいかなとも思います。この互いの依存性を低くするというのは、いろんな名著でよく語られている原則ですね。
11 可逆性
現実ではいろんな決定があとからひっくり返ったりする。なるべく後から変えられるように、柔軟で適合性の高いソフトウェアを作る。DB接続部分を入れ替え可能にする、アーキテクチャーの柔軟性を保つ、ベンダー依存を避ける、信頼できないサードパーティ製APIを抽象化レイヤーで隠蔽して後から取り換え可能にするなど。
最後のアドバイスに「流行を追い求めないようにする」。
このへんのひっくり返った話はよくUncle Bob御大のCleanシリーズの昔話で見た気がします。使うDBが後から変わるというのは今はあまりない気もしますが……RDB
とNoSQL
両方試して性能がダメで後から変えるなどでしょうか。このへんも意識した設計は大事ですね。
12 曳光弾
機関銃のガンベルトに数発おきに入っていて暗闇でも着弾地点が分かって修正できるもの。不確実なものにフィードバックを即座に得ながら行うのが曳光弾開発。
例えばUI、認証、ロジック……などレイヤードアーキテクチャだったら全レイヤーの一部づつを通る機能を試しに作って、実現可否を確かめたりリスクを洗い出したり。ユーザに早い段階で実物を見せられ、開発者の足掛かりになり、テスト環境も早期に作れ、デモもできる。
「プロトタイピング」は、アプリの実物とは別のGUIツールで仮に画面だけ作ったり、アルゴリズムを幾つかの言語で試したり、評価が終わったら使い捨てになる可能性があるもの。曳光弾は最終的なシステムの骨格になるもので両者は異なる。
実物を機敏に作る必要があるアジャイル関連の文脈でよく出てくるワードですね。
この曳光弾、機関銃のメタファーは良く分かるのですが実物がいまいちイメージが湧いていませんでした。予定していたアーキテクチャで画面からDBまで行って返ってくる簡単な機能をひとつ作って後に続くメンバーへのお手本にする……などでも当てはまるのでしょうか。だとすると自分も実践してきたので似たようなことはしてきたかな……?
13 プロトタイプとポストイット
曳光弾とは異なり、プロトタイプはコーディングとは限らない。ホワイトボードに書いた絵やロジックを付箋で表したぐらいでも良い。学ぶのが目的。
ダミーデータでよいし画面のメニューは一つでもよいし、エラーチェックは省いてよい。アーキテクチャのプロトタイピングでは主要コンポーネント間の関連や結合度、二重化を避ける識別、データアクセスの方法などを論じる。プロトタイプはあくまで使い捨てであり、そのままプロジェクトを進めないよう注意。
よくホワイトボードに雑な四角と線で構成図っぽいものを書いて議論したりする時の写真を見ますが、プロトタイピングというのはこの程度でよいのかなと思いました。
14 専用の言語
特定の問題領域の解法となっているドメイン言語(DSL)
がある。Ruby
のテスト用ライブラリRSpec
、テスト記述のCucumber
, ルーティングのPhoenix
, 構成作成ツールのAnsible
など。これらをうまく使っていこう。
Ansibleをドメイン言語扱いするのは他ではあまり見かけない気がしましたが、確かにYAML
言語で記述して人間が見れば分かるのだからこれもそうなのかも……そして演習問題が全然分からなかったので切腹です。
15 見積もり
後で驚いたり困ったりしないように、しっかり見積しよう。
- どの程度正確か:期間によって答える際の単位を日/週/月と分けるとよい。
- 見積はどこから来るか:モデル化する前に、過去に同じような経験をした人を探すとよい。
- 内容の理解:まず尋ねられている内容を理解する。
- モデル化とコンポーネントに分割:それぞれで見積もれる。パラメーターは、増えるごとに足していくものはそれほど影響しない。乗算になるものに注意。
- 答えを計算する:スプレッドシートなどが便利。数値がおかしかったら見直してみる。
- 自分の見積能力を見誤らない:失敗しても次はよりうまく見積もっていけるので記録を取る。
- 現実の見積には複数シナリオがある:有名な手法を用いたからとって万能と思わないこと。
- 象を食べるには:「ひとくちづずつ」が答え、というジョーク。スケジュールを分割して見積もって実行して繰り返して精度を上げるしかない。
- 何と答えるべきか:その場で答えず、のちほどじっくり考えた見積を出すのがよい。その場で答えると相手はその値が答えだと記憶してしまう。
見積は本が何冊も書けるぐらい奥が深い話ですが、確かにその通りです。最後の話は、下手にその場で答えると数字が一人歩きしてしまうよということだと思います。
第3章 基本的なツール The Basic Tools
16 プレインテキストの威力
プレーンテキストは強い。バイナリでなく人間が目で読めるし、時代が変わっていっても陳腐化しない。多くのツールで使えてテストも簡単。UNIX
哲学でも、プレーンテキストを重視する考えが貫かれている。
ここは初版でも同じようなことが書いてありました。
17 貝殻(シェル)遊び
シェルは強力。GUI
は素晴らしいインターフェースだが全ての機能は使えず、自動化もできない。達人プログラマーはシェルを活用してすべてのことを連携させ、生産性を上げる。
このへん余り活用できていないので、いつか見直さないとなあと思いました。
18 パワーエディット
エディターに熟達し、無意識のうちに様々な作業ができるようにする。何かの繰り返し作業をするごとに、もっと良い方法がないか考えると良い。エディターの拡張機能を活用する。
明言されてはいませんがvim/Emac
などで強くなろうというという話。最後の「チャレンジ」に書いてあることが、エディターからオートリピートを外す(コードヒントやインテリセンスのような話?)、マウスを使わずにキーボードだけでやるという“痛みを伴うチャレンジ”でガチなやつでした。ひぃぃ達人になれなくてすいません……(切腹)
19 バージョン管理
共有サーバーでなく、常にバージョン管理システムを使おう。すべてのものをバージョン管理システム(VCS)
の中に入れる。
今どき必ず使うと思いますが、こうしてセクションに書かれるということはアメリカでもいまだに使っていないプロジェクトもあるのだろうなあと思います。本書ではGit/Subversion/Mercurial/CVS
など具体的なツール名には触れず、VCSを使おうとだけ述べていますね。
20 デバッグ
- バグを作った人を非難するのでなく、問題を修復する。
- パニックに陥らず冷静に対処し、気持ちを切り替えて行う。近視眼的にならないように。
- バグの場所を正確に観察し、適切なデータを集める
- 修正の前にまずテストして失敗させ、バグを再現する。
- エラーメッセージをちゃんと読む。
- 途中でおかしな結果が合ったらメモしていくとよい。
- 「二分探索法」がバグ調査でも使える。長い長いスタックトレースの真ん中へんを見てエラーがそれより前か後かを知り、さらにまた半分にして……
- デバッガーだけでなくログやトレースも有効。
- 誰かに説明するラバーダッキングを行うと、新たな見識がひらめいたりする。
- サードパーティ製品やプラットフォーム環境、ライブラリやOSなどなどに問題があることは少ない。まずアプリケーション側のコードを疑うこと。
- 驚くようなバグが実は存在することは必ずある。仮定を置かずにちゃんとしたデータと条件で証明すること。
言いたいことはよくわかります! 最初のバグ(bug)
は大きなコンピュータシステムに入り込んでしまった本物の「蛾」だったという話は割と有名な小噺ですが、この報告を受け取って記録した歴史上初の人物が、COBOL言語の母であるかのグレース・ホッパー准将だそうです。
21 テキスト操作言語
UNIX
系ならawk
やsed
、より構造的なツールとしてはPython
やRuby
でテキストを強力に操作できる。本書自体も執筆にRuby
を使っている。
22 エンジニアリング日誌
ミーティングの内容やデバッグ時のこと、やりかけの作業、なんでも記録する日誌を付けるとよい。記憶より確実、アイデアを残すことできる。何かを書きとめようとすると頭が切り替わって振り返りのチャンスになる。
本書では手書きには特別な力があるとして、ファイルやWikiでなく紙ベースを推奨しています。最近YouTubeでデスクツアー系動画を見た時、環境に紙のノートも用意している方というのも時々見かけるのでこれと関連しているなあと。
僕は紙でなくテキストファイルにいつもメモっているのですが、なんにせよ記録に残すのは意味のあることですね。
第4章 妄想の達人 Pragmatic Paranoia
「妄想の達人」というとセルフ脳内でイマジネイションがどこまでも広がって捗る人のように読めますが、原語だとPragmatic Paranoia
で「実践的な偏執病」。
完璧なソフトウェアを作ることなどできないことを念頭に置いて、他人も自分すらも信用せず防衛的なコーディングをして有事に備えよう…という感じのニュアンスだと受け取りました。
23 契約による設計(DbC)
呼び出し側によって呼び出される機能の前提条件が満足されたら、その機能は処理完了時点で事後条件と不変表明を満足させる。
Clojure
やElixir
言語は言語の仕組みとして持っていて、引数が範囲外だったらそのそも関数を呼べなくできたりする。TDD
をしていてもDbC
は必要。別項の「早めのクラッシュ」の話ともうまくマッチする。
このDesign by Contract
の話、時々本で見かけたりもします。言語によっては引数の型やNull許容で表現できたり、関数の一番最初で引数チェックをして例外やエラーを出すことで対応できる場合もあります。コードのコメントや文書で表現する手もあるかと思います。
自分としては明確にはやっていないのでピンと来ないのですが、契約(制約)を明確に定義すると設計もわかりやすくなるしデバッグもやりやすくなるという感じで理解しました。
24 死んだプログラムは嘘をつかない
あるライブラリの関数があったら、呼び出し側に何重もtry-catch
を強いるような実装はよくない。達人プログラマーはその関数を呼ぶだけで良いようにする。ありえない事態がその関数の中で起こったら、入力値が処理をトラッシュ(trash
, ゴミ箱、メチャクチャにするの意)する前にクラッシュ(crash
, 停止させるの意味も)させる。
簡単な例であれば、引数が異常だったら長いメイン処理が始まる前に早期リターンしてプログラムを停止させよう、という話ですね。
25 表明を用いたプログラミング
そんなことは起こるはずがない……と思ったら、思うだけの自己欺瞞をせず表明を使って保証する。assert
文を使って処理結果が異常でないこと(null
でない、配列が0でないなど)を保証する。
この表明も実際に使っていないのでちょっとピンと来ない話でした。
26 リソースのバランス方法
始めたことは終わらせるのが基本。
- 例えばファイルをオープンしたら必ずクローズする。オープン-クローズの処理は共通化したり言語の機能を使って、影響する範囲を局所化する。
- リソースは割り当てた順番と逆の順序で開放する。
- 異なった場所で同じリソース割り当てをするなら同じ順序にする。
- オブジェクトを作ったらデストラクタで解放する。
- 変数のスコープが終わったら解放させる仕組みを使ったり、例外の仕組みのある言語なら
finally
節で解放する。 - 階層型のデータ構造なら解放の順番の仕組みを統一する。
本書の随所に引用がありますが本項に「ゲド戦記」が出てきておおっ!となりました。(ファンタジー脳)
モダンな言語やフレームワークだとこのへんあまり気にしなくても動くようになってはきていますが、Java
でオブジェクトに明示的にnull
を代入すると解放される話など懐かしいなあと。
27 ヘッドライトを追い越そうとしない
速度を上げた車だと、ヘッドライトが照らせる限界距離よりも急ブレーキで止まるまでの距離が長くなり、障害物を避けられない。(=ヘッドライトを追い越す)
プログラミングも同じで、フィードバックを受けながら常に少しづつ進むこと。あまりに大きいタスクは分解して未来を予測できる範囲まで小さくする。コードの部分部分は交換可能にして、将来より良いものが出てきたら入れ変えられるようにする。
未来についても認知バイアスが掛かって変化に気付けないことがある。明日が今日とよく似ていても前提にしてはいけない。
本書の初版登場時は次世代GUI戦争が活発だったが、勝者はどの候補技術でもなくウェブだった……という話を読むと、未来は常に変わっていくものだなと改めて思います。
第5章 柳に雪折れ無し Bend, or Break
雪が積もっても柔らかい柳は折れることがない。コードにも同じような柔軟性を持たせて、外界の変化に対応できるようにしていこうという章。
28 分離
分離されたコードは変更しやすい。3つの事柄で語っていく。コードは結合を避け、自分が知っていることだけを実行するようにする。
1. 列車の衝突事故-メソッド呼び出しの連鎖
custmer.orders.find(id).getHogeHoge().applyFoo(amount);
のようなオブジェクトのメソッド呼び出し連鎖はよくない。照会せずに依頼する(Tell, Don't ask)
。すなわち、相手のオブジェクトに処理を頼んでドットの連続をなるべく減らす。
デメテルの法則(Law of Demetel)
とも近いが、近年では大域変数は使わない。また連鎖の対象が変更されない検索処理などではこの1ドットルールは適用されない。(Active Record
パターンを採用したフレームワークのDB検索処理など。)
2. グローバリゼーション - 大域データの弊害
あらゆるメソッドの内部から利用できる大域データは便利だが、変更した時に影響が大きいのでなるべく使わない。
グローバル変数以外にデザインパターンのSingleton
なオブジェクトも含まれる。データベースやファイルシステムなど外部リソースも含まれる。大域データにしたかったらAPIでラップするとよい。
3.相続問題 - サブクラス化が危険な理由
別項で述べる通り、サブクラスの乱用は危険。
ドットの連鎖(PHPならアロー)を避ける話は他の本でも登場するのですが、あれフレームワークが推奨する書き方がこうなってることあるな……とその時も思いました。本書ではきちんと検索では除外であることが書いてありますね。
29 実世界を扱う
実世界でのボタンクリック、システム内での処理終了など、「イベント」をうまく扱うアプリケーションを作ろうという話。
- 有限状態機械(finite state machine, FSM): 有限オートマトン。イベントで遷移していく状態それぞれを定義し、この状態ならこの処理をする、というコードを書いていく。
- Observerパターン:観測可能
(Observable)
なイベントの発生源と、観測者(Observer)
を定義する。観測者はイベント発生時に呼び出してほしい関数を観測対象に渡すと、観測対象はその時実行する。デザインパターンにもある。実績豊富。ただし結合度が増してしまう。 - Publish/Subscribeプロトコル:
pubsub
モデル。パブリッシャーはイベント発生時にそれをチャンネルで通知する。購読しているサブスクライバーはそれを知ることができる。2つの繋がりはコードから隠蔽され、他のレベルで実現されている。クラウドプラットフォームでよく使われる。 - リアクティブプログラミングとストリーム、イベント:何かの値を変えると参照先も自動で変わるのがリアクティブプログラミング。自動的に反応
(react)
。フロントエンドではReact
とVue.js
が該当。JavaScript
のRxJs
ライブラリではさらに先を進み、イベントをデータのコレクションとして扱えるようになっている。同期処理と非同期処理が統合され、時間を管理しなくてよくなっている。
有限状態機械の話が演習問題含め分かりませんでした……(切腹)
ちょうどこの間C#でイベント周りを処理するプログラムを書いていたので、おっObserver
パターンだ! となりました。pub/sub
の話もクラウドやマイクロサービスの文脈で頻出ですし、本書にReact
とVue.js
の名がチラッと出てくるあたりも時代の変遷を感じます。(「本書が出る前に陳腐化しているかも」とあるのは、フロントエンドの変化が速い事への皮肉?)
RxJSも深掘りしようかと前に思ったのですが、情報もまだあまり多くないですね。
qiita.com cloud.google.com tech.recruit-mp.co.jp
30 変換のプログラミング
プログラミングはコードについての話だが、プログラムはデータについての話である。入力を出力に変換するのがプログラムの原点。
UNIX/Linux
コマンドの処理をパイプラインで繋げられるのは大きな発明だが、Elixir
言語では |>
演算子でこれが実現されている。パイプラインができない言語でも設計で意識すると良い。コードを変換の連続と捉えるのも新たなアプローチであり、コードを改善できる。
Elixir
言語は詳しくないのですが、関数型言語のアプローチっぽい話。
31 インヘリタンス(相続)税
オブジェクト指向の継承の弊害の話。
- コード共有のために継承を使う:親クラスのいらないメンバ変数やメソッドも受け継ぐことになる。親を変更したら子は全て影響を受けて壊れてしまう。
- 型の構築のために継承を使う:継承の数が増えるとどんどん複雑さが増し、全体への影響が大きくなる。
C++
は多重継承の悪名を高めてしまった。
これらの解決方法が以下。最善の方法を選んでいく。
- インターフェースとプロトコル:型を持つにはこのメソッドを実装せよという情報を定義する
Java
のインターフェース。言語ではプロトコルやトレイト。ポリモーフィズムの表現にはこちらを使う。 - 委譲:
has-a
はis-a
に勝る。何かのクラスを継承するのではなく、クラスのメンバ変数に閉じ込めて必要な処理だけ外部に公開する。機能の追加時に使う。 - mixin, trait, カテゴリー、プロトコル拡張:あるクラスに何かの
mixin
を加えると、そのmixin
の持っている機能が使えるようになるもの。言語によって名前や仕様が異なる。異なるクラスで機能を共有する時に使う。
「継承より委譲」の話はよく聞きますね。雑誌のSoftware Design 2021年3月号の特集に詳しくあって参考になります。
例えばJava
で業務システムを作るなら、String, Date, Calendar, ArrayList
などなどJava
言語自体のクラスを継承するケースはほとんどなく、自作クラスの中のメンバ変数で持って必要な処理だけを移譲する……という覚え方でよいと思います。
32 設定
アプリケーションが動き始めた後で挙動を変えたいなら、コードを変えなくてよいようにその外側、外部設定を用いてパラメーターを定義する。
多くのフレームワークでフラットなファイルにYAML
やJSON
で書くことが多い。設定情報はAPIの裏に隠すのがよい。参照も制御でき、動的に変更できる。柔軟性と適応性の低いコードを書いてドードー鳥のように絶滅しないように。
設定もAPIを持たせるというのはPropertyManager
のようなクラス経由でアクセスするのも入るのでしょうか。なるほどなあと。
そして第2版の本書では、このコードでなく設定で持たせる話もやりすぎないよう但し書きがあります。なるほどこのへんはバランスですね。
次の記事に続きますよ→