OTAKUは頭字語であり、すべての文字が制約です。40のルールがそれを測定可能にし、1つの指標がメソッドの存在可否を決めます。
この哲学には硬い核と柔らかい縁があります。核=5つの柱とそれを運用する閾値は交渉しません。縁=言語、フレームワーク、スタイル、ツールは自由です。
5つの柱の順序には意図があります。規律が最初なのは、それがなければ何も残らないからです。契約が最後なのは、外の世界が見てよい唯一のものだからです。
規律を自ら律する
自分に厳しく。
制約だけが自由への道です。複雑度、サイズ、命名は議論ではなく測定の対象です。
構成のための道具
Unixのように構成する。
入出力が明確な小さな部品。アプリケーションはデータパイプで、副作用は縁に留まります。
中核を装甲する
ビジネスの中核を守る。
依存は内側だけへ。エンティティとユースケースはフレームワークの名前を知りません。
インフラを静かに保つ
インフラはただの詳細。
永続化はメモリ上のコレクションのように振る舞います。失敗は明示的で、状態は既定で不変です。
普遍言語と契約
ユーザーの言葉で語る。
ユビキタス言語を設計先行の契約に明示します。プリミティブは包み、すべての公開メソッドに契約があります。
主要な指標
循環的複雑度(Thomas J. McCabeによる、メソッドを通る独立経路の数)がこの哲学の主要な計器です。複雑度が5を超えるメソッドは、どれほど読みやすく見えても却下されます。5つの経路は、読み手が同時に保持すべき5つの推論です。
規律の節の他のすべては、この数を低く保つための手段です。1階層のインデント、ELSEなし、switch/caseなし、ガード節、抽出。この指標は本書のすべての言語で測定でき、どのエコシステムにも報告するツールがあります。
40のルール
すべてのルールには測定可能な閾値があります。迷ったら、より制限の強い選択をしてください。
40のルール · 7グループ · 5つの柱
O複雑度
- メソッドごとの循環的複雑度は5を超えてはならない。
- メソッド内のインデントは1階層まで。
- ELSEキーワードを使わない(ガード節や早期リターンを使う)。
- switch/case文を使わない(ポリモーフィズム、match式、Strategyを使う)。
- マジックナンバーやマジックストリングを避ける(定数かenumを使う)。
Oサイズ
- クラスは最大50行(クラス本体のコードのみ)。
- メソッドは最大20行(実行コードのみ)。
- 名前空間またはパッケージあたり最大10クラス。
- インスタンス変数が3つ以上のクラスは禁止。
- メソッドの引数は最大2つ。
- コンストラクタの引数は最大2つ。
- インターフェースのメソッドは最大2つ。
O命名
- 略語を使わず、完全で説明的な名前を使う。
- 真偽値を返すメソッドは is / has / can / should で始める。
- メソッド名は動詞で始める。
- 定数は UPPER_SNAKE_CASE。
- プロパティとメソッドは camelCase。
Tモジュール性
- コレクションを第一級オブジェクトにする(配列を専用クラスで包む)。
- 1行につき1つのドット。可読性のためメソッドチェーンを避ける。
- staticメソッドはファクトリと純粋関数のみ許可。
- コマンドとクエリを分離する(値を返すメソッドに副作用を持たせない)。
- 可能な限り関数を純粋にする(同じ入力なら同じ出力、副作用なし)。
- グローバル状態やシングルトンを避け、依存を明示的に注入する。
- 小さく焦点の定まった関数を好む(1つのこと以上をするなら抽出する)。
A保護
- getter / setter / 公開プロパティを禁止し、振る舞いのメソッドを使う。
- プロパティは既定でprivate。protectedはフレームワークの継承のみ。
- クラスは既定でfinal。拡張はインターフェース経由で行う。
- 継承はフレームワークの基底クラスのみ許可。合成を優先する。
- 境界(コンストラクタと公開メソッド)で全ての入力を検証する。
- 早期に失敗する(前提条件が破られたら即座に例外を投げる)。
- 引数を変更しない(不変として扱う)。
K副作用と失敗
- 不変性を優先する(readonlyプロパティ、新しいインスタンスを返す)。
- コレクションを返すメソッドは空のコレクションを返し、nullを返さない。
- 失敗しうるメソッドはResult/Eitherを返すか例外を投げる。nullは返さない。
- 暗黙より明示:隠れた依存、マジックメソッド、暗黙の型変換を避ける。
- ドメインにインフラの詳細(SQL、HTTP、ファイルパス)を漏らさない。
U契約
- すべてのプリミティブと文字列を値オブジェクトで包む。
- 明示的なシリアライズ以外でジェネリック型(mixed, array, object)を使わない。
- すべての公開メソッドはインターフェースで宣言する。
- コメントは「なぜ」を説明し、実装ではなく契約に置く。
柱は互いを支える
規律が構成を可能にします。300行のクラスは差し替えられません。構成が中核を守ります。モノリスは依存を隠せません。守られた中核がインフラを本当に任意のものにします。契約だけが、それを外部から検証できる理由です。
柱を1つ外すと、残りは儀式になります。5つすべてを保てば、システムは退屈になります。橋が退屈であるのと同じ意味で。