🔍 暗黙知だらけコード(Explicit is better than implicit)
🧭 はじめに
このページでは、「動くけれど説明できないコード」 が生まれる最大要因である 暗黙の前提(implicit assumptions) に焦点を当てます。 Python の Zen における Explicit is better than implicit は、可読性の話ではなく、 設計上の責任の所在をコードに刻めているかという問いです。
🎯 ねらい
- 「なぜこのコードは壊れやすいのか」を、暗黙知という観点で言語化する
- 「察しの共有」に依存しない、契約が読めるコードの基準を示す
❓ 問題の定義
暗黙知だらけコードとは、次のような状態です。
- 型・単位・前処理・例外条件がコード上に現れない
- 呼び出し側が「こうだろう」と推測して使うことを前提にしている
- 正しく使われている限りは動くが、誤用時の挙動が不定
暗黙の前提は「共有されている間だけ」安全です。 チーム・時間・用途が変わった瞬間に破綻します。
🤒 よくある症状
🏷️ 名前が情報を持っていない
processhandleexecutedo_something
→ 何を・どこまで・副作用はあるのかが分からない。
📦 引数の意味が曖昧
dataobjparams
→ 生データ?検証済み?正規化済み? どの段階のデータかが不明。
🔁 戻り値の契約が揺れている
- 成功時は値を返す
- 条件によって
None - 異常時は例外を投げることもある
→ 呼び出し側が every case を推測で処理することになる。
戻り値と例外の責務が混在すると、エラーは必ず取りこぼされます。
❌ 悪い例:すべてを飲み込む関数
def process(data):
# 何を期待しているのか不明
# dataの型も単位も前提も書かれていない
if not data:
return None
# 検証?
if 'value' not in data:
return None
# 変換?
data['value'] = int(data['value'])
# 保存?
save_to_db(data)
return data
問題点
- 検証・変換・永続化が一体化
Noneが「何を意味するのか」不明- 失敗の理由が呼び出し側から観測不能
- I/O があることが名前から分からない
✅ 良い例:境界と責務を分ける
def validate_input(raw: dict) -> None:
if 'value' not in raw:
raise ValueError('value is required')
def normalize_input(raw: dict) -> int:
return int(raw['value'])
def persist_value(value: int) -> None:
save_to_db(value)
改善点
- 各関数が1つの責務しか持たない
- 失敗は例外として明示
- 型・単位・副作用が読み取れる
- 呼び出し側が制御フローを設計できる
処理を分けることは、設計判断をコードに露出させることです。
🧩 設計の要点
明示すべきものは3つだけ
-
境界 どこからがこの関数の責任か
-
契約 入力条件・出力保証・失敗の仕方
-
副作用 I/O・DB・外部状態の変更があるか
これらがコードから読み取れれば、 ドキュメントを読まずとも安全に使えます。
✅ チェックリスト
- 関数名だけで 副作用(I/O/DB/通信) を想像できるか
Noneが返る場合、その意味は 1つに定義されているか- 入力が不正な場合の挙動が 例外 or 戻り値で明示されているか
- 呼び出し側が「察し」を必要としていないか
🧠 まとめ
暗黙知だらけコードは、 「作者の頭の中にある設計」をコードに書き切れていない状態です。
Python の Zen が言う Explicit とは、
すべてを書くことではなく、 誤用されたときに壊れ方が分かること
です。
次の記事では、この暗黙知が構造的に可視性を奪う 「🪆 ネスト地獄」を扱います。