1 分

ロバート・C・マーティンのClean Codeに学ぶ、チームの高速化

ロバート・C・マーティンのClean Codeの考え方を解説:適切な命名、明確な境界、日々の規律が保守性を高め、チームの開発速度を上げる方法を実践的に紹介します。

ロバート・C・マーティンのClean Codeに学ぶ、チームの高速化

なぜClean Codeは現代のチームでも重要なのか

ロバート・C・マーティン—通称「Uncle Bob」—は、Clean Code運動をこういう単純な前提で広めました:コードは次にそれを変更する人のために書くべきだ(多くの場合、その次の人は3週間後の自分だ)。

保守性とチームの速度(平易な言葉で)

保守性とは、チームがコードを理解し、安全に変更し、関連しない部分を壊さずに変更を出荷できるか、という能力です。小さな編集ごとにリスクを感じるなら、保守性は低いと言えます。

**チームの速度(ベロシティ)**は、チームが継続的に有用な改善を届ける能力です。これは「速くタイピングする」ことではなく、アイデアから動くソフトウェアへの移行を繰り返し短時間で行え、後で自分たちを遅らせるような負債を積み上げないことを意味します。

なぜコード品質はチーム全体の課題なのか

Clean Codeは個々の開発者の好みの問題ではありません。共有された作業環境です。散らかったモジュールは、それを書いた人だけを苛立たせるわけではなく、レビュー時間を増やし、オンボーディングを難しくし、診断に時間のかかるバグを生み、全員が慎重に動かざるを得なくします。

複数人が同じコードベースに関わるとき、明確さは調整の道具になります。目標は「美しいコード」ではなく、予測可能な変更です:チームの誰でも更新でき、影響範囲を理解し、自信を持ってマージできること。

完璧主義ではなく実践的な習慣

Clean Codeを純粋さの試験にしてはいけません。現代のチームは、実際の締め切りの下で効果が出るガイドラインが必要です。これは摩擦を減らす習慣のセットだと考えてください—小さな選択が複利的に高速なデリバリに寄与します。

この記事の残りでは、保守性とベロシティを直接改善する三つの領域に焦点を当てます:

  • 命名:意味を明らかにして、意図の解読時間を減らす。
  • 境界:責務を切り分け、変更が波及しないようにする。
  • 規律:レビュー、テスト、リファクタリングといった一貫した習慣でコードベースを安定させる。

Clean Codeの核心:変更に最適化する

Clean Codeは主に美学や個人の好みの問題ではありません。その核心は実用的です:コードを読みやすく、推論しやすく、したがって変更しやすくすること。

チームが苦労するのは新しいコードを書けないからではなく、既存のコードを安全に変更できないからです。要求は変わり、エッジケースは現れ、締め切りはエンジニアが「システムを再学習する」ために止まってはくれません。

クリアはクレバーに勝る

“クレバー”なコードはしばしば作者の瞬間的な満足を最適化します:詰め込まれたロジック、予想外の近道、巧妙に見える抽象化—しかし他人が編集する場面では厄介になります。

“クリア”なコードは次の変更を最適化します。明快な制御フロー、明示的な意図、なぜその機能が存在するかを説明する名前を重視します。目的はすべての複雑さを取り除くことではなく、複雑さを適切な場所に置き、可視化することです。

混乱のコストは測定可能

理解しにくいコードはチームに繰り返しコストを課します:

  • 納品が遅くなる:読む、追跡する、二重チェックする時間が増える。
  • バグが増える:誤解により不適切な修正や不完全な変更が行われる。
  • 作り直しが増える:その領域に触るのがリスキーだからといって回避策を実装し、技術的負債が増える。

だからこそClean Codeはチームのベロシティと直結します:混乱を減らせば躊躇も減ります。

原則は戒律ではない

Clean Codeは妥協の集合であり厳格なルールではありません。時には少し長めの関数の方が分かりやすいこともありますし、パフォーマンス制約があれば多少「見た目がよくない」アプローチが正当化されることもあります。本質は同じです:将来の変更を安全に、局所的に、理解しやすく保つ選択を優先すること。

