シングルパーパスな人々に気をつけろ
純粋すぎて痛い
Single Responsibility Principle(単一責任の原則)は、あまりにも理にかなっているため、判断力をすり抜けてしまうような考え方のひとつだ。
ひとつのことだけをしろ。うまくやれ。モジュールは焦点を絞れ。変更の理由をコードに与えろ。良いアドバイスだ。
ところが、誰かがそのアドバイスをメジャーに変えてしまい、「5行を超える関数はコードの匂いがする」と宣言し始める。
問題なのはSRPではない。「小さい」ことを「凝集している」ことの代用品とみなすことだ。
その瞬間、あなたは「シングルパーパスな人々」に出くわしたことになる。モジュール化について完全に間違っているわけではないが、有用な境界線と最大限の断片化を混同している開発者たちだ。

I. その下にある有用なアイデア
フォームにチェックボックスを1つ追加するだけで、 ideally 1つのファイルにしか影響を与えないはずだ。5つのディレクトリにまたがる8つのファイルに影響を与えるなんて…お前らのことだ、React/Redux。
SRPが判断力を持って適用されれば、確かに役に立つ。単一の概念的タスクに焦点を当てたコード単位は、理解しやすい。テストは適切な境界で動作を対象にできる。明確なモジュールは、アプリケーションの残りの部分を引きずり込まなくても、システムの一部を変更しやすくする。
古典的なUnixの例でさえ、スローガンが示唆するほどには純粋ではない。ls はファイルをリストするが、opendir、readdir、closedir、stat などの呼び出しも調整している。有用な単位は最小限の操作ではない。タスクを解決する最小限の凝集したものだ。
オリジナルのUnix哲学は、すべてを単一の関数やファイルに縮小することではなく、合成と単純さについてだった。
この違いは重要だ。「ひとつの責任」は「1行の振る舞い」と同じではない。
II. 過剰な抽象化:単純さがカオスに変わるとき
「5行を超える関数はすべて『コードの匂い』だ」と建築家が insisting する。私たちのコードベースは今、 clueless な絶望の匂いをかすかに放っている。
この失敗モードは、すでにあなたの週を悪化させた後なら簡単に見分けがつく。
コードベースにはファイルが増えているが、形は失われている。すべてのヘルパーがヘルパーを持っている。すべての概念が、製品の意味ではなく技術的な役割で名付けられたフォルダに分割されている。チェックボックスを追加するには、コンポーネント、フック、セレクター、アクション、リデューサー、定数、テストフィクスチャ、そしてインポートパスが罪悪感を持たないように存在するだけのバレルエクスポートに触れる必要がある。

その純粋さは何を買ったのか?
- ファイルシステムの破片: ソースディレクトリが、しばしば悲劇的に孤独な関数を1つだけ含む無数の小さなファイルの悪夢のような風景に膨れ上がる。ナビゲーションは探検の演習になる。
- 依存関係のもつれ: 実行を追跡するのに大きなホワイトボードと、その機能に値する以上の忍耐が必要なほど密なインポートとエクスポートのウェブ。ちょうど一度だけインポートされたファイルが、再利用可能であるふりをしてそこにある。
- テストの背信: テストは、最小限の実装詳細を守る壊れやすい、超特異的な番人になる。関数のシグネチャを変更する? 何十ものテストが古代の陶器のように崩れ去るのを見守れ。テストスイートはセーフティネットから地雷原へと変貌する。
- 速度の消失: 単純な変更が、複数ファイルにまたがる修正の叙事詩に転移する。新しい開発者のオンボーディングには、
UserProfileコンポーネントが実際にどこにあるかを見つけるために地図とコンパスを数週間手渡すことが含まれる。この「組織化」の重みの下で、前進は地質学的な Crawling に減速する。
私は、単純な100行の機能が15以上のファイルに切り刻まれ、それぞれが1つか2つの関数しか含まない「純粋な」小さな天使であるコードベースの深淵を覗き込んだことがある。その混乱を頭の中に保持しようとする認知的爆発半径は、分離からの理論的な利点を完全に打ち消した。それは単純ではなかった。ただ散らばっていただけだ。
III. 完璧さの代償:開発者への影響
機能を実際に出荷するよりも、ファイル構造と命名規則について議論する時間の方が長い。これがアジャイルなのか?

