⌨️

技術的負債を減らす「読めるコード」入門

に公開

Septeni Japan株式会社でプロダクト開発のエンジニアをしている工藤です。
本記事では、私自身が開発プロジェクトで実際に経験した、多くのエンジニアが直面する課題を題材に、『リーダブルコード』の教えを元にした具体的な解決策までをご紹介していきます。

忍び寄る「技術的負債」の影

「このコード、誰が書いたんだ…?」
チームでの開発経験がある方なら、一度はそう呟いたことがあるのではないでしょうか。
あるいは、半年前に自分が書いたコードを見て、同じ言葉が頭をよぎった経験があるかもしれません。

プロジェクトが発足したばかりの頃は、コードベースも小さく、全員が仕様を把握していました。
しかし、開発が進み、機能追加や仕様変更が繰り返され、メンバーの入れ替わりが起きると、状況は一変します。

  • 「この変数の flag って、一体何のフラグなんだ?」
  • 「この関数を修正したいけど、どこに影響が出るか分からなくて怖い…」
  • 「とりあえず動いているけど、誰も仕組みを正確に説明できない…」

いつしかコードは、書いた本人にしか意図が分からない「暗号」となり、次第にその本人でさえも解読が難しくなっていきます。

このような、将来の改修や機能追加を困難にする「読みにくいコード」 は、「技術的負債」 になり得ます。

最初は小さな負債かもしれません。
しかし、それを放置したまま開発を続けると、利息のように問題が膨れ上がっていきます。
勘違いが新たなバグを生み、簡単な修正のはずが数日を要するようになり、やがて誰も手をつけたがらない「ブラックボックス」が完成してしまうのです。

なぜ"読みにくいコード"が生まれるのか

では、なぜこのような「技術的負債」は生まれてしまうのでしょうか。

もちろん、誰もがわざと読みにくいコードを書こうとしているわけではありません。
納期に追われていたり、当時の知識ではそれが最善の方法だったり、様々な理由があったはずです。
しかし、多くの「読みにくいコード」に共通する根本的な原因が一つあります。

それは、「未来への想像力」の欠如です。

  • 半年後の自分は、このコードの意図を覚えているだろうか?
  • 新しくチームに加わったメンバーは、このコードをすんなり理解できるだろうか?
  • この仕様を知らない人が読んでも、処理の流れを追えるだろうか?

「今の自分」だけが理解できるコードを書いていると、それは時間と共に必ず負債となります。

「コードの分かりやすさなんて、センスの問題じゃないか…」
そう感じた方もいるかもしれませんが、違います。

読みやすいコードを書く能力は、センスや才能ではなく、具体的なテクニックで身につけることができます。
そして、そのためのテクニックが詰まった名著が、『リーダブルコード』です。

『リーダブルコード』は全エンジニアに読んでほしいですが、忙しい日々の中でなかなか時間が取れない方も多いはず。
そこで今回は、私自身が読んで特に「これは知っておいてほしい」と感じたテクニックを、厳選してご紹介します。

『リーダブルコード』から学ぶテクニック

本書では冒頭で「読みやすさの基本定理」として、こう定義されています。

「コードは他の人が最短時間で理解できるように書かなければいけない」

これは本当に良い言葉ですよね。
コードを書くときに常に心に留めておきたい基本原則です。
この「読みやすさの基本定理」を実現するために、本書の教えの中から特に重要だと感じたテクニックをいくつかご紹介します。

名前に情報を詰め込み、誤解をなくす