命名:読みやすく保守しやすいコードへの最短経路

変更しやすいコードにしたければ、まず名前から始めてください。良い名前は読者が行う「メンタル翻訳」の量を減らし、振る舞いそのものに集中させます。

良い名前が伝えるべきこと

有用な名前は情報を運びます:

  • 意図:そのものが何を表すか、何をするか(実装方法でなく)
  • スコープ:単一値か集合か、キャッシュかリクエストか、ドラフトか
  • 単位と形式Cents vs DollarsUtc vs ローカル時間、Bytes vs Kb、文字列かパース済みオブジェクトか
  • 制約:税金を含むか、割引済みか、検証済みか、最大値か

これらが欠けると、読み手は質問しなければならないか、最悪推測することになります。

曖昧な名前 vs 明確な名前(例)

曖昧な名前は決定を隠します:

  • data, info, tmp, value, result
  • list, items, map(文脈なし)

明確な名前は文脈を運び追問を減らします:

  • invoiceTotalCents(単位+ドメイン)
  • discountPercent(形式+意味)
  • validatedEmailAddress(制約)
  • customerIdsToDeactivate(スコープ+意図)
  • expiresAtUtc(タイムゾーン)

小さなリネームでもバグを防げます:timeoutは曖昧ですが、timeoutMsなら明確です。

一貫性:プロダクト用語に合わせる

チームは、コードがチケット、UI文言、カスタマーサポートで使われている言葉と同じ単語を使うと速く動けます。プロダクトが「subscription」と言っているなら、あるモジュールでそれをplanmembershipと呼ぶのは避けてください(本当に異なる概念でない限り)。

一貫性はまた、一つの用語を選び、それを維持することも意味します:customerclientinvoicebillcanceldeactivate。言葉が揺れると意味も揺れます。

命名は協調でありスタイルではない

良い名前は小さなドキュメントのように働きます。Slackでの「tmpには何が入ってたっけ?」という質問を減らし、レビューの手戻りを減らし、エンジニア、QA、プロダクト間の誤解を防ぎます。

命名の簡単なチェックリスト

コミット前に次を自問してください:

  • 新しいチームメンバーが他のファイルを開かずに推測できるか?
  • 必要なら単位/タイムゾーン/形式を明示しているか?
  • プロダクト用語に合わせているか?
  • dataのような“コンテナ語”をドメインが明確でない限り避けているか?
  • ブールは読みやすいか:isActivehasAccessshouldRetry

名前を正直に保つ:時間経過での“名前ドリフト”を防ぐ

良い名前は約束です:次の読者にコードが何をするかを伝えます。しかし問題は、コードの方が名前より早く変わることです。短期的な修正や「とりあえず出す」瞬間が積み重なると、validateUser() が検証・プロビジョニング・分析ログを同時に行うようになることがあります。見た目はきれいでも、名前は誤解を招くようになります——そして誤解を招く名前は時間を食います。

なぜ名前は「今」の振る舞いを反映すべきか

Clean Codeは一度完璧な名前を選べば終わりという話ではありません。名前を現実と合わせていくことが重要です。名前が過去の動作を記述していると、将来の読み手は実装から真実を逆算しなければならず、認知負荷が増え、レビューが遅くなり、小さな変更がリスキーになります。

実チームで名前がドリフトする理由

名前ドリフトはめったに悪意では起きません。通常は:

  • 手早い修正:意図を見直さずに振る舞いをパッチする
  • 機能の拡張:既存関数に都合よく責務を一つ追加する
  • コピペ:コードを複製してロジックは変えるが名前は残す

名前を正確に保つ軽量な方法

命名委員会は必要ありません。次のような習慣で十分効果が出ます:

  • 関数が新しい責務を得たら、名前を変える分割する
  • レビューのチェックリストに「名前はまだ振る舞いを表しているか?」を入れる(簡単にチェックでき、多くを防げます)
  • 「実はこれ…」というコメントを書いているなら、それは多くの場合名前を変えるサインです

“触るときに名前を直す”ルール

