“良いコ/悪いコ”で悪魔討伐! (お排泄物)コード撲滅!
前々から本で出ることは聞いていたのですが、爆殺シリーズやク〇コード動画でおなじみのミノ駆動さんのコード設計を扱った本がついに2022/4に商業本で登場。東京ですと書泉ブックタワーでのコンピュータ書籍ベスト1を4週連続達成など、かなり売れています。
エンジニア界隈では早速GW中などに読んだ方も多いようでネットでも反響が大きく、感想記事もよく見かけます。Twitterでもハッシュタグ #ミノ駆動本 で毎日のように反響を見ることができます。
僕もGW明けから拝読しました。とても学びの多い本でしたので以下、章ごとに感想を。
- “良いコ/悪いコ”で悪魔討伐! (お排泄物)コード撲滅!
- 1 悪しき構造の弊害を知覚する
- 2 設計の初歩
- 3 クラス設計 ―すべてにつながる設計の基盤―
- 4 不変の活用 ―安定動作を構築する―
- 5 低凝集 ―バラバラになったモノたち―
- 6 条件分岐 ―迷宮化した分岐処理を解きほぐす技法―
- 7 コレクション ―ネストを解消する構造化技法―
- 8 密結合 ―絡まって解きほぐせない構造―
- 9 設計の健全性をそこなうさまざまな悪魔たち
1 悪しき構造の弊害を知覚する
まずは本書ではバグを「プログラムの欠陥によりシステム仕様を満たせないこと」と定義し、バグ発生の原因になりやすい悪しき構造を上げていきます。
序盤から過去実際のプロジェクトで遭遇した例が登場し、あっこのミノ駆動さんは長年の悪魔退治のプロだ...お疲れ様です!となります。
本章で悪しきとされているデータクラス、DTOクラス的に使う方法は僕も実際のプロジェクトでよくやってきましたし、別に問題ない場合もあるんですね。まあこのへんは本の主張ですのでこれはこれでと理解して読み進めます。
「技術駆動命名」「連番命名」など、他の技術書やエンジニア同士の会話ではあまり見ない本書独自の命名も全体を通してよく登場します。不思議な感じもしますが、設計やパターン化、アンチパターンを可視化する話では名付けにも大きな意味があるので、これはこれで意味があるでしょう。
2 設計の初歩
続いてコード設計の初歩の話。
この辺は基本の話。本書前半ではコード例にRPGがよく登場し、これはイメージしやすくて良いですね。元TRPGゲーマーのワイは大歓喜です。
3 クラス設計 ―すべてにつながる設計の基盤―
オブジェクト指向の難しい本では「クラス、表明、総称性、継承、多相性、動的束縛から構成されるもの」と難しい定義がしてあるオブジェクト指向。エレガントで成熟したクラスを目指して設計をしていく章。
本書では値オブジェクトになりそうな概念を列挙してくれていて、これはありがたいですね。
メンバ変数amountをfinal
にする手法は、伝統的なJavaプログラミングだとprivate int amount
にして外部にはgetAmount()
だけ公開、setAmount()
は定義しないのが普通かなと思いました。
メソッドの引数やローカル変数もすべてfinal
で統一するのは徹底するとすごそうですが大変そうでもあります。JavaScript
なら変数宣言にlet
でなくてよいなら原則const
を使うルール徹底でもいけそうですが。
といっても僕も近年はJavaから離れているので、最近のトレンドだとfinal
重視なのかもしれません。ドットによるメンバ変数アクセスも最近はやるのかもしれません。このへん現場により近いいろんな方の感想を聞いてみたいですね。
また、値を不変にする他言語の例でRubyならself.freeze
、JavaScriptならObject.freeze(this);
が載っています。これも現場でここまでやってるのかな...?という気もしました。
また本書ではint
やfloat
やboolean
やString
などをまとめてプリミティブ型、それらよりは値オブジェクトでクラスを作ったほうがいいよ...という文脈で「プリミティブ」を使っており、言いたいことはわかります。重箱の隅ですが厳密にはJavaの言語仕様ではString
型はプリミティブではないですね。(これはAmazonの書評にもあったような)
なお値オブジェクト、Value Object
周りの話は本や人によって諸説あり、解釈が微妙に違ったりします。最近はてなブックマークでもホットになっていました。リンクなのです。
4 不変の活用 ―安定動作を構築する―
3章で登場した不変をうまく使っていく方法を深堀りする章。
何でもfinal
にするのはやりすぎな印象があったのですが、本章のこRPGの武器と攻撃力のコード例を見ていくと、仕様追加が度重なっていくとこのインスタンスが不変なことに価値が出てくるなあと思いました。
Go言語も value := 0
で代入すると(左辺に他の変数が一緒にない限り)再代入NGで不変になりますが、Rust言語は基本が不変なんですね。確かにこの不変周りは近年注目されている感じがあるので、頭をアップデートしないとな~と思いました。
5 低凝集 ―バラバラになったモノたち―
「モジュール内におけるデータとロジックの関係性の強さの指標」が「凝縮度」。本書では「クラス内のデータとロジックの関係性の強さ」の凝縮度について語っていきます。
本章を始め悪いコード例のクラス名には、HogeHogeManager
系が多いですね。よく分かります...僕も昔よく作っちゃった...悪魔が生まれやすいことにあの頃は気付かなかったんや...ああァァァ(駆け出しJavaエンジニアの頃の黒歴史を思い返して死亡)
Common
やUtil
クラスも悪魔の匂いが漂ってきますね。僕はよくutil
パッケージの下のLogUtil
とかLogger
クラス, StringUtil
, DateUtil
のような感じで横断的関心事の用途別に組んでいったりします。
6 条件分岐 ―迷宮化した分岐処理を解きほぐす技法―
if文やswitch文に潜む悪魔を見つけ出していく章。
本章の魔法のコード例はイメージしやすくてよいですね。読みながら途中から、あっこのパターンは個別の魔法クラスを定義してインターフェースを使う解法だな...と気づけました。
なおJava14以降ならswitch文のほうがよいのでは、という意見もあります。
こういう風に読み手が様々に考えるきっかけになるという意味でも価値のある本です。
ボブおじさんの本などでもおなじみのリスコフの置換原則なども出てきてだんだん本格的になってきました。ホテル宿泊のコード例なんかもイメージしやすくてよいですね。
極端に何でもかんでもインターフェースにすればif文やswitch文が撲滅できるのか...といったらそういう訳でもないですが、悪魔根絶とスキルアップの助けにはなると思います。
7 コレクション ―ネストを解消する構造化技法―
今度は配列回りの悪魔を退治していく章。
anyMatch
を忘れていて、やばいJava7で知識が止まっていた...!(切腹) となりました。この章もRPG風のサンプルコードが理解しやすいです。
ファーストコレクションのパターンは知っていたのですが、最後に不変にして戻すのは新しい発見でした。
8 密結合 ―絡まって解きほぐせない構造―
モジュール間の依存の度合いを「結合度」といい、オブジェクト指向言語の場合はクラス間で算出。依存が多い構造を「密結合」。 全体を通して低凝縮×高凝縮◎と論ずる本書らしく、密結合の悪魔を討滅していきます。
僕はpackage private
はあまり使ってこなかったのでこういう手法もあるのか...と思いました。またpublic
使いがち問題について本書では、Javaの入門書や入門サイトでpublicが標準的な扱いで書いてありパッケージ制御まで解説していないことが多いからではないか、という考察がされており興味深いです。
「継承より委譲」は近年ネットでもよく聞くようになりましたが、本書のような技術書できちんと取り上げられているのがありがたい。本書では親の物理攻撃クラスのメソッドが別メソッドを複数回呼んでいたところに変更が加わり、それぞれをオーバーライドしていた武闘家クラスでおかしくなってしまった、という現象を取り上げているのですがこれは理解しやすいですね。なんか通常攻撃が全体攻撃で2回攻撃のお母さんっぽい...(言いたかっただけ)
Go言語のようにクラスや継承をそもそも取り入れなかった言語もあるし、この辺の考え方も移り変わっていくものだなあと思います。僕も経験ありますがエンタープライズ寄りの大規模業務システムでも、基盤やフレームワークを作ったりする際は継承を重宝しますが、それをベースに適用する機能側の開発の場合は意外と継承の出番がなかったりもします。
後半のECサイトを例にしたコード例もなかなか真に迫っており、実際の悪魔との長年の戦いの記録が記憶が染み込んでいるなあと思います。
後半の「トランザクションスクリプトパターン」も出典は確かPofEAA本でした。オブジェクト指向に基づいた高凝縮クラスを目指す本書ではアンチパターン的に書かれていますが、必ずしも悪ということではないかなと思います。オブジェクト指向が関係ないバッチ処理だと基本トランザクションスクリプトになったりします。
なお最後にクラスの行数目安で100~200行と載っています。このへんは理想形でもあり、皆さんの現実は人それぞれではないでしょうか。僕も実務で保守開発をしているプロジェクトのクラス群を試しに見返してみましたが、変更容易性に特に困っていない状態でもロジックが貯まったクラスだと数百行~中には1千行超えのクラスも普通にありましたねー。わははは。
9 設計の健全性をそこなうさまざまな悪魔たち
まだまだ悪魔は潜んでいる...ということで紹介する章。
最後の締めが「設計にbestはありません。常にbetterを目指しましょう」で、これこそ至言だ...と思いました。
「技術駆動パッケージング」と名前がついた悪魔はRailsが例として挙げられていますが、バックエンドの各言語のフレームワークはほぼすべて当てはまるでしょうね。ドメイン駆動設計寄りの分け方の方がベターだよということでしょうが、これはもうしょうがないですね。
controller
層とmodel
層の間にロジックを置くレイヤーを配置、この中をドメインごとに分割していくあたりが現実解なのかなあと思ったりしています。このへん様々な方がいろんなことを考えていろんな解法を試しています。
長いので分割して、悪魔討伐の旅は後編に続く...