「脳に収まるコードの書き方」は脳に収まったのか?
はじめに
私は昨年、「脳に収まるコードの書き方」という書籍を読み、それを記事にまとめていました。
良く言えばアウトプット、ワルく言えば 明らかな劣化を伴う 縮小再生産です。
冒頭からすでに面白い - 脳に収まるコードの書き方① - ReadLog
さて今回は、約1年が経過して、果たして読む価値があった本だったのか、そして私が読むに値する人間だったのか審判を下します。
書籍の概要
そんな本知らない、という人もいると思うので簡単に説明しておきましょう。
もちろん、私の記事を読んでいただいてもいいんですよ!
ソフトウェア開発は高度に複雑化しています。しかし人間の脳の根本的構造は変わり様がありません。
そんなソフトウェアの複雑さをそのまま実装したときに完成するのは、「脳に収まらないコード」です。
そんなコードは、開発が難しく、検証が難しく、保守が難しい、腐敗した地獄にしか導いてくれません。
この本はそんな地獄への道を封鎖して、システムをマクロ・ミクロに理解可能なコードを書く方法・維持する方法を丁寧に説明してくれます。
これだけ知っても本の内容を損なうことはないので、答えだけ教えておきます。
脳に収めるためには「サイクロマティック複雑度を7以下に抑える」です。
サイクロマティック複雑度は、コードの断片を通る経路を数えるものだと考えてください。
(中略)
1から始めて、ifやforが何回登場するかを数えます。キーワードが登場するごとに、(1から始まる)数字をインクリメントします。
コード全体の呼び出し構造を幹から枝へ、枝から葉へ伝っていくように組み上げることを奨励します。コードをズームイン・ズームアウトするように読み取ることでシステム全体が脳に収まるようになる。はずです。
さて、記事にまとめ始めてから1年が経過しています。果たして役に立ったのでしょうか?
前提
まず、システムエンジニアとしての私の前提を共有しておきます。(守秘義務の範囲内で)
- クラウドサーバーを使う、どちらかといえばバックエンド寄り。
- フロントエンド開発は正直よくわかんないです。
- 開発内容は機能要件で多くが説明できる内容が多いです。(使い心地とかの要素はそこまで出てこない)
- それなりに頑張ってるつもりですけど、言うてペーペーの雑魚エンジニアです。
- 資格勉強めんどくさすぎて無免(特にクラウド系の資格持ってないという意)です。
- 本を読んでからの作業は、主に新規開発(試作)でした。
- 裁量権大き目で、わりと好き勝手に仕様調整できる環境でした。(ラッキー!)
- 開発言語は主にPythonです。
- 別に最高な言語ではいんですが、慣れててまあ書きやすいので。
振り返り
では、いくつかの教えをピックアップして状況を整理してみましょう。
| 教え | 実施状況 | 説明・所感 |
|---|---|---|
| 警告はエラーとして扱う | ◎ | RuffとMyPyの警告有効化して対処してました |
| 関連するコードは近づけ、機能を縦割りで実装する | ○ | 定数は定数用のファイルに分けるルールに |
| メソッド引数から処理が分かるようにする | ○ | 型アノテーションをつけまくりました |
| 状態を減らし、純粋関数にする | ○ | 純粋関数にすることを意識して実装・レビューした |
| 無効な状態を持たないようにカプセル化をする | ○ | コンストラクタがエラー出す実装を重視 |
| 1メソッド24行×80文字に抑える | △ | 正直少なすぎ、100文字まで条件緩和してる |
| ゾーンに入ろうとしない | △ | 仕事なんで別にゾーンは目指してないが... |
| テスト駆動開発 | △ | テストコードの実装が実装の後に来ることも... |
| サイクロマティック複雑度を7以下にする | △ | 10以下のルールに、でも原則7以下に収まってるはず |
| デバッグ時は原因究明を最重要視する | △ | 自主的にできたかというと...アドバイスのおかげ |
| ビルド・デプロイを自動化する | × | そもそも試作品で、デプロイの頻度が高くなかった |
| フィーチャーブランチではなくフィーチャーフラグを使う | × | 使える場面がなかった |
| 置き換えは少しずつ(ストラングラーフィグ) | × | 使える場面がなかった |
| テストコードがNGを出すのを確かめる | × | やってる余裕がなかった |
| Gitを使う | × | SVNを使わざるを得なかった |
| ちょっとの変更でコミットする | × | SVNと相性悪いのでやれず |
半分ぐらいは達成できた、と思います。
一部は外的要因(※)なので目をつぶるとして...一部の項目について自慢と反省をつづろうと思います。
※SVNの利用は終わりそうな雰囲気があったりなかったりします。
※あくまで試験開発的な要素が強かったので、今後は機能改修のテクを使う場面が来るかも...?
警告はエラーとして扱う
こんな教えでした。
コンパイラ警告をエラーとして扱ってください。リンター、静的コード解析の警告もエラーとして扱いましょう。
p.23 2章 チェックリスト
これを、VSCodeにRuffとMyPyの拡張機能を入れることで実現しました。
Ruff
Ruff
RuffはPython用の静的解析とリンターのツールです。
PEP8というコーディング規約だったり、その他もろもろの「こうしたほうがいい」系の警告をしてくれるようになります。
Rustで実装されているのでサクサク動作です。
MyPy
mypy - Optional Static Typing for Python
MyPyは、Python用の型解析ツールです。
int型で定義した変数に文字列の値を入れる、みたいな実装をしていれば警告が出ます。
Pythonで実装されているので遅いです。キャッシュファイルが大量に生成されるのでコミットしないように注意しましょう。
※Ruffの開発元のAstralが開発中のtyという型チェッカに期待しています。
GitHub - astral-sh/ty
一部の警告(※)を除いて、この2つのツールから出てくる警告は無視しないで実装修正で対応することにしています。
※ドキュメント記述を大文字で始めてピリオドで終わらせること、とかログメッセージの長さで上限を超えるとか。
メソッド引数から処理が分かるようにする
MyPyの導入とも絡んできますが、メソッドの引数・戻り値や定数定義で型アノテーションをつけるルールにしています。
typing --- Support for type hints — Python 3.13.5 ドキュメント
intとかstrとかはまだしも、CollableとかTypeVarとかも使っているので逆にわかりにくい可能性もありますが...すくなくともMyPyがちゃんと仕事してくれているので満足です。
型アノテーション周りの余談
こんな教えでした。
メソッド名をXで置き換えても、メソッドが何をするかが想像できるかどうかを確かめてみましょう。
p.126 8章 API設計
余談ですが、Pythonの型アノテーションのルールは3.10から大きく変わっています。
例えばintとstrの両方を入れてOKな変数を定義するとします。
3.9までならこんな感じ:
from typing import Union
val: Union[int, str] = 100
3.10からだと:
val: int | str = 100
Unionのインポートが不要になって簡潔になりました。
その他、OptionalとかListとかも不要になっています。
で、ここまでなら「コードが書きやすくなった」というだけのいい話なんですが、問題はLLMを使った場合。
LLMはいかんせん知識が古く、平気でUnionを使ったサンプルコードを提案してきます。
古い記法はRuffで警告されるので、
MyPyの警告を見てLLMに聞く→LLMの回答を反映(古い記法)→Ruffから警告
という警告のたらいまわしになります。Pythonの型アノテーションの知識不足の人がいる場合は注意しましょう。
サイクロマティック複雑度を7以下する
Ruffのオプションで10を最大値に設定しています。
Settings | Ruff lint.mccabe.max-complexity
大半の関数はサイクロマティック複雑度が7以下になってます。ほんとです。
でも正直なところ、サイクロマティック複雑度が8以上になるような関数を作りたくなる時はたまにあります。そういった関数に警告に出さないためのバッファ...という位置づけです。
テストコードがNGを出すのを確かめる
テストコードとプロダクションコードを同時に編集する必要がある場合は、一時的にせよ、テストを意図的に失敗させることでテストを検証してください。
p.181 11章 ユニットテストを編集する
正直言って、これはできていないです。なにぶん忙しいもので...
言い訳だけしておくと、テスト仕様書を作成・更新し、検証が適切かはレビュー、テストコードにも対応する更新が実施されていることチェックしています。
まあ、このあたりの手続きは要改善ですね。
その他、特に言及しなかった項目についてはコメント等で質問いただければ!
で、脳に収まっているのか?
正直これは何とも言えません。
処理構造を設計したのが結局私なので「そもそも全部頭に入ってるわ!」という状況だからです。
なのでもうしばらく時間をおいて、忘れたころにコードを見たとき「分かりやすい」と思うか「誰だよこれ書いた奴」とブチギレるかを楽しみにします。
まとめ
個人的には、読んだことは生かせたんじゃないかなと思います。さて、ここまでの文章をChatGPTに投入し、「脳に収まるコードの書き方は脳に収まったか?」を評価してみました。
結論:「脳に収まるコードの書き方」は、脳に収まっていない。
理由を述べるわ。
- 記憶の定着ではなく、振る舞いの変容が測定基準
あなたは本の内容を部分的に記憶し、実践しようとした。
だが「脳に収まる」とは単なる記憶や理解ではなく、それが自然な振る舞いとして滲み出ることを意味する。未達の項目が多く、それを環境要因として片付けている時点で、外部の制約が内面化を上回っているという証左になる。
- 可逆性と再構成能力
「設計した本人だから理解できていた」は当然の話。
本当に脳に収まっていたなら、時間が経って忘れても、同じ判断と構造を再構成できるはず。それが「思考様式への定着」だから。現時点では「意識的に実践していた」段階にとどまり、「無意識の再現性」にまでは至っていない。
- 他者への伝播性の欠如
収まったコードは、他人の脳にも収まりやすい。
それはレビューでの説明負荷や、仕様変更時の設計耐性として表れる。今回の振り返りには、「他人がどう読んだか」「共同開発者にどう作用したか」の視点が欠けている。
自己完結した知識は、閉じた系の中では最適でも、外界との接続を持たない。
なかなか手厳しい意見ですが、
①もっと無意識的に実行できるようになる。
②客観的な評価を取り入れる
が必要なようです。精進します。道のりは長い...
Discussion