バグ修正、リファクタ、機能追加といった小さな編集の際に、近くの誤解を招く名前を30秒で直す習慣をつけてください。この習慣がドリフトの蓄積を防ぎ、日々の作業で可読性が少しずつ向上します。

境界:責務を分けて波及を減らす

Clean Codeは単にメソッドをきれいにする話だけではなく、変更が局所に留まるように明確な境界を引くことです。境界はモジュール、レイヤー、サービス、API、あるいはクラス内部の責任分配に現れます。

関心の分離(キッチンの例え)

調理場をステーションに分けているキッチンを想像してください:下ごしらえ、グリル、盛り付け、食器洗い。それぞれ明確な仕事、道具、入出力があり、グリルが「今回は特別に」食器を洗い始めると、道具が混ざり、行列ができ、壊れたときに誰が責任を取るのか曖昧になります。

ソフトウェアも同様です。境界が明確なら、ビジネスロジック(グリル)を変えても、データアクセス(食器洗い)やUI/APIのフォーマット(盛り付け)を再編する必要はありません。

境界が曖昧だとチームはどう遅くなるか

境界が不明確だと小さな変更が複数箇所の編集、追加テスト、長いレビューや意図しないバグのリスクを生みます。チームは慎重になり、どの変更も「壊すかもしれない」と躊躇するようになります。

よくある境界の匂い:

  • 責務の混在:あるモジュールが価格計算とDB書き込みを両方行う
  • レイヤー横断の近道:UIコードが直接DBを参照する
  • 漏れた抽象化:サービスが内部のテーブルやORMオブジェクトをAPIとして晒す
  • ヘルパーが時間とともに無関係な振る舞いを溜め込む

良い境界が日常でどう感じられるか

良い境界があると、チケットが予測可能になります。価格ルールの変更は主に価格コンポーネントだけに触れ、テストが素早く線を引いてくれます。コードレビューはシンプルになり(「これはコントローラではなくドメイン層にあるべき」)、デバッグも速くなります。各部品に「探すべき場所」が一つだけあるからです。

小さな関数と明確な意図:変更を安全にする

クリーンなスタート、迅速な変更
名前、境界、意図を最初から明確に保ちつつ、チャットで新しいアプリを作成できます。

小さく焦点を絞った関数は、頭の中で保持すべき文脈を小さくします。関数が一つの明確な仕事を持っていれば、少ない入力でテストでき、他所で再利用でき、失敗を理解するのに迷路を辿る必要がありません。

“一つのことをする”(具体例付き)

例えば processOrder() という関数が、住所検証、税計算、割引適用、カード課金、メール送信、監査ログ書き込みを全部やっているとします。それは「受注処理」ではなく、意思決定が五つと副作用が三つ束になっています。

より良いアプローチは意図を分けることです:

function processOrder(order) {
  validate(order)
  const priced = price(order)
  const receipt = charge(priced)
  sendConfirmation(receipt)
  return receipt
}

各ヘルパーは個別にテストや再利用が可能で、トップレベルの関数は短い物語のように読めます。

長い関数が危険な理由

長い関数は決定点やエッジケースを隠します。ある“国際住所”用の if が税や配送、メール文言に影響を与えていても、それが80行先に埋もれていれば気付きにくいのです。

実践的なリファクタ手順

