0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

リーダブルコード 覚書

Last updated at Posted at 2025-09-07

リーダブルコードを読み、自分なりに解釈してまとめた覚書です。

表面上の改善

名付け

  • 誤解されにくい明確な名前を付ける
    • send → 〇 deliver, dispatch, announce, distribute, route
    • find → 〇 search, extract, locate, recover
    • filter → 〇 select / exclude
       
  • 汎用的な名前や短い名前(例:tmp, retval)を避ける
    • 具体的な名前の方がバグに気づきやすい
      • 例:sum_squares(意味:2乗の合計)
    • スコープが短い場合は使ってOK
      • コードを簡単に追えて用途を理解できるから
         
  • 重要な属性を付与する
    • 例:値の単位を付ける
      • start → 〇 start_ms(意味:ミリ秒)
      • size → 〇 size_mb(意味:メガバイト)
         
    • 例:注意喚起する ※ バグになりそうな箇所だけ付与でOK
      • password → 〇 plaintext_password(意味:暗号化が必要)
      • comment → 〇 unescaped_comment, raw_coment(意味:エスケープが必要)
      • html → 〇 html_utf8(意味:文字コードをUTF-8に変えた)
         
  • 限界値を決めるときは min / max を使う
    • CART_TO_BIG_LIMIT
      • 「未満」なのか「以下」なのか判断できない
    • MAX_ITEM_IN_CART
       
  • 範囲を指定するときは first / last を使う
    • print range(start=2, stop=4);
      • 出力は「2, 3」?それとも「2, 3, 4」?
    • print range(first=2, last=4);
      • last を使えば、4を包含していることが明確
         
  • 「包含/排他的範囲」(= 開始は含み、終了は含まない範囲)を表現するときは、慣習的に begin / end を使う
     
  • Bool値だと分かる名前にする
    • 例:is, has, can, should, use, need
       
  • 先入観のある単語に気をつける
    • getResult()
      • メンバ値を返すだけの軽量アクセサだと思われがち
    • computeResult()
      • コストの高い計算の場合は compute などの名前にすべき

レイアウトを整える

  • 改行のタイミングや変数の並びなどに一貫性と意味を持たせる
     
  • 縦の線をまっすぐにする
    • 例:変数への代入を複数行に記載する際、= の位置を縦方向で揃える
      • ただ、メンテナンス箇所が増えるので、この項目については好みが分かれる
         
  • 宣言をブロックにまとめる
     
  • 段落に分割する

コメント

  • 読み手の立場になって考える
    • コードを読んだ人が「えっ?」と思うところを予想してコメント
    • 利用時にハマりそうな罠を注意喚起
    • ファイルやクラスには「概要」を記載
       
  • あいまいな(複数の意味を示す)言葉を使わない
    • 例:代名詞(「それ」「これ」)など
       
  • 入出力の実例を書く
    • 例:
      // src の先頭や末尾にある chars を除去する
      ↑「chars は順序のない文字集合?」「src 末尾に複数の chars があったら?」など疑問が生じる
      // 実例:Strip("abba/a/ba", "ab") は "/a/" を返す
      ↑ このように実例を書いておけば明確
      String Strip(String src`, `String chars) { ... }```
      

 

  • コードの「動作」ではなく「意図」や「なぜこの実装をしたのか」を書く
    • 良い例1:
       // 価格の高い順に表示する
      
    • 良い例2:
       // このデータだとハッシュテーブルよりバイナリツリーの方が40%速かった
      
    • 良い例3:
       const MAX_RSS_SUBSCRIPTIONS = 1000; // 合理的な限界値。人間はこんなに読めない
      

 

  • 多くの意味が詰め込まれた言葉や表現(例:ブルートフォース、ヒューリスティックなど)を使って、簡潔にする
    • 悪い例:
       // この関数は、問題を解決するための一番単純な方法で書かれている
       // もっと速いアルゴリズムがあるが、とりあえず動くことを優先
      
    • 良い例:
       // TODO: まずはナイーブソリューションで実装したので、要改善
      

ループとロジックの改善

制御フロー

  • 比較を書くときは、変化する「調査対象」の値を左に、あまり変化しない「比較対象」の値を右に配置する
    • 例:if(bytes_received > bytes_expected)
       
  • 可能ならガード節を使う(特殊なケースやエラーは冒頭で処理し、すぐに処理を抜ける)
     
  • if/else文のブロックの並びは、基本的には以下のものを先に処理することで、読む人の認知的な負担を減らす
    • 単純な条件:コードの長さ的に ifelse が同じ画面内に収まりやすいので見やすい
    • 正常系、主要なケース:「このコードが主に行なっている処理は何か?」を先に伝えたい
    • 肯定系の条件:肯定系の方が直感的。ただし、否定系でも目立つ条件の場合は先に書く
       
  • 以下の構文は、あまり使わない方がいい
    • 三項演算子:単純な条件式の場合なら使ってOK
    • do/while文:ループの終了条件が最後まで分からないため
    • goto文:プログラムの実行順序を理解しにくい
       
  • ネストを浅くする
    • returncontinue を利用し、なるべくネストを削除する

変数

  • 複雑な式は理解するのに時間がかかるため、適切な名前の変数に代入する(= 説明変数)
  • ただし、変数が多いと追跡するのが難しくなるため注意
    • 良い例:
       username = line.split(':')[0].strip()
       if username == "root" { ... }
      
    • 悪い例:
       now = datetime.datetime.now()
       root_message.last_view_time = now()
      

 

  • 変数のスコープはなるべく小さくする
     
  • 変数の定義は、変数を使う直前に行う。先頭にまとめて定義すると覚えておくのが大変
     
  • 一度だけしか書き込まない変数を使う(あるいは、constfinal でイミュータブルにする)とコードを理解しやすい。

コードを再構成するときに大事な視点

  • プログラムの主目的と関係のない「無関係な下位問題」を抽出する
     
  • 一度に1つのことをやるようにする。メソッドを分けるか、ブロックにまとめる
     
  • なるべくライブラリでロジックを実現する
    • ライブラリやAPI、組み込みモジュールの一覧に目を通しておき、「引き出し」を作っておく
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?