この記事のポイント

  • 「定数化できるか? 変数に残すべきか?」の設計判断をレビューで読み取る力をつける
  • const-correctnessをレビュー観点として捉え直す
  • スコープ・変更可能性・初期化タイミングを整理する

レビューの現場では「const付けましょう」と形式的に指摘される場面も多いですが、
本来は変更可能性の設計意図を読み取るレビューが重要になります。


1. 変数定義がレビュー対象になる理由

1-1. 変更可能性は設計そのものに関わる

  • 誰がいつこの値を変更する想定なのか?
  • そもそも本当に変更する必要があるのか?
  • 誤って変更されないように守るべきか?

この判断がコードにはっきり表現されていることが大事です。


1-2. 設計意図が埋め込まれていない例

int retryCount = 3;

この 3 は単なる数字ですが、

  • 仕様で固定なのか
  • 環境で変わる前提なのか
  • テストで差し替える想定なのか

レビューアーはこういった背景を読み取る必要があります。


2. 変数定義は「管理責任の宣言」でもある

パターン 説明
定数(constexpr / const 変更禁止を明示して固定
変更可能変数 状態変化の必要がある設計
誤変更誘発変数 本来固定のはずが変更可能に残してしまった設計

3. constexpr と const の使い分け

3-1. constexpr(完全固定)

  • コンパイル時に値が確定するもの
  • 実行時のコストゼロ
  • 設計的にも「動かない設計」を意味する
constexpr int MaxRetryCount = 3;

3-2. const(実行時固定)

  • 実行時に決まるけれど、その後変更不可
  • 設定ファイル読込結果などに多い
const int RetryLimit = config.GetDefaultRetryLimit();

3-3. 比較表まとめ

| 特性 | constexpr | const | |–|–| | 決定タイミング | コンパイル時 | 実行時含む | | 設計意図 | 完全固定宣言 | 実行後固定宣言 | | 最適化効果 | 高い | 状況次第 |


4. const-correctness というレビューの要所

4-1. const-correctness = 変更不能契約の宣言

class Config {
public:
  std::string GetName() const;
};
  • メンバ関数に const が付いていれば、
    「この関数は状態を変更しません」 と読むことができます。

4-2. const を付ける場所は多い

  • 関数引数
  • 戻り値
  • メンバ関数自体
  • ポインタ・参照先の内容
void Process(const ApiRequestLog& request);
  • const は実装の都合ではなく、設計意図の整理結果として付くもの です。

5. 良い実装例:設計が整理された定義

#pragma once

#include <string>

struct ApiRequestLog {
    int requestId;
    std::string endpoint;
    std::string clientIp;
};

inline constexpr int DefaultTimeoutSeconds = 30;

class Config {
public:
    Config(const std::string& filename);
    int GetMaxRetryCount() const;

private:
    const std::string configFile;
};
  • 定数は constexprconst を使い分けて整理
  • 不変メンバには const を付け、設計意図を明確にしている

6. よくある誤りとレビュー例

ケース1:本来固定なのに変数にしてしまう

int DefaultTimeoutSeconds = 30;
@Reviewer
固定値ならconstexprで定数化してください

改善例

inline constexpr int DefaultTimeoutSeconds = 30;

ケース2:const 漏れ(関数引数)

void Process(ApiRequestLog& request);
@Reviewer
参照専用ならconstを付けて意図を明示してください

改善例

void Process(const ApiRequestLog& request);

ケース3:const 漏れ(メンバ関数)

class Config {
public:
  int GetMaxRetryCount();
@Reviewer
状態変更しない関数はconst指定してください
};

改善例

class Config {
public:
  int GetMaxRetryCount() const;
};

7. PlantUMLで整理する設計責務

UML Diagram
  • 定数と可変の責務が分かれて整理されている
  • 依存も過剰にならず管理しやすい構造

8. CI統制:変更不能性レビューの支援ツール

clang-tidy 例

Checks: '-*,cppcoreguidelines-avoid-magic-numbers,readability-const-return-type'
  • マジックナンバー排除
  • const 漏れの指摘

include-what-you-use 活用

  • 定数ヘッダーの整理でインクルード最小化も支援できる

PR文化としても統制

  • 「constは設計意図を表す」文化をレビュー文化にする

9. レビュー観点チェックリスト

観点 確認すること
定数化できるもの constexpr を積極的に利用しているか
実行時固定 const で正しく固定しているか
マジックナンバー排除 裸の数字が散らばっていないか
const-correctness 関数・引数・戻り値・メンバのconst漏れ確認
スコープ設計 グローバル/クラス内/関数内で整理できているか
ODR安全性 inline constexpr で多翻訳単位の安全性確保
CI統制 自動チェックで漏れなく検出できているか

10. まとめ

定数と変数の設計は、実は
「誰がいつ責任を持って値を変更できるのか?」 を整理している作業でもあります。

レビューアーは「constを付けましょう」ではなく
「そもそも誰が管理する値なのか?」
という設計の背景を読み取る視点を持つことがとても重要です。

こうした読み取りができると、自然と保守性も高くなり、設計としても安定します。