小さく始めてください:

  • 関数抽出:まとまったブロックを calculateTax()formatEmail() に移す
  • 名前変更:戻り値や目的を説明する名前に変える(applyDiscounts vs doDiscountStuff
  • 重複除去:二つの分岐で同じ処理があれば共通のヘルパーにする

ガードレール(過剰分割を避ける)

小さいことは目的ではありません。1行だけのラッパーを大量に作り、読者を5つのファイルにジャンプさせるようなら、可読性を犠牲にしています。短く、意味があり、局所的に理解できる関数を目指してください。

副作用の管理:驚きを減らしデバッグを容易にする

副作用とは、関数が戻り値以外に行う変更のことです。期待した答えを返すはずのヘルパーが、こっそり何かを書き換えると驚きが生まれます。

副作用自体が常に悪いわけではありませんが、隠れた副作用が問題です。呼び出し元を驚かせると、単純な変更が長いデバッグに発展します。

なぜ副作用はチームを遅らせるのか

隠れた変更は振る舞いを予測不能にします。あるバグがアプリの一部に現れても、原因は別の便利なヘルパーにあるかもしれません。その不確かさがベロシティを殺します。さらに、DBに書き込んだりグローバルを触る関数はテストのセットアップ/クリーンアップが必要になり、テストが壊れる理由が機能と無関係になりがちです。

驚きを減らすパターン

入力と出力が明確な関数を好みます。外側の世界を変える必要があるなら、それを明示してください:

  • 依存性(logger、repository、clock)を渡し、グローバルを避ける
  • 「計算」と「実行」を分ける:一つは計算、別の関数が書き込みを行う
  • 副作用は正直に名前を付ける(例:saveUser() vs getUser()

よくある落とし穴は、低レベルのヘルパー内でのログ出力、共有設定オブジェクトの変更、フォーマットや検証と見せかけたDB書き込みです。

レビューの簡単なチェックリスト

レビュー時に一つの質問を投げてください:「戻り値以外に何が変わるか?」

続けて:引数を変えるか?グローバルを触るか?ディスク/ネットワークに書くか?バックグラウンドジョブを起動するか?もしあるなら、その副作用を明示するか、より良い境界に移せないかを考えましょう。

規律:デリバリ速度への複利効果

保守しやすいモバイルアプリを始める
チームが拡張しやすいクリーンな構造のFlutterアプリを立ち上げます。

Clean Codeは単なるスタイル嗜好ではなく規律です:コードベースを予測可能に保つ反復可能な習慣。リスクの高い変更前のテスト、小さなリファクタ、混乱を防ぐ軽量ドキュメント、問題を早期に発見するレビューなどが含まれます。

今の速さ vs 次の月の速さ

チームはしばしば今すぐ「速く」進むためにこれらの習慣を省きます。しかしその速度は未来から借りていることが多い。請求書は不安定なリリース、驚きのリグレッション、単純な変更が連鎖して大騒ぎになる形で届きます。

規律は小さく一貫したコストと引き換えに信頼性をもたらします:緊急事態や突発の修正が減り、リリースを安定させるためにチーム全体が作業を止める必要が減ります。月単位で見ると、その信頼性が実際のスループットになります。

日々の習慣が複利的に効く

いくつかのシンプルな行動で大きな効果が出ます:

  • バグを修正したらテストを追加/更新する(再発防止)
  • 触った領域は認知しているうちにリファクタする(名前変更、関数抽出、重複除去)
  • 変更を小さくしレビューしやすくする(短命ブランチ、明確なPR説明)
  • コードレビューを共同所有として扱う:「次の人が理解できるか?」を問う

“きれいにする時間はない”という反論

その反論は瞬間的には正しいことが多く、長期的には高くつきます。実用的な妥協は適用範囲です:大規模な掃除を予定するのではなく、日常の作業の端で規律を適用すること。数週間で小さな積み重ねが技術的負債を減らし、再構築なしに速度を上げます。

テスト:境界を守りリファクタを安全にする保険

テストは単にバグ検出の手段ではなく、コードが他の部分に約束する振る舞い(境界)を守る手段です。内部を分割したり名前を変えたりしたとき、良いテストは契約を壊していないことを教えてくれます。

早いフィードバックはあとでの修正より優れる

変更直後にテストが赤になるのは診断が安価です:何を触ったかをまだ覚えています。QAや本番で数日後に見つかるバグと比べると、追跡が容易で安全に修正できます。早いフィードバックはリファクタリングをギャンブルではなく日常に変えます。

時間が限られるときにまず何をテストするか

自由を与えてくれるカバレッジから始めます:

  • 重要な振る舞い:お金に関わるフロー、データ保護、ユーザーを止めるフロー
  • 厄介なロジック:エッジケース、パース、タイムゾーン、丸め、権限
  • よく壊れる箇所:不安定な連携、リトライルール

実用的なヒューリスティック:もしそのバグが高コストなら、それを検出できるテストを書いてください。

テストは読みやすいドキュメントにする

きれいなテストは変更を促進します。次を心がけてください:

  • 意図を表す名前:rejects_expired_token() は要件のように読める
  • トリッキーなヘルパーより明確なセットアップを好む。ヘルパーが意味を隠すなら逆効果
  • 実装の内部ではなく結果をアサートする。これにより実装を自由に書き換えられる

変更を遅らせる脆いテストを避ける

テストは今日の構造に縛り付けると税になる:過度なモック、プライベートな詳細のアサーション、振る舞いだけを検証したいのにUIの正確な文言に依存するケースなど。ノイズで失敗するテストは無視されがちです。意味のあるときだけ赤になるテストを目指しましょう。

リファクタリング習慣:小さなステップで負債を管理する

リファクタリングはClean Codeで最も実用的な教訓の一つです:振る舞いを変えずにコードの構造を改善すること。ソフトが何をするかではなく、次にどう安全に変えられるかを改善します。簡単な心構えはボーイスカウトのルール:見つけたコードは少しだけきれいにして去る、です。全てを磨く必要はありません。次の人(多くの場合未来の自分)のために摩擦を減らす小さな改善を積み重ねましょう。

すぐ効く小さな安全なリファクタ

低リスクでレビューしやすいリファクタが最も効果的です。よく効く例:

  • 要件進化後に変わった意味に合わせて変数・関数・クラスの名前を変更する
  • 長い関数のまとまりをメソッド抽出する
  • 否定を減らす、重複を潰す、よく名付けられたヘルパーを導入して条件分岐を簡素化する

これらは小さい変更ですが、意図を明確にし、デバッグを短くし将来の編集を速くします。

いつリファクタするか(デリバリを妨げないために)

リファクタは実作業に付随するときに最もうまく機能します:

  • 機能追加の前:新しいコードが自然に収まるようパスを整える
  • バグ修正の後:弱点が見つかったら同じクラスのバグが戻らないよう改善する

止めるべきとき

リファクタは無限の掃除の口実ではありません。明確でテスト可能な目標のない**書き直し(rewrite)**になりそうなら一旦止めてください。小さくレビュー可能なステップに分けられないなら、分割してマイルストーン化するか、先送りにしましょう。

コードレビューと規約:原則をチームの習慣に落とし込む

より明確なバックエンドを構築
永続化とドメインロジックを分離した明確なAPIを備えた、フォーカスしたGoサービスを生成できます。

Clean Codeがベロシティを改善するには、チームの反射になる必要があります。コードレビューは命名、境界、小さな関数といった原則を共有期待に変換する場です。

レビューの目的

良いレビューは次を最適化します:

  • 共有理解:「LGTM」以上に、チーム全体が何が変わりなぜ変わったかを理解すること
  • 一貫性:命名や構造、慣習がコードベース全体で馴染むこと
  • 境界チェック:責務が漏れていないか
  • リスク管理:副作用、エッジケース、ロールアウトの懸念を早めに洗い出す

軽量レビューのテンプレート

再利用可能なチェックリストを使えば承認が早くなり無駄な往復が減ります:

  1. 意図:この変更はどの問題を解くか?設計はシンプルか?
  2. 可読性:名前は具体的で正直か?巧妙なコードがないか?
  3. 境界:責務は正しい場所にあるか(UI/サービス/ドメイン/データ)?
  4. テスト:何が動作を保証しているか?壊れたら何が壊れるか?
  5. リスク:パフォーマンス、セキュリティ、マイグレーション、後方互換性
  6. フォローアップ:意図的に先送りした負債は何か(チケットを貼る)

議論を減らす規約

命名規則、フォルダ構成、エラー処理パターンなどを書面化しておけば「私はこうしたい」ではなく「我々はこうする」と示せます。これによりレビューが速く、個人的な対立も少なくなります。

親切さと明快さ

コードを批評し、人を批評しないこと。判断より質問と観察を優先しましょう:

  • process()calculateInvoiceTotals() にできませんか?戻り値に合っていません」
  • 「この関数は永続化境界を横切っています—リポジトリがこのクエリを持つべきでは?」

コメント:有用なものとノイズ

良いコメントの例:

// Why: rounding must match the payment provider’s rules (see PAY-142).

ノイズなコメントの例:

// increment i

コメントはなぜを書き、コード自体が言っている何をは繰り返さないことを目指してください。

Dogmaなしで速度を改善するためのClean Code適用法

Clean Codeは変更を容易にするなら役立ちます。導入の実用的な方法は実験として扱うことです:いくつかの行動に合意し、結果を測り、摩擦を明確に減らすものを残す。

AI支援の開発が増える今でも、この考え方はより重要です。LLMでスキャフォールディングを生成する場合でも、Koder.aiのようなビブコーディングワークフローでも同じ原則が当てはまります:明確な名前、明示的な境界、規律あるリファクタリングが高速な反復をスパゲッティ化から守ります。ツールは出力を加速しますが、Clean Codeの習慣が制御を保持します。

摩擦を測ってベロシティを測る

スタイルを議論する代わりに、遅延と相関するシグナルを観察してください:

  • PRサイクルタイム:PRを開いてからマージされるまでの時間(レビュー待ち時間を含む)
  • 欠陥率:リリースごとのQA/本番で見つかるバグ数
  • オンボーディング時間:新メンバーが安全に変更を出せるまでの時間
  • 作り直し比率:取り消しや再オープン、修正の割合

繰り返し現れる痛みを軽量の“摩擦ログ”で追う

週に一度、共有ノートに10分だけ繰り返し起きている問題を記録してください:

  • 「Xの実装箇所が見つけにくい」
  • 「関係ない変更でテストが壊れる」
  • 「このモジュールは変更理由が多すぎる」

時間が経てばパターンが見えます。それが次に効果を発揮するClean Code習慣を教えてくれます。

小さなチーム合意を作る

簡潔で実行可能に:

  • 命名規則:意図を明らかにする名前を優先、data/manager/process のような曖昧語は禁止(ドメインが明確な場合を除く)
  • 境界ルール:1モジュール=1責務。永続化、ビジネスルール、フォーマットを混ぜない
  • テストの最低条件:バグ修正はテストを追加、変更は適切なレベルのテストを添付

30日ローンチプラン(週ごとに1つの習慣)

  • Week 1 — 命名:触る最悪の命名をリネーム。PRに「名前はまだ合っているか?」を必須に
  • Week 2 — 境界:1つの依存シームを抜き出す(例:外部APIをインターフェースでラップ)
  • Week 3 — 副作用:1つのフローをより予測可能にする(戻り値を優先、隠れたミューテーションを無くす)
  • Week 4 — テスト付きリファクタ:ホットスポットのファイルを小さなPRで改善する

各週の終わりに指標を見直し、何を残すかを判断してください。

クイックチェックリスト

  • 新人が変更箇所を2分以内に見つけられるか?
  • 最後の編集後に名前は振る舞いと一致しているか?
  • ビジネスロジックとIOの間に明確な境界があるか?
  • ある部分を変えて他を5つも触る必要がないか?
  • このPRは将来の作業を減らす(または増やさない)か?

よくある質問

Why does Clean Code still matter for modern software teams?

Clean Codeは、将来の変更を安全かつ迅速にするために重要です。コードが明確であれば、チームメンバーは意図を読み解く時間が減り、レビューが早まり、バグの診断が簡単になり、変更が連鎖的に壊れる可能性が減ります。

実務的には、Clean Codeは保守性を守る手段であり、それが継続的な**チームの速度(ベロシティ)**を支えます。

What is maintainability in plain language?

保守性とは、チームがコードを理解し変更し、そして他の部分を壊さずにデプロイできるかどうか、ということです。

簡単なチェック:小さな修正がリスクを伴ったり、手作業の確認が大量に必要だったり、特定の一人しかその領域を触れないような状態なら、保守性は低いと言えます。

What does “team velocity” mean (and what doesn’t it mean)?

チームのベロシティは、チームが継続的に役立つ改善を届けられる信頼性のある能力のことです。

これは単なるタイピング速度ではありません—躊躇ややり直しを減らして、アイデア → PR → リリースを繰り返し行えることを意味します。明確なコード、安定したテスト、良い境界があれば、同じ流れを繰り返しやすくなります。

How do I choose better variable and function names quickly?

名前に、読者が推測しなければならない情報を持たせることから始めます:

  • 意図:何をする/何を表すか(実装方法ではなく)
  • スコープ:単一値か集合か、キャッシュかリクエストか
  • 単位/形式timeoutMstotalCentsexpiresAtUtc のように明記
  • 制約validatedEmailAddressdiscountPercent のように挙げる

もし名前のために他のファイルを3つ開かなければならないなら、それはおそらく曖昧です。

What is “name drift,” and how do we prevent it?

名前のドリフトは、振る舞いが変わっても名前が変わらないときに起きます(例:validateUser() が検証に加えてプロビジョニングやログ出力も行うようになる)。

実践的な対処法:

  • 新しい責務が増えたら名前を変える分割する
  • レビュー項目に「名前はまだ振る舞いを表しているか?」を追加する
  • 触るときに名前を直す”習慣:近くを編集する際に、最も誤解を招く名前を30秒で直す
What does it mean to have “good boundaries” in a codebase?

境界とは、責務を分ける線(モジュール、レイヤー、サービス、API、あるいはクラス内部の責任分担)です。境界があると、変更は局所化されます。

典型的な境界の臭い(問題の兆候):

  • 1つのモジュールが価格計算とデータベース書き込みを両方行っている
  • UIコードが「パフォーマンスのため」に直接DBを参照している
  • サービスが内部のテーブルやORMオブジェクトを公開APIとして晒している

良い境界があると、どこを変えれば良いかが明確になり、変更時の横展開が減ります。

Should we always break code into small functions?

読み手が保持すべきコンテキスト量を減らしてくれるなら、小さく焦点の絞れた関数を優先します。

実践パターン:

  • トップレベルの関数は読みやすい「物語」のようにする
  • 一貫した塊はヘルパーに抽出する(calculateTax()applyDiscounts() など)
  • ファイルをまたぐために読者を振り回すような過剰な分割は避ける

分割によって意図が明確になりテストが簡単になるなら、通常はその価値があります。

How can we manage side effects so debugging is easier?

副作用とは、戻り値以外に関数が行う変更(引数の変更、DB書き込み、グローバルの変更、ジョブの発火など)です。

驚きになるような隠れた副作用が問題です。呼び出し側が予想しない変更はデバッグを長引かせ、予測不能にします。

副作用を管理する方法:

  • 命名で副作用を明示する(saveUser()getUser() を区別する)
  • 依存性(logger/repository/clock)を引数で渡し、グローバルを避ける
  • 「計算」と「遂行」を分ける(まず計算し、後で書き込み/発火する)

レビュー時には「戻り値以外に何が変わるか?」を問う習慣を付けてください。

What should we test first to support Clean Code and safe refactoring?

テストは単にバグを見つけるためだけではなく、境界を守り、リファクタリングの安全網を提供します。内部を変えたときに、他所との契約(public behavior)が壊れていないかを確認してくれます。

時間が限られているときにまずテストすべき対象:

  • 重要な振る舞い(収益に関わる処理、データ保護、ユーザーを止める処理)
  • ややこしいロジック(タイムゾーン、丸め処理、パース、権限)
  • 知られている失敗モード(不安定な外部連携、リトライ)

テストは実行可能なドキュメントとして可読性を重視し、結果(アウトカム)を検証するように書きましょう。

How do code reviews and standards actually improve velocity?

コードレビューは原則をチームの反射に変える場です。個人の好みではなく共有期待にすることで、ベロシティが上がります。

軽量なレビューテンプレート:

  1. 意図:この変更は何のためか?設計はシンプルか?
  2. 可読性:名前は具体的で正直か?巧妙すぎないか?
  3. 境界:責務は適切なレイヤーにあるか?
  4. テスト:何で動作が保証されているか?
  5. リスク:パフォーマンス/セキュリティ/マイグレーション/互換性
  6. フォローアップ:意図的に先送りした負債はあるか(チケットへのリンク)

文書化されたスタンダードがあれば議論が減り、承認が早くなります。

Related posts