メインコンテンツへスキップ

🔍 暗黙知だらけコード(Explicit is better than implicit)

🧭 はじめに

このページでは、「動くけれど説明できないコード」 が生まれる最大要因である 暗黙の前提(implicit assumptions) に焦点を当てます。 Python の Zen における Explicit is better than implicit は、可読性の話ではなく、 設計上の責任の所在をコードに刻めているかという問いです。


🎯 ねらい

  • 「なぜこのコードは壊れやすいのか」を、暗黙知という観点で言語化する
  • 「察しの共有」に依存しない、契約が読めるコードの基準を示す

❓ 問題の定義

暗黙知だらけコードとは、次のような状態です。

  • 型・単位・前処理・例外条件がコード上に現れない
  • 呼び出し側が「こうだろう」と推測して使うことを前提にしている
  • 正しく使われている限りは動くが、誤用時の挙動が不定

暗黙の前提は「共有されている間だけ」安全です。 チーム・時間・用途が変わった瞬間に破綻します。


🤒 よくある症状

🏷️ 名前が情報を持っていない

  • process
  • handle
  • execute
  • do_something

何を・どこまで・副作用はあるのかが分からない。


📦 引数の意味が曖昧

  • data
  • obj
  • params

→ 生データ?検証済み?正規化済み? どの段階のデータかが不明


🔁 戻り値の契約が揺れている

  • 成功時は値を返す
  • 条件によって 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つだけ

  1. 境界 どこからがこの関数の責任か

  2. 契約 入力条件・出力保証・失敗の仕方

  3. 副作用 I/O・DB・外部状態の変更があるか

これらがコードから読み取れれば、 ドキュメントを読まずとも安全に使えます。


✅ チェックリスト

  • 関数名だけで 副作用(I/O/DB/通信) を想像できるか
  • None が返る場合、その意味は 1つに定義されているか
  • 入力が不正な場合の挙動が 例外 or 戻り値で明示されているか
  • 呼び出し側が「察し」を必要としていないか

🧠 まとめ

暗黙知だらけコードは、 「作者の頭の中にある設計」をコードに書き切れていない状態です。

Python の Zen が言う Explicit とは、

すべてを書くことではなく、 誤用されたときに壊れ方が分かること

です。

次の記事では、この暗黙知が構造的に可視性を奪う 「🪆 ネスト地獄」を扱います。