「コードは上から下へ読むのが一番」と思った時に、思い出してほしい話
序文
プログラミングを始めたばかりの頃、私たちはこう教わりました。
「プログラムは、上から下へ動くものである」
これはCPUの仕組みから考えても正しく、直感的です。
しかし、現在、私が取り組む「基幹システム移行」
そこで苦しんでいる原因もまた「上から下への一本道」にあります。
本記事では、
なぜ私たちが直感的な「一本道」を捨てて、
一見すると複雑な「アーキテクチャ(関心事の分離)」を選ぶのか。
その理由を、「人間の脳のスペック(認知の限界)」から紐解きます。
※どちらが優れているかという話ではありません。
「なぜ、そうなったのか」という、エンジニアが歩んできた歴史と選択のお話です。
スライド版もあります。
誰もが通る「一本道」の快感
最初のコードを「上から下への一本道」で書かれたコードにすることは、現代においても正義です。
(全くの新規で機能を開発する際、必ずそうします。)
これは、いわゆる「手続き型」のアプローチです。
ですが、これには開発初期においては価値があります。
あちこちのファイルを行き来する必要がなく、迷わない。
思考の流れのままに書き下すことができる。
int main() {
/* 変数宣言:ここで全てを把握できる安心感 */
int status = 0;
int count = 0;
int user_type = 1;
double price = 0.0;
FILE *fp;
/* ひたすら上から下へ */
fp = fopen("data.csv", "r");
if (fp != NULL) {
while( /* ...読み込み... */ ) {
/* ロジックがここに全部書いてある */
if (status == 0) {
if (user_type == 1) {
price = 1000.0;
count++;
}
/* ... */
}
/* ... (ひたすら続く計算と分岐) ... */
}
}
return 0;
}
プログラミングは純粋に楽しいものです。
この段階では。
作り手は神のように全ての変数を把握し、意図通りに世界を動かすことができます。
「楽しい時間」の終わりと、認知の限界
しかし、コードが1,000行、5,000行と育った時、かつての「快感」は「苦痛」へと変わります。
ここで直面するのが「認知の限界(Cognitive Limit)」です。
一本道のコードを読み解くために、無意識のうちに巨大な文脈を脳内のスタックに積み上げ続けています。
-
Statusは今Activeだ -
Countは99で止まっている -
UserはA001だ - ループの中でフラグ
IsProcessedがTrueになった...
この状態で、もし電話が鳴ったらどうなるでしょう?
あるいは、変数がもう一つ増えたら?
「あれ、今の状態(State)、どうなってたっけ?」
一瞬で脳内メモリが溢れ、積み上げたコンテキストが崩壊(Reset)します。
こうした「忘却」と「再構築」の徒労を経て、私たちはある決断に至ります。
「分ける」ことです。
なぜ私たちは「分ける」のか
限界を迎えた我々は、コードをクラスやモジュールに分割し始めます。
これは単に「コードが整理整頓されていると綺麗だから」ではなく
「人間のスペックの限界だから」です。
しかし、ここで新たなジレンマが生まれます。
「バラバラに分かれていて、逆に行ったり来たりして読みにくい...」
この感覚は正しく、一本道の方が直感的です。
では、なぜ読みづらさを許容してまで分けるのか。
それを理解するために、System 1 / System 2 という脳のモードについて触れます。
脳の2つのモード
ダニエル・カーネマンらが提唱した理論を借ります。
人間の思考モードは2つに分けられます。
| モード | System 1 (速い思考) | System 2 (遅い思考) |
|---|---|---|
| 特徴 | 直感的・無意識・自動的 | 論理的・意識的・計算的 |
| コスト | 省エネ | 激しく消耗する |
プログラミングにおいて、変数の値を追跡したり、複雑な条件分岐をシミュレーションしたりする作業は、高コストな System 2 です。
脳内メモリ(RAM)の枯渇
巨大な一本道コードを読むとき、私たちの脳内リソースは以下のようになっています。
変数を覚えることに System 2 を使い果たし、肝心の「業務ロジック」を思考する余地がありません。これでは、ビジネスロジックの理解がすすみません。
アーキテクチャ=「地図」を持つ選択
ここで「関心事の分離(SoC)」やアーキテクチャパターンの出番です。
構造化し、詳細を隠蔽することは、脳のメモリを解放するために行います。
構造を理解するために「地図」を読むコストは発生します。
が、その代わり「変数の状態」を記憶し続けるコストからは解放されます。
人間の脳は、膨大なランダムアクセスメモリ(記憶力)よりも、パターン認識(地図を読む力)の方がスケールするようにできているからです。
明日からの武器:「カプセル化」という思いやり
理論はわかりました。
では、我々はどうコードを書けばいいのでしょうか。
抽象化、DI、境界づけられたコンテキスト...武器は多くありますが、最も身近で重要な「カプセル化(隠蔽)」について考えます。
認知負荷の観点から
カプセル化とは、「詳細を忘れる自由」を読み手に与えること
と捉えることができます。
中身がどうなっているか「知らなくても使える」状態にする。
それは、未来のコードの読み手に対して、
「この中の複雑なロジックは、私が引き受けました。
あなたはこのカプセルを飲む(メソッドを呼ぶ)だけでいい。
中身のことは、忘れていいんだよ。」
これこそが、設計における「思いやり」です。
結論:わかりやすさとは「脳への配慮」
コードを書くとき、自分に問うてみてください。
「この設計は、未来の読み手が中身を『忘れる』ことを許しているか?」
もし、読み手がその関数を使うために、
内部の変数の状態や実行順序を事細かに覚えていなければならないとしたら、それは「忘れること」を許していません。読み手の System 2 を酷使するコードです。
「わかりやすさ」とは、読み手の脳のリソースを節約し、System 1(直感)でスラスラと本質的なロジックを追えるように整えてあげること。
先人たちが築き上げた設計手法やアーキテクチャは、決して高尚な理論のためではなく、人間の不完全な脳を助けるための知恵なのです。
一本道のコードが生み出した初期の価値に敬意を払いつつ、
それが限界を迎えた時、「地図」を手に取りましょう。
未来の私と、コードを読んでくれる仲間の「脳」を守るために。
Discussion