良いコードは、良い名前から始まります。
変数名や関数名がその役割を正確に表現していれば、コードの8割は説明できていると言っても過言ではありません。

  • 曖昧な単語を避ける

    • filter() という関数名を見て、「何を選択する」のか「何を除外する」のか、瞬時に判断できますか?
    • length という変数が「バイト数」なのか「文字数」なのか、迷うことはないでしょうか?

    このように、文脈によって解釈が分かれる単語は、誤解やバグの元です。
    特別な理由がない限り、selectUsers()excludeInactiveUsers()lengthInBytes のように、より具体的で誤解の余地がない名前を選びましょう。

  • 状態や単位を名前に含める
    特に重要なのは、データの「状態」を名前に含めることです。
    例えば、ユーザー入力をそのまま表示するのは危険ですが、エスケープ処理後の安全なHTMLであれば問題ありません。
    この違いを html という変数名だけで管理すると、いつか必ず事故が起こります。
    escaped_htmlunsafe_user_input のように、その変数がどのような状態なのかを明確に示しましょう。
    _utf8 のような文字コード情報も同様に重要です。

  • データ構造がわかるようにする
    特にPythonのような動的型付け言語では、変数を見ただけでは型がわかりません。
    user という変数が単一のユーザー情報なのか、ユーザーのリストなのか、一目では不明です。

    • 単数形・複数形を使い分ける(user / users
    • あるいは接尾辞でデータ構造を示す(user_list / user_dict / user_df
      といった命名規則をチームで徹底するだけで、可読性は劇的に向上します。

コードの「なぜ」を語るコメント術

「コメントは多ければ多いほど良い」というのは間違いです。
価値のあるコメントとは何かを考えましょう。

  • 「What」ではなく「Why」を書く

    # ユーザーIDを使ってユーザー情報を取得する
    user = fetch_user(user_id)
    

    上記のような、コードを読めばわかる「何をしているか(What)」を説明するコメントは不要です。
    もしコードが複雑で説明が必要だと感じたなら、それはコメントを追加する前に、コード自体(関数名や変数名)を改善すべきサインです。
    本当に価値のあるコメントは、コードの裏側にある「なぜ、そうなっているか(Why)」を伝えるものです。

    • # Cognito, SSMなど多数のクライアントを利用するため、メモリを512MBに増量
    • # APIの仕様上、一度に取得できる件数が100件までのため、ループで処理している

    このような、仕様上の制約や、設計判断の背景こそ、未来の自分や同僚が最も知りたい情報です。

  • 未来の罠を教える
    コードを読むだけでは気づきにくい注意点や、非直感的な動作についてもコメントを残しましょう。

    • 「この関数は特定の状況で例外を投げる可能性がある」
    • 「この値は外部サービスのこの項目と連動している」

    といった補足情報は、将来のバグを防ぐための貴重な道しるべとなります。

  • アノテーションコメントを活用する
    チーム内でのコミュニケーションを円滑にするために、決まった形式のコメント(アノテーション)を活用するのも有効です。

    • TODO: 将来的に実装すべき機能やリファクタリング箇所
    • FIXME: 既知のバグがあり、修正が必要な箇所
    • HACK: やむを得ずトリッキーな実装をした箇所
    • NOTE: 実装の意図や注意点の補足

    これらを活用することで、コードに「やるべきことリスト」や「取扱説明書」を埋め込むことができます。

複雑なロジックを分解し、流れを整える

コードの流れは、できるだけ上から下へ、インデントが浅い状態を保つのが理想です。
複雑なネストは、ロジックを追うのを困難にし、バグの温床となります。

  • 早期リターン(Guard Clause)を徹底する
    エラー処理や事前条件のチェックのために if-else を深くネストするのではなく、関数の冒頭で条件を満たさないケースを弾いてしまいましょう。

    # Bad: ネストが深い
    def process_data(data):
        if data is not None:
            if "id" in data:
                # 本質的な処理...
                return "Success"
            else:
                return "Error: ID not found"
        else:
            return "Error: Data is None"
    
    # Good: 早期リターンでスッキリ
    def process_data(data):
        if data is None:
            return "Error: Data is None"
        if "id" not in data:
            return "Error: ID not found"
    
        # 本質的な処理に集中できる
        return "Success"
    

    このように、前提条件を先に処理することで、メインのロジックをインデントの浅い、見通しの良い場所に記述できます。

  • 説明変数を活用する
    複雑な条件式や、複数回利用する式は、その式が「何を表しているのか」を示す名前の変数(説明変数)に格納しましょう。

    if (user.role == 'ADMIN' or (user.id == article.author_id and user.is_premium))
    

    のような式は、

    is_admin = (user.role == 'ADMIN')
    is_author = (user.id == article.author_id)
    can_edit = is_admin or (is_author and user.is_premium)
    
    if (can_edit):
    

    と分解することで、コードが自己文書化され、意図が格段に分かりやすくなります。

  • 不要なものは、コメントアウトではなく削除する
    使われなくなったコードは、ノイズです。
    将来使うかもしれないと思っても、バージョン管理システム(Gitなど)が過去のコードをすべて記憶してくれています。
    思い切って削除しましょう。
    コメントアウトされたコードの山は、読み手の混乱を招くだけです。

  • 変数のスコープを最小限にする
    グローバル変数は極力避け、変数はそれが必要な処理の直前で、可能な限り狭いスコープで定義しましょう。
    変数の生存期間が短いほど、その値がどこで変更されるかを追跡するのが容易になり、意図しない副作用を防ぐことができます。

ここで紹介したテクニックは、ほんの一部です。
しかし、これらの原則を意識するだけでも、あなたの書くコードの「読みやすさ」は格段に向上するはずです。

未来のチームのために、今できること

これまで『リーダブルコード』の具体的なテクニックをご紹介してきましたが、
この本が本当に伝えたかったのは、単なるコーディング作法だけではないように思います。
それは、「コードは、コンピューターへの命令である前に、人間同士のコミュニケーションツールである」という思想です。

近年、プログラミング教育の必修化などもあり、これからエンジニアとしてのキャリアをスタートする若手はますます増えていくでしょう。
彼らが初めて配属されたチームで目にするコードが、意図が分からず解読に苦しむようなものだったら、どう感じるでしょうか。
きっと、自信を失い、開発の楽しさを見失ってしまうかもしれません。

この記事で紹介したことは、決して難しいことではありません。
次に変数を命名するとき、少しだけ立ち止まって「もっと分かりやすい名前はないか?」と考えてみる。
複雑な条件分岐を目の前にして、「これを別の関数に切り出せないか?」と試してみる。
その小さな意識の積み重ねが、あなた自身とチームの未来を、より良いものに変えていきます。

もし、この記事を読んで少しでも共感するものがあれば、ぜひ『リーダブルコード』を手に取ってみてください。
きっと、あなたのコーディング人生における、確かな道しるべとなってくれるはずです。

Discussion