この病理的な断片化は美的な問題だけではない。開発者がどのように注意を払うかを変える:
生産性の低下: 技術的負債を忘れろ。これは強迫神経症的なディレクトリのネストを通じて蓄積された組織的負債だ。すべての小さな修正が、抽象化の層を通じた考古学的な発掘調査になる。時間は cd .. と grep のブラックホールに消えていく。
テストの税金: テストスイートは自信を与える代わりに、摩擦の源になる。軽微なリファクタで壊れたテストを修正するために時間が溶けていく。それらのテストは、検証すべき微視的な詳細にあまりにも密結合していた。
認知的負荷: 人間の脳が同時に扱える断片化された情報には限界がある。開発者に12の散らばったファイルからプログラムの流れを組み立てさせることは、理解を積極的に妨げ、自信を持った変更をより難しくする。
IV. 実用主義の採用:実践的な代替案
「関連する2つの関数を同じファイルに置くことを提案したら、ステージングを削除する提案をしたかのような反応をされた」 — 回復中の純粋主義者の読者より
出口はSRPを放棄することではない。答えはそれを意味の正しいレベルで適用することだ。
実践ではこれがどのような姿になるか:
- 原子ではなく凝集に焦点を当てる: 一緒に変更されるもの、概念的に一緒に属するものをグループ化しろ。モジュールはユーザー認証のいくつかの関連する側面を扱うかもしれない。それでいい。ログイン状態に関連する関数を1つずつ持つ6つの別々のファイルよりも、おそらく良い。
- 一緒に動くものを一緒に保つ: 実際の再利用性など、明白で具体的な利点がない限り、関連するコードを分割するな。仮想的な未来ではなく、実践での再利用性だ。近接性は理解のために重要だ。
- 現実に駆動させる: 機能的純粋性の抽象的な理想ではなく、アプリケーションの実際の機能とワークフローに基づいて整理しろ³。この構造は、誰かが
Feature Xを理解して修正するのを容易にするか、難しくするか? - ミートウェアを気にしろ: 不幸な開発者のことを忘れるな。コードを操作するために必要な精神的ジャグリングを最小限にする組織は何か? 人間の理解のために最適化しろ。
- 重要なものをテストしろ: すべての小さな関数の内部配線に密接にはんだ付けされたテストではなく、適切な境界で動作を検証するテストを書け。カバレッジ率の劇場ではなく、自信を目指せ。
目標は博士号論文に値する理論的な完璧さではなく、同僚(そして未来のあなた)がビルに火をつけたいと思わずにナビゲート、理解、修正できるコードを作成することだ。
時には、ファイルが50行ではなく200行になることもある。時には、関数がデータの取得とわずかな変換の両方を処理することもある。時には、クラスに2つの責任があり、それらが密結合しているため一緒にあるべきこともある。それがシステム全体を作業しやすくするなら、おそらく正しい選択だ。
実用的な質問に relentessly に焦点を当てろ:
- 新人は周りをnavigateできるか?
- 無関係な
Yを壊さずにXを変更できるか? - このテストは、機能が実際に動作しているかどうかを教えてくれるか?
- 私たちは価値を出荷しているのか、それともフォルダを並べ替えているだけなのか?
V. 結論:凝集性と保守性のあるコードの育成
単一責任の原則は有用なツールだ。コードベースを原子の粉塵に粉砕するための命令ではない。どんなツールと同様に、その価値は使う人の判断に依存する。
だから、3行を超える関数に戦争を仕掛ける準備ができているシングルパーパスな人々に出くわしたら、深呼吸しろ。12ファイルのチェックボックスを思い出せ。
私たちの仕事は、理論的に完璧な雪の結晶のような関数を構築することではない。私たちの仕事は、動作し、問題を解決し、次に触れる人を罰しないソフトウェアを構築することだ。
実用的であれ。結果に焦点を当てろ。完璧な純粋さの追求が保守可能なコードの敵になるな。あなたの正気、そしてあなたのチームの速度は、それに依存している。
¹ 皮肉なことに、最低レベルで実際の単一責任を達成するには、表面のすぐ下に隠された immense な複雑さが必要だということ。
² ここでの純粋性について話しているのは、関数が論理的に「1つのこと」だけを行うべきだという考えだ。副作用のない関数型プログラミングの「純粋関数」の概念と混同するな。それは別の、時には関連するが異なるアイデアだ。