Files
playbook/brooks-lint/docs/guide.html
T
2026-06-27 16:04:15 +00:00

263 lines
78 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The Six Code Decay Risks — A Field Guide Grounded in Twelve Engineering Classics | brooks-lint</title>
<meta name="description" content="A practical field guide to the six ways production code decays — cognitive overload, change propagation, knowledge duplication, accidental complexity, dependency disorder, and domain model distortion — each mapped to the classic software engineering books that named it, with diagnostic questions, signature symptoms, and concrete remedies.">
<link rel="icon" type="image/svg+xml" href="logo.svg">
<link rel="canonical" href="https://hyhmrright.github.io/brooks-lint/guide.html">
<meta property="og:title" content="The Six Code Decay Risks — A Field Guide Grounded in Twelve Engineering Classics">
<meta property="og:description" content="How code decays, what each pattern is called in the literature, and how to fix it — synthesized from Brooks, Fowler, Martin, McConnell, Evans, Ousterhout and more.">
<meta property="og:type" content="article">
<meta property="og:url" content="https://hyhmrright.github.io/brooks-lint/guide.html">
<meta property="og:image" content="https://hyhmrright.github.io/brooks-lint/hero.png">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://hyhmrright.github.io/brooks-lint/hero.png">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "The Six Code Decay Risks — A Field Guide Grounded in Twelve Engineering Classics",
"description": "A practical field guide to the six ways production code decays, each mapped to the classic software engineering books that named it.",
"image": "https://hyhmrright.github.io/brooks-lint/hero.png",
"author": { "@type": "Person", "name": "hyhmrright" },
"publisher": { "@type": "Organization", "name": "brooks-lint" },
"mainEntityOfPage": "https://hyhmrright.github.io/brooks-lint/guide.html",
"keywords": "code smells, technical debt, refactoring, code review, dependency inversion, domain-driven design, cognitive complexity, software maintainability"
}
</script>
<style>
:root{
--paper:#f7f1e4; --card:#fffdf8; --ink:#2a2520; --ink-soft:#5c5347;
--rule:#e3d8c2; --rule-soft:#ece2cf; --blue:#2d4a7c; --green:#2b8a3e; --gold:#b07d2b; --red:#b23b3b;
--serif:"Iowan Old Style","Palatino Linotype",Palatino,"Book Antiqua",Georgia,serif;
--sans:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",Roboto,Helvetica,Arial,sans-serif;
--mono:"SF Mono","JetBrains Mono","Fira Code",Menlo,Consolas,monospace;
}
*{margin:0;padding:0;box-sizing:border-box;}
body{background:var(--paper);color:var(--ink);font-family:var(--sans);line-height:1.7;
background-image:radial-gradient(rgba(120,90,40,.04) 1px,transparent 1px);background-size:4px 4px;}
.wrap{max-width:820px;margin:0 auto;padding:48px 24px 80px;}
header.top{display:flex;align-items:center;gap:12px;margin-bottom:36px;}
header.top img{width:34px;height:34px;}
header.top a{font-family:var(--serif);font-size:20px;font-weight:700;color:var(--ink);text-decoration:none;}
nav.crumb{font-size:14px;color:var(--ink-soft);margin-left:auto;}
nav.crumb a{color:var(--blue);text-decoration:none;}
h1{font-family:var(--serif);font-size:36px;line-height:1.25;margin-bottom:14px;}
.lede{font-size:18px;color:var(--ink-soft);margin-bottom:10px;}
.meta{font-size:14px;color:var(--ink-soft);font-style:italic;margin-bottom:32px;padding-bottom:24px;border-bottom:1px solid var(--rule);}
h2{font-family:var(--serif);font-size:26px;margin:44px 0 8px;scroll-margin-top:20px;}
h2 .code{font-family:var(--mono);font-size:16px;color:var(--gold);font-weight:400;}
h3{font-family:var(--serif);font-size:19px;margin:24px 0 6px;color:var(--ink);}
p{margin:12px 0;}
ul{margin:10px 0 10px 22px;}
li{margin:5px 0;}
a{color:var(--blue);}
.toc{background:var(--card);border:1px solid var(--rule);border-radius:10px;padding:18px 22px;margin:28px 0;}
.toc h4{font-family:var(--serif);font-size:15px;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-soft);margin-bottom:10px;}
.toc ol{margin-left:20px;} .toc li{margin:4px 0;} .toc a{text-decoration:none;}
.risk{background:var(--card);border:1px solid var(--rule);border-left:4px solid var(--gold);border-radius:10px;padding:20px 24px;margin:22px 0;}
.q{font-style:italic;color:var(--blue);font-size:17px;margin:6px 0 14px;}
.src{font-size:14px;color:var(--ink-soft);margin-top:12px;}
.src b{color:var(--ink);}
table{border-collapse:collapse;width:100%;margin:18px 0;font-size:14.5px;}
th,td{border:1px solid var(--rule);padding:8px 11px;text-align:left;vertical-align:top;}
th{background:var(--rule-soft);font-family:var(--serif);}
.cta{background:#211d18;color:#f2e9d6;border-radius:12px;padding:26px 28px;margin:44px 0 0;text-align:center;}
.cta h3{font-family:var(--serif);color:#f7f1e4;font-size:22px;margin-bottom:8px;}
.cta p{color:#cdbf9f;margin:6px 0 16px;}
.cta code{font-family:var(--mono);background:#33291f;color:#e8c98a;padding:3px 8px;border-radius:5px;font-size:14px;}
.cta a{display:inline-block;margin-top:14px;background:var(--gold);color:#1c160f;font-weight:700;text-decoration:none;padding:10px 22px;border-radius:8px;}
footer{margin-top:56px;padding-top:24px;border-top:1px solid var(--rule);font-size:14px;color:var(--ink-soft);text-align:center;}
footer a{color:var(--blue);text-decoration:none;}
.lang-toggle{display:inline-flex;border:1px solid var(--rule);border-radius:999px;overflow:hidden;font-size:13px;background:var(--card);vertical-align:middle;}
.lang-toggle button{border:none;background:transparent;padding:4px 9px;cursor:pointer;color:var(--ink-soft);font-family:var(--sans);font-weight:600;font-size:12.5px;}
.lang-toggle button.active{background:var(--ink);color:var(--paper);}
</style>
</head>
<body>
<div class="wrap">
<header class="top">
<img src="logo.svg" alt="brooks-lint logo">
<a href="index.html">brooks-lint</a>
<nav class="crumb"><a href="index.html" data-en="Home" data-zh="首页" data-zhtw="首頁" data-ja="ホーム" data-ko="홈" data-es="Inicio">Home</a> · <a href="gallery.html" data-en="Gallery" data-zh="示例画廊" data-zhtw="範例展示" data-ja="ギャラリー" data-ko="갤러리" data-es="Galería">Gallery</a> · <a href="https://github.com/hyhmrright/brooks-lint">GitHub</a></nav>
<span class="lang-toggle">
<button data-set-lang="en">EN</button>
<button data-set-lang="zh"></button>
<button data-set-lang="zhtw"></button>
<button data-set-lang="ja"></button>
<button data-set-lang="ko"></button>
<button data-set-lang="es">ES</button>
</span>
</header>
<h1 data-en="The Six Code Decay Risks" data-zh="六大代码腐化风险" data-zhtw="六大程式碼衰退風險" data-ja="六つのコード劣化リスク" data-ko="여섯 가지 코드 쇠퇴 위험" data-es="Los seis riesgos de deterioro del código">The Six Code Decay Risks</h1>
<p class="lede" data-en="A field guide to the ways production code rots — and the classic engineering books that named each one fifty years before your codebase did it again." data-zh="一份关于生产代码如何腐化的实战指南——以及那些早在你的代码库重蹈覆辙五十年前就为每种腐化命名的经典工程著作。" data-zhtw="一份關於生產程式碼如何衰退的實戰指南——以及那些早在你的程式碼庫重蹈覆轍五十年前就為每種衰退命名的經典工程著作。" data-ja="本番コードが腐っていく道筋への実践的なフィールドガイド——そして、あなたのコードベースが再び同じ過ちを犯す五十年前に、それぞれを名付けた古典的なエンジニアリングの名著。" data-ko="프로덕션 코드가 썩어가는 방식에 대한 실전 가이드 — 그리고 당신의 코드베이스가 같은 일을 반복하기 오십 년 전에 각각을 명명한 고전 엔지니어링 명저들." data-es="Una guía de campo sobre las formas en que el código de producción se pudre — y los libros clásicos de ingeniería que nombraron cada una cincuenta años antes de que tu base de código lo repitiera.">A field guide to the ways production code rots — and the classic engineering books that named each one fifty years before your codebase did it again.</p>
<p class="meta" data-en="Most linters count lines and cyclomatic complexity. They measure the <em>surface</em>. Decay happens underneath: in how responsibilities tangle, how knowledge duplicates, how dependencies invert. These six patterns are a synthesis of twelve classic software engineering books, applied to modern code review." data-zh="多数 linter 只统计行数和圈复杂度。它们衡量的是<em>表面</em>。腐化发生在底层:在于职责如何纠缠、知识如何重复、依赖如何倒置。这六种模式是对十二本经典软件工程著作的综合,应用于现代代码评审。" data-zhtw="多數 linter 只統計行數和圈複雜度。它們衡量的是<em>表面</em>。衰退發生在底層:在於職責如何糾纏、知識如何重複、依賴如何倒置。這六種模式是對十二本經典軟體工程著作的綜合,應用於現代程式碼審查。" data-ja="ほとんどのリンターは行数とサイクロマティック複雑度を数えます。それらが測るのは<em>表面</em>です。劣化はその下で起こります——責務がどう絡まり、知識がどう重複し、依存がどう逆転するか。これら六つのパターンは、十二冊の古典的なソフトウェア工学の名著を統合し、現代のコードレビューに適用したものです。" data-ko="대부분의 린터는 줄 수와 순환 복잡도를 셉니다. 그것들은 <em>표면</em>을 측정합니다. 쇠퇴는 그 아래에서 일어납니다: 책임이 어떻게 엉키고, 지식이 어떻게 중복되며, 의존성이 어떻게 뒤집히는지에서. 이 여섯 가지 패턴은 열두 권의 고전 소프트웨어 공학 명저를 종합하여 현대 코드 리뷰에 적용한 것입니다." data-es="La mayoría de los linters cuentan líneas y complejidad ciclomática. Miden la <em>superficie</em>. El deterioro ocurre debajo: en cómo se enredan las responsabilidades, cómo se duplica el conocimiento, cómo se invierten las dependencias. Estos seis patrones son una síntesis de doce libros clásicos de ingeniería de software, aplicados a la revisión de código moderna.">Most linters count lines and cyclomatic complexity. They measure the <em>surface</em>. Decay happens underneath: in how responsibilities tangle, how knowledge duplicates, how dependencies invert. These six patterns are a synthesis of twelve classic software engineering books, applied to modern code review.</p>
<div class="toc">
<h4 data-en="The six risks" data-zh="六大风险" data-zhtw="六大風險" data-ja="六つのリスク" data-ko="여섯 가지 위험" data-es="Los seis riesgos">The six risks</h4>
<ol>
<li data-en="&lt;a href=&quot;#r1&quot;&gt;Cognitive Overload&lt;/a&gt; — how hard is this to understand?" data-zh="&lt;a href=&quot;#r1&quot;&gt;认知过载&lt;/a&gt; — 这有多难理解?" data-zhtw="&lt;a href=&quot;#r1&quot;&gt;認知過載&lt;/a&gt; — 這有多難理解?" data-ja="&lt;a href=&quot;#r1&quot;&gt;認知的過負荷&lt;/a&gt; — これはどれほど理解しにくいか?" data-ko="&lt;a href=&quot;#r1&quot;&gt;인지 과부하&lt;/a&gt; — 이것은 이해하기가 얼마나 어려운가?" data-es="&lt;a href=&quot;#r1&quot;&gt;Sobrecarga cognitiva&lt;/a&gt; — ¿qué tan difícil es entender esto?"><a href="#r1">Cognitive Overload</a> — how hard is this to understand?</li>
<li data-en="&lt;a href=&quot;#r2&quot;&gt;Change Propagation&lt;/a&gt; — what breaks when you touch one thing?" data-zh="&lt;a href=&quot;#r2&quot;&gt;变更扩散&lt;/a&gt; — 改动一处时会有什么跟着坏掉?" data-zhtw="&lt;a href=&quot;#r2&quot;&gt;變更擴散&lt;/a&gt; — 改動一處時會有什麼跟著壞掉?" data-ja="&lt;a href=&quot;#r2&quot;&gt;変更の波及&lt;/a&gt; — 一箇所を触ると何が壊れるか?" data-ko="&lt;a href=&quot;#r2&quot;&gt;변경 전파&lt;/a&gt; — 한 곳을 건드리면 무엇이 깨지는가?" data-es="&lt;a href=&quot;#r2&quot;&gt;Propagación de cambios&lt;/a&gt; — ¿qué se rompe cuando tocas una sola cosa?"><a href="#r2">Change Propagation</a> — what breaks when you touch one thing?</li>
<li data-en="&lt;a href=&quot;#r3&quot;&gt;Knowledge Duplication&lt;/a&gt; — is one decision expressed in many places?" data-zh="&lt;a href=&quot;#r3&quot;&gt;知识重复&lt;/a&gt; — 一个决策是否在多处表达?" data-zhtw="&lt;a href=&quot;#r3&quot;&gt;知識重複&lt;/a&gt; — 一個決策是否在多處表達?" data-ja="&lt;a href=&quot;#r3&quot;&gt;知識の重複&lt;/a&gt; — 一つの決定が多くの場所で表現されていないか?" data-ko="&lt;a href=&quot;#r3&quot;&gt;지식 중복&lt;/a&gt; — 하나의 결정이 여러 곳에 표현되어 있는가?" data-es="&lt;a href=&quot;#r3&quot;&gt;Duplicación de conocimiento&lt;/a&gt; — ¿una sola decisión se expresa en muchos lugares?"><a href="#r3">Knowledge Duplication</a> — is one decision expressed in many places?</li>
<li data-en="&lt;a href=&quot;#r4&quot;&gt;Accidental Complexity&lt;/a&gt; — is the code harder than the problem?" data-zh="&lt;a href=&quot;#r4&quot;&gt;偶发复杂度&lt;/a&gt; — 代码是否比问题本身更复杂?" data-zhtw="&lt;a href=&quot;#r4&quot;&gt;偶發複雜度&lt;/a&gt; — 程式碼是否比問題本身更複雜?" data-ja="&lt;a href=&quot;#r4&quot;&gt;偶有的複雑性&lt;/a&gt; — コードは問題そのものより難しくなっていないか?" data-ko="&lt;a href=&quot;#r4&quot;&gt;우발적 복잡성&lt;/a&gt; — 코드가 문제보다 더 어려운가?" data-es="&lt;a href=&quot;#r4&quot;&gt;Complejidad accidental&lt;/a&gt; — ¿el código es más difícil que el problema?"><a href="#r4">Accidental Complexity</a> — is the code harder than the problem?</li>
<li data-en="&lt;a href=&quot;#r5&quot;&gt;Dependency Disorder&lt;/a&gt; — do dependencies flow one way?" data-zh="&lt;a href=&quot;#r5&quot;&gt;依赖失序&lt;/a&gt; — 依赖是否朝一个方向流动?" data-zhtw="&lt;a href=&quot;#r5&quot;&gt;依賴失序&lt;/a&gt; — 依賴是否朝一個方向流動?" data-ja="&lt;a href=&quot;#r5&quot;&gt;依存関係の無秩序&lt;/a&gt; — 依存は一方向に流れているか?" data-ko="&lt;a href=&quot;#r5&quot;&gt;의존성 무질서&lt;/a&gt; — 의존성이 한 방향으로 흐르는가?" data-es="&lt;a href=&quot;#r5&quot;&gt;Desorden de dependencias&lt;/a&gt; — ¿las dependencias fluyen en una sola dirección?"><a href="#r5">Dependency Disorder</a> — do dependencies flow one way?</li>
<li data-en="&lt;a href=&quot;#r6&quot;&gt;Domain Model Distortion&lt;/a&gt; — does the code mean what the business means?" data-zh="&lt;a href=&quot;#r6&quot;&gt;领域模型失真&lt;/a&gt; — 代码表达的含义是否与业务一致?" data-zhtw="&lt;a href=&quot;#r6&quot;&gt;領域模型失真&lt;/a&gt; — 程式碼表達的含義是否與業務一致?" data-ja="&lt;a href=&quot;#r6&quot;&gt;ドメインモデルの歪み&lt;/a&gt; — コードはビジネスが意味するものを表しているか?" data-ko="&lt;a href=&quot;#r6&quot;&gt;도메인 모델 왜곡&lt;/a&gt; — 코드가 비즈니스가 의미하는 바를 뜻하는가?" data-es="&lt;a href=&quot;#r6&quot;&gt;Distorsión del modelo de dominio&lt;/a&gt; — ¿el código significa lo que el negocio significa?"><a href="#r6">Domain Model Distortion</a> — does the code mean what the business means?</li>
</ol>
</div>
<p data-en="Each risk below follows the same shape brooks-lint uses for every finding — the <strong>Iron Law</strong>: <em>Symptom → Source → Consequence → Remedy</em>. A symptom you can see in the diff, a source you can cite to a book, a consequence that explains why it matters, and a remedy you can actually apply." data-zh="下面每条风险都遵循 brooks-lint 用于每条结论的同一形式——<strong>铁律</strong><em>症状 → 根源 → 后果 → 修复</em>。一个你能在 diff 中看到的症状,一个你能引用到书的根源,一个解释其为何重要的后果,以及一个你真正能落地的修复。" data-zhtw="下面每條風險都遵循 brooks-lint 用於每條結論的同一形式——<strong>鐵律</strong><em>症狀 → 根源 → 後果 → 對策</em>。一個你能在 diff 中看到的症狀,一個你能引用到書的根源,一個解釋其為何重要的後果,以及一個你真正能落地的對策。" data-ja="以下の各リスクは、brooks-lint がすべての指摘で用いるのと同じ形——<strong>鉄の掟</strong><em>症状 → 根源 → 結果 → 対策</em>に従います。diff で見える症状、書籍に引用できる根源、なぜ重要かを説明する結果、そして実際に適用できる対策。" data-ko="아래의 각 위험은 brooks-lint가 모든 발견에 사용하는 동일한 형태——<strong>철칙</strong><em>증상 → 근원 → 결과 → 처방</em>을 따릅니다. diff에서 볼 수 있는 증상, 책에 인용할 수 있는 근원, 왜 중요한지 설명하는 결과, 그리고 실제로 적용할 수 있는 처방." data-es="Cada riesgo a continuación sigue la misma forma que brooks-lint usa para cada hallazgo — la <strong>Ley de Hierro</strong>: <em>Síntoma → Origen → Consecuencia → Remedio</em>. Un síntoma que puedes ver en el diff, un origen que puedes citar de un libro, una consecuencia que explica por qué importa, y un remedio que realmente puedes aplicar.">Each risk below follows the same shape brooks-lint uses for every finding — the <strong>Iron Law</strong>: <em>Symptom → Source → Consequence → Remedy</em>. A symptom you can see in the diff, a source you can cite to a book, a consequence that explains why it matters, and a remedy you can actually apply.</p>
<h2 id="r1"><span data-en="1 · Cognitive Overload" data-zh="1 · 认知过载" data-zhtw="1 · 認知過載" data-ja="1 · 認知的過負荷" data-ko="1 · 인지 과부하" data-es="1 · Sobrecarga cognitiva">1 · Cognitive Overload</span> <span class="code">R1</span></h2>
<div class="risk">
<p class="q" data-en="Diagnostic question: How much mental effort does a human need to understand this?" data-zh="诊断问题:理解这段代码,人需要付出多少脑力?" data-zhtw="診斷問題:理解這段程式碼,人需要付出多少腦力?" data-ja="診断的質問:これを理解するのに人はどれだけの精神的労力を要するか?" data-ko="진단 질문: 이것을 이해하는 데 사람은 얼마나 많은 정신적 노력이 필요한가?" data-es="Pregunta diagnóstica: ¿cuánto esfuerzo mental necesita una persona para entender esto?">Diagnostic question: How much mental effort does a human need to understand this?</p>
<p data-en="Working memory holds about four chunks at once. Code that exceeds that budget causes mistakes, invites avoidance, and blocks the very refactoring that would fix it." data-zh="工作记忆一次大约只能容纳四个组块。超出这一预算的代码会引发错误、令人回避,并阻碍本该修复它的重构。" data-zhtw="工作記憶一次大約只能容納四個組塊。超出這一預算的程式碼會引發錯誤、令人迴避,並阻礙本該修復它的重構。" data-ja="ワーキングメモリは一度に約四つのまとまりしか保持できません。その予算を超えるコードはミスを招き、敬遠され、それを直すはずのリファクタリングを妨げます。" data-ko="작업 기억은 한 번에 약 네 개의 덩어리만 담을 수 있습니다. 그 예산을 초과하는 코드는 실수를 유발하고, 회피를 부르며, 그것을 고칠 리팩터링 자체를 가로막습니다." data-es="La memoria de trabajo retiene unos cuatro fragmentos a la vez. El código que excede ese presupuesto provoca errores, invita a evitarlo y bloquea la propia refactorización que lo arreglaría.">Working memory holds about four chunks at once. Code that exceeds that budget causes mistakes, invites avoidance, and blocks the very refactoring that would fix it.</p>
<h3 data-en="Signature symptoms" data-zh="典型症状" data-zhtw="典型症狀" data-ja="典型的な症状" data-ko="대표적인 증상" data-es="Síntomas característicos">Signature symptoms</h3>
<ul>
<li data-en="Functions that mix multiple levels of abstraction in one body, or run past ~20 lines" data-zh="在一个函数体内混合多个抽象层级,或长度超过约 20 行的函数" data-zhtw="在一個函式體內混合多個抽象層級,或長度超過約 20 行的函式" data-ja="一つの本体に複数の抽象レベルが混在する、または約20行を超える関数" data-ko="한 본문에 여러 추상화 수준이 섞이거나, 약 20줄을 넘는 함수" data-es="Funciones que mezclan varios niveles de abstracción en un mismo cuerpo, o que superan las ~20 líneas">Functions that mix multiple levels of abstraction in one body, or run past ~20 lines</li>
<li data-en="Nesting deeper than three levels; boolean conditions with three or more clauses" data-zh="嵌套超过三层;带有三个或更多子句的布尔条件" data-zhtw="巢狀超過三層;帶有三個或更多子句的布林條件" data-ja="三段を超えるネスト、三つ以上の節を持つ真偽条件" data-ko="세 단계보다 깊은 중첩, 절이 셋 이상인 불리언 조건" data-es="Anidamiento de más de tres niveles; condiciones booleanas con tres o más cláusulas">Nesting deeper than three levels; boolean conditions with three or more clauses</li>
<li data-en="Long parameter lists, flag arguments, and &quot;train-wreck&quot; chains like <code>a.getB().getC().doD()</code>" data-zh="过长的参数列表、标志参数,以及像 <code>a.getB().getC().doD()</code> 这样的“火车失事”式链式调用" data-zhtw="過長的參數列表、旗標參數,以及像 <code>a.getB().getC().doD()</code> 這樣的「火車失事」式鏈式呼叫" data-ja="長い引数リスト、フラグ引数、そして <code>a.getB().getC().doD()</code> のような「列車事故」式の連鎖" data-ko="긴 매개변수 목록, 플래그 인자, 그리고 <code>a.getB().getC().doD()</code> 같은 「열차 전복」식 연쇄 호출" data-es="Listas de parámetros largas, argumentos de bandera y cadenas tipo «choque de tren» como <code>a.getB().getC().doD()</code>">Long parameter lists, flag arguments, and "train-wreck" chains like <code>a.getB().getC().doD()</code></li>
<li data-en="<strong>Primitive obsession</strong> — domain concepts smuggled through as <code>String</code>/<code>int</code> instead of purpose-built types" data-zh="<strong>基本类型偏执</strong> — 把领域概念用 <code>String</code>/<code>int</code> 这类基本类型偷偷传递,而非专门构建的类型" data-zhtw="<strong>基本型別偏執</strong> — 把領域概念用 <code>String</code>/<code>int</code> 這類基本型別偷偷傳遞,而非專門構建的型別" data-ja="<strong>基本型への執着</strong> — ドメイン概念を専用の型ではなく <code>String</code>/<code>int</code> として紛れ込ませる" data-ko="<strong>기본형 집착</strong> — 도메인 개념을 목적에 맞는 타입 대신 <code>String</code>/<code>int</code> 같은 기본형으로 몰래 전달" data-es="<strong>Obsesión por primitivos</strong> — conceptos de dominio colados como <code>String</code>/<code>int</code> en vez de tipos creados a propósito"><strong>Primitive obsession</strong> — domain concepts smuggled through as <code>String</code>/<code>int</code> instead of purpose-built types</li>
<li data-en="<strong>Shallow modules</strong> — an interface as complex as the functionality it hides" data-zh="<strong>浅模块</strong> — 接口与其所隐藏的功能一样复杂" data-zhtw="<strong>淺模組</strong> — 介面與其所隱藏的功能一樣複雜" data-ja="<strong>浅いモジュール</strong> — 隠している機能と同じくらい複雑なインターフェース" data-ko="<strong>얕은 모듈</strong> — 감추는 기능만큼이나 복잡한 인터페이스" data-es="<strong>Módulos superficiales</strong> — una interfaz tan compleja como la funcionalidad que oculta"><strong>Shallow modules</strong> — an interface as complex as the functionality it hides</li>
</ul>
<p class="src" data-en="<b>Sources:</b> Fowler, <em>Refactoring</em> (Long Method, Long Parameter List, Message Chains, Primitive Obsession) · McConnell, <em>Code Complete</em> (high-quality routines, the power of variable names) · Ousterhout, <em>A Philosophy of Software Design</em> (deep modules) · Evans, <em>Domain-Driven Design</em> (ubiquitous language)." data-zh="<b>根源:</b>Fowler<em>Refactoring</em>(过长函数、过长参数列表、消息链、基本类型偏执)· McConnell<em>Code Complete</em>(高质量子程序、变量命名的力量)· Ousterhout<em>A Philosophy of Software Design</em>(深模块)· Evans<em>Domain-Driven Design</em>(统一语言)。" data-zhtw="<b>根源:</b>Fowler<em>Refactoring</em>(過長函式、過長參數列表、訊息鏈、基本型別偏執)· McConnell<em>Code Complete</em>(高品質子程式、變數命名的力量)· Ousterhout<em>A Philosophy of Software Design</em>(深模組)· Evans<em>Domain-Driven Design</em>(統一語言)。" data-ja="<b>根源:</b>Fowler、<em>Refactoring</em>(長いメソッド、長い引数リスト、メッセージの連鎖、基本型への執着)· McConnell、<em>Code Complete</em>(高品質なルーチン、変数名の力)· Ousterhout、<em>A Philosophy of Software Design</em>(深いモジュール)· Evans、<em>Domain-Driven Design</em>(ユビキタス言語)。" data-ko="<b>근원:</b> Fowler, <em>Refactoring</em>(긴 메서드, 긴 매개변수 목록, 메시지 체인, 기본형 집착) · McConnell, <em>Code Complete</em>(고품질 루틴, 변수 이름의 힘) · Ousterhout, <em>A Philosophy of Software Design</em>(깊은 모듈) · Evans, <em>Domain-Driven Design</em>(유비쿼터스 언어)." data-es="<b>Fuentes:</b> Fowler, <em>Refactoring</em> (Método largo, Lista de parámetros larga, Cadenas de mensajes, Obsesión por primitivos) · McConnell, <em>Code Complete</em> (rutinas de alta calidad, el poder de los nombres de variables) · Ousterhout, <em>A Philosophy of Software Design</em> (módulos profundos) · Evans, <em>Domain-Driven Design</em> (lenguaje ubicuo)."><b>Sources:</b> Fowler, <em>Refactoring</em> (Long Method, Long Parameter List, Message Chains, Primitive Obsession) · McConnell, <em>Code Complete</em> (high-quality routines, the power of variable names) · Ousterhout, <em>A Philosophy of Software Design</em> (deep modules) · Evans, <em>Domain-Driven Design</em> (ubiquitous language).</p>
<h3 data-en="Remedy" data-zh="修复" data-zhtw="對策" data-ja="対策" data-ko="처방" data-es="Remedio">Remedy</h3>
<p data-en="Extract methods until each one operates at a single level of abstraction. Replace primitives with value types. Make modules <em>deep</em>: a simple interface over substantial functionality, not a thin wrapper." data-zh="不断提炼方法,直到每个方法都只在单一抽象层级上工作。用值类型替换基本类型。让模块变得<em>深</em>:在丰富的功能之上提供简单的接口,而不是一层薄薄的包装。" data-zhtw="不斷提煉方法,直到每個方法都只在單一抽象層級上工作。用值型別替換基本型別。讓模組變得<em>深</em>:在豐富的功能之上提供簡單的介面,而不是一層薄薄的包裝。" data-ja="各メソッドが単一の抽象レベルで動作するまでメソッドを抽出する。基本型を値型に置き換える。モジュールを<em>深く</em>する——薄いラッパーではなく、十分な機能の上にシンプルなインターフェースを。" data-ko="각 메서드가 단일 추상화 수준에서 작동할 때까지 메서드를 추출하라. 기본형을 값 타입으로 교체하라. 모듈을 <em>깊게</em> 만들어라: 얇은 래퍼가 아니라 충분한 기능 위의 단순한 인터페이스로." data-es="Extrae métodos hasta que cada uno opere en un solo nivel de abstracción. Reemplaza los primitivos por tipos de valor. Haz que los módulos sean <em>profundos</em>: una interfaz simple sobre una funcionalidad sustancial, no una envoltura delgada.">Extract methods until each one operates at a single level of abstraction. Replace primitives with value types. Make modules <em>deep</em>: a simple interface over substantial functionality, not a thin wrapper.</p>
</div>
<h2 id="r2"><span data-en="2 · Change Propagation" data-zh="2 · 变更扩散" data-zhtw="2 · 變更擴散" data-ja="2 · 変更の波及" data-ko="2 · 변경 전파" data-es="2 · Propagación de cambios">2 · Change Propagation</span> <span class="code">R2</span></h2>
<div class="risk">
<p class="q" data-en="Diagnostic question: How many unrelated things break when you change one thing?" data-zh="诊断问题:当你改动一处时,会有多少不相关的东西跟着坏掉?" data-zhtw="診斷問題:當你改動一處時,會有多少不相關的東西跟著壞掉?" data-ja="診断的質問:一つを変更したとき、無関係なものがいくつ壊れるか?" data-ko="진단 질문: 한 가지를 바꿀 때 무관한 것들이 얼마나 많이 깨지는가?" data-es="Pregunta diagnóstica: ¿cuántas cosas no relacionadas se rompen cuando cambias una sola cosa?">Diagnostic question: How many unrelated things break when you change one thing?</p>
<p data-en="This is the most expensive decay risk because it compounds: every future edit inherits the blast radius of the last one." data-zh="这是代价最高的腐化风险,因为它会复利累积:未来每一次修改都会继承上一次修改的波及范围。" data-zhtw="這是代價最高的衰退風險,因為它會複利累積:未來每一次修改都會繼承上一次修改的波及範圍。" data-ja="これは最もコストの高い劣化リスクです。なぜなら複利的に膨らむからです——将来のすべての編集が、前回の編集の影響範囲を引き継ぎます。" data-ko="이것은 가장 비용이 큰 쇠퇴 위험입니다. 복리처럼 누적되기 때문입니다: 미래의 모든 수정이 직전 수정의 폭발 반경을 물려받습니다." data-es="Este es el riesgo de deterioro más costoso porque se acumula: cada edición futura hereda el radio de impacto de la anterior.">This is the most expensive decay risk because it compounds: every future edit inherits the blast radius of the last one.</p>
<h3 data-en="Signature symptoms" data-zh="典型症状" data-zhtw="典型症狀" data-ja="典型的な症状" data-ko="대표적인 증상" data-es="Síntomas característicos">Signature symptoms</h3>
<ul>
<li data-en="Modifying one feature forces edits across more than three files in unrelated modules" data-zh="修改一个功能时被迫改动不相关模块中超过三个文件" data-zhtw="修改一個功能時被迫改動不相關模組中超過三個檔案" data-ja="一つの機能を変更すると、無関係なモジュールの三つを超えるファイルの編集を強いられる" data-ko="한 기능을 수정하면 무관한 모듈의 세 개가 넘는 파일을 고쳐야 한다" data-es="Modificar una funcionalidad obliga a editar más de tres archivos en módulos no relacionados">Modifying one feature forces edits across more than three files in unrelated modules</li>
<li data-en="One class changes for several different business reasons (Single Responsibility violation)" data-zh="一个类因多个不同的业务原因而改动(违反单一职责)" data-zhtw="一個類別因多個不同的業務原因而改動(違反單一職責)" data-ja="一つのクラスが複数の異なるビジネス上の理由で変更される(単一責任の違反)" data-ko="하나의 클래스가 여러 다른 비즈니스 이유로 변경된다(단일 책임 위반)" data-es="Una clase cambia por varias razones de negocio distintas (violación de Responsabilidad Única)">One class changes for several different business reasons (Single Responsibility violation)</li>
<li data-en="Shotgun surgery: a single conceptual change scattered across many small edits" data-zh="霰弹式修改:一个概念上的变更被分散成许多处小修改" data-zhtw="散彈式修改:一個概念上的變更被分散成許多處小修改" data-ja="ショットガン手術:一つの概念的な変更が多くの小さな編集に散らばる" data-ko="산탄총 수술: 하나의 개념적 변경이 여러 작은 수정으로 흩어진다" data-es="Cirugía de escopeta: un único cambio conceptual disperso en muchas ediciones pequeñas">Shotgun surgery: a single conceptual change scattered across many small edits</li>
</ul>
<p class="src" data-en="<b>Sources:</b> Fowler, <em>Refactoring</em> (Divergent Change, Shotgun Surgery) · Martin, <em>Clean Architecture</em> (Single Responsibility) · Hunt &amp; Thomas, <em>The Pragmatic Programmer</em> (orthogonality) · Winters et al., <em>Software Engineering at Google</em>." data-zh="<b>根源:</b>Fowler<em>Refactoring</em>(发散式变化、霰弹式修改)· Martin<em>Clean Architecture</em>(单一职责)· Hunt &amp; Thomas<em>The Pragmatic Programmer</em>(正交性)· Winters et al.<em>Software Engineering at Google</em>。" data-zhtw="<b>根源:</b>Fowler<em>Refactoring</em>(發散式變化、散彈式修改)· Martin<em>Clean Architecture</em>(單一職責)· Hunt &amp; Thomas<em>The Pragmatic Programmer</em>(正交性)· Winters et al.<em>Software Engineering at Google</em>。" data-ja="<b>根源:</b>Fowler、<em>Refactoring</em>(発散的変更、ショットガン手術)· Martin、<em>Clean Architecture</em>(単一責任)· Hunt &amp; Thomas、<em>The Pragmatic Programmer</em>(直交性)· Winters et al.、<em>Software Engineering at Google</em>。" data-ko="<b>근원:</b> Fowler, <em>Refactoring</em>(발산적 변경, 산탄총 수술) · Martin, <em>Clean Architecture</em>(단일 책임) · Hunt &amp; Thomas, <em>The Pragmatic Programmer</em>(직교성) · Winters et al., <em>Software Engineering at Google</em>." data-es="<b>Fuentes:</b> Fowler, <em>Refactoring</em> (Cambio divergente, Cirugía de escopeta) · Martin, <em>Clean Architecture</em> (Responsabilidad Única) · Hunt &amp; Thomas, <em>The Pragmatic Programmer</em> (ortogonalidad) · Winters et al., <em>Software Engineering at Google</em>."><b>Sources:</b> Fowler, <em>Refactoring</em> (Divergent Change, Shotgun Surgery) · Martin, <em>Clean Architecture</em> (Single Responsibility) · Hunt &amp; Thomas, <em>The Pragmatic Programmer</em> (orthogonality) · Winters et al., <em>Software Engineering at Google</em>.</p>
<h3 data-en="Remedy" data-zh="修复" data-zhtw="對策" data-ja="対策" data-ko="처방" data-es="Remedio">Remedy</h3>
<p data-en="Separate responsibilities into focused units and let a thin orchestrator call them. Aim for orthogonality — changing the loyalty formula should never risk breaking email notifications." data-zh="把职责拆分为聚焦的单元,让一个轻量的编排者去调用它们。追求正交性——改动积分公式绝不应有可能破坏邮件通知。" data-zhtw="把職責拆分為聚焦的單元,讓一個輕量的編排者去呼叫它們。追求正交性——改動積分公式絕不應有可能破壞郵件通知。" data-ja="責務を焦点を絞った単位に分け、薄いオーケストレーターにそれらを呼び出させる。直交性を目指す——ロイヤルティの計算式を変えることが、メール通知を壊す危険につながってはならない。" data-ko="책임을 집중된 단위로 분리하고 얇은 오케스트레이터가 그것들을 호출하게 하라. 직교성을 목표로 하라 — 적립 공식을 바꾸는 것이 이메일 알림을 깨뜨릴 위험이 되어선 안 된다." data-es="Separa las responsabilidades en unidades enfocadas y deja que un orquestador delgado las invoque. Busca la ortogonalidad — cambiar la fórmula de fidelización nunca debería arriesgar romper las notificaciones por correo.">Separate responsibilities into focused units and let a thin orchestrator call them. Aim for orthogonality — changing the loyalty formula should never risk breaking email notifications.</p>
</div>
<h2 id="r3"><span data-en="3 · Knowledge Duplication" data-zh="3 · 知识重复" data-zhtw="3 · 知識重複" data-ja="3 · 知識の重複" data-ko="3 · 지식 중복" data-es="3 · Duplicación de conocimiento">3 · Knowledge Duplication</span> <span class="code">R3</span></h2>
<div class="risk">
<p class="q" data-en="Diagnostic question: Is the same decision expressed in more than one place?" data-zh="诊断问题:同一个决策是否在不止一个地方被表达?" data-zhtw="診斷問題:同一個決策是否在不止一個地方被表達?" data-ja="診断的質問:同じ決定が複数の場所で表現されていないか?" data-ko="진단 질문: 같은 결정이 두 곳 이상에서 표현되고 있는가?" data-es="Pregunta diagnóstica: ¿la misma decisión se expresa en más de un lugar?">Diagnostic question: Is the same decision expressed in more than one place?</p>
<p data-en="DRY is about <em>knowledge</em>, not text. Two identical-looking blocks that encode different decisions are fine; one decision copied into three files is a latent bug waiting for the day someone updates two of them." data-zh="DRY 关乎的是<em>知识</em>,而非文本。两段看起来相同却编码了不同决策的代码块没有问题;而一个决策被复制到三个文件里,则是一个潜伏的 bug,只等某天有人只更新了其中两处。" data-zhtw="DRY 關乎的是<em>知識</em>,而非文字。兩段看起來相同卻編碼了不同決策的程式碼塊沒有問題;而一個決策被複製到三個檔案裡,則是一個潛伏的 bug,只等某天有人只更新了其中兩處。" data-ja="DRY は<em>知識</em>に関するものであって、テキストではありません。見た目が同じでも異なる決定を符号化している二つのブロックは問題ありません。一つの決定が三つのファイルにコピーされていれば、それは誰かがそのうち二つだけを更新する日を待つ潜在的なバグです。" data-ko="DRY는 텍스트가 아니라 <em>지식</em>에 관한 것입니다. 똑같아 보이지만 서로 다른 결정을 담은 두 블록은 괜찮습니다. 하나의 결정이 세 파일에 복사되어 있다면, 누군가 그중 둘만 갱신하는 날을 기다리는 잠재적 버그입니다." data-es="DRY trata sobre el <em>conocimiento</em>, no sobre el texto. Dos bloques de aspecto idéntico que codifican decisiones distintas están bien; una decisión copiada en tres archivos es un error latente que espera el día en que alguien actualice solo dos de ellos.">DRY is about <em>knowledge</em>, not text. Two identical-looking blocks that encode different decisions are fine; one decision copied into three files is a latent bug waiting for the day someone updates two of them.</p>
<h3 data-en="Signature symptoms" data-zh="典型症状" data-zhtw="典型症狀" data-ja="典型的な症状" data-ko="대표적인 증상" data-es="Síntomas característicos">Signature symptoms</h3>
<ul>
<li data-en="The same logic copy-pasted across files or functions" data-zh="同样的逻辑被复制粘贴到多个文件或函数中" data-zhtw="同樣的邏輯被複製貼上到多個檔案或函式中" data-ja="同じロジックがファイルや関数にコピー&amp;ペーストされている" data-ko="같은 로직이 여러 파일이나 함수에 복사·붙여넣기되어 있다" data-es="La misma lógica copiada y pegada entre archivos o funciones">The same logic copy-pasted across files or functions</li>
<li data-en="One concept named differently in different parts of the codebase" data-zh="同一个概念在代码库的不同部分有不同的命名" data-zhtw="同一個概念在程式碼庫的不同部分有不同的命名" data-ja="一つの概念がコードベースの異なる部分で異なる名前で呼ばれている" data-ko="하나의 개념이 코드베이스의 다른 부분에서 다르게 명명되어 있다" data-es="Un mismo concepto nombrado de forma distinta en diferentes partes de la base de código">One concept named differently in different parts of the codebase</li>
<li data-en="Business rules (tax rates, validation limits) hard-coded in multiple spots" data-zh="业务规则(税率、校验上限)被硬编码在多个位置" data-zhtw="業務規則(稅率、驗證上限)被硬編碼在多個位置" data-ja="ビジネスルール(税率、検証の上限値)が複数の箇所にハードコードされている" data-ko="비즈니스 규칙(세율, 검증 한도)이 여러 곳에 하드코딩되어 있다" data-es="Reglas de negocio (tasas de impuestos, límites de validación) codificadas a mano en varios sitios">Business rules (tax rates, validation limits) hard-coded in multiple spots</li>
</ul>
<p class="src" data-en="<b>Sources:</b> Hunt &amp; Thomas, <em>The Pragmatic Programmer</em> (DRY) · Fowler, <em>Refactoring</em> (Duplicated Code) · Evans, <em>Domain-Driven Design</em>." data-zh="<b>根源:</b>Hunt &amp; Thomas<em>The Pragmatic Programmer</em>DRY)· Fowler<em>Refactoring</em>(重复代码)· Evans<em>Domain-Driven Design</em>。" data-zhtw="<b>根源:</b>Hunt &amp; Thomas<em>The Pragmatic Programmer</em>DRY)· Fowler<em>Refactoring</em>(重複程式碼)· Evans<em>Domain-Driven Design</em>。" data-ja="<b>根源:</b>Hunt &amp; Thomas、<em>The Pragmatic Programmer</em>DRY)· Fowler、<em>Refactoring</em>(重複したコード)· Evans、<em>Domain-Driven Design</em>。" data-ko="<b>근원:</b> Hunt &amp; Thomas, <em>The Pragmatic Programmer</em>(DRY) · Fowler, <em>Refactoring</em>(중복 코드) · Evans, <em>Domain-Driven Design</em>." data-es="<b>Fuentes:</b> Hunt &amp; Thomas, <em>The Pragmatic Programmer</em> (DRY) · Fowler, <em>Refactoring</em> (Código duplicado) · Evans, <em>Domain-Driven Design</em>."><b>Sources:</b> Hunt &amp; Thomas, <em>The Pragmatic Programmer</em> (DRY) · Fowler, <em>Refactoring</em> (Duplicated Code) · Evans, <em>Domain-Driven Design</em>.</p>
<h3 data-en="Remedy" data-zh="修复" data-zhtw="對策" data-ja="対策" data-ko="처방" data-es="Remedio">Remedy</h3>
<p data-en="Give each decision a single authoritative home. Extract shared logic; unify vocabulary so one concept has one name everywhere." data-zh="为每个决策设立一个权威的归属地。提炼共享逻辑;统一词汇,让一个概念在任何地方都只有一个名字。" data-zhtw="為每個決策設立一個權威的歸屬地。提煉共享邏輯;統一詞彙,讓一個概念在任何地方都只有一個名字。" data-ja="各決定に唯一の権威ある住処を与える。共有ロジックを抽出し、語彙を統一して、一つの概念がどこでも一つの名前を持つようにする。" data-ko="각 결정에 단 하나의 권위 있는 거처를 부여하라. 공유 로직을 추출하고, 어휘를 통일해 하나의 개념이 어디서나 하나의 이름을 갖게 하라." data-es="Da a cada decisión un único hogar autoritativo. Extrae la lógica compartida; unifica el vocabulario para que un concepto tenga un solo nombre en todas partes.">Give each decision a single authoritative home. Extract shared logic; unify vocabulary so one concept has one name everywhere.</p>
</div>
<h2 id="r4"><span data-en="4 · Accidental Complexity" data-zh="4 · 偶发复杂度" data-zhtw="4 · 偶發複雜度" data-ja="4 · 偶有的複雑性" data-ko="4 · 우발적 복잡성" data-es="4 · Complejidad accidental">4 · Accidental Complexity</span> <span class="code">R4</span></h2>
<div class="risk">
<p class="q" data-en="Diagnostic question: Is the code more complex than the problem it solves?" data-zh="诊断问题:代码是否比它所解决的问题更复杂?" data-zhtw="診斷問題:程式碼是否比它所解決的問題更複雜?" data-ja="診断的質問:コードは、それが解く問題よりも複雑になっていないか?" data-ko="진단 질문: 코드가 해결하려는 문제보다 더 복잡한가?" data-es="Pregunta diagnóstica: ¿el código es más complejo que el problema que resuelve?">Diagnostic question: Is the code more complex than the problem it solves?</p>
<p data-en="Brooks distinguished <em>essential</em> complexity (inherent to the problem) from <em>accidental</em> complexity (introduced by our solution). The second kind is the only kind you can delete." data-zh="Brooks 区分了<em>本质</em>复杂度(问题本身固有的)与<em>偶发</em>复杂度(由我们的解决方案引入的)。后者才是你唯一能删除的那种。" data-zhtw="Brooks 區分了<em>本質</em>複雜度(問題本身固有的)與<em>偶發</em>複雜度(由我們的解決方案引入的)。後者才是你唯一能刪除的那種。" data-ja="Brooks は<em>本質的</em>複雑性(問題に固有のもの)と<em>偶有的</em>複雑性(我々の解決策が持ち込んだもの)を区別しました。後者こそが、削除できる唯一の種類です。" data-ko="Brooks는 <em>본질적</em> 복잡성(문제에 내재한)과 <em>우발적</em> 복잡성(우리 해법이 끌어들인)을 구분했습니다. 두 번째 종류만이 당신이 삭제할 수 있는 유일한 것입니다." data-es="Brooks distinguió la complejidad <em>esencial</em> (inherente al problema) de la complejidad <em>accidental</em> (introducida por nuestra solución). La segunda es la única que puedes eliminar.">Brooks distinguished <em>essential</em> complexity (inherent to the problem) from <em>accidental</em> complexity (introduced by our solution). The second kind is the only kind you can delete.</p>
<h3 data-en="Signature symptoms" data-zh="典型症状" data-zhtw="典型症狀" data-ja="典型的な症状" data-ko="대표적인 증상" data-es="Síntomas característicos">Signature symptoms</h3>
<ul>
<li data-en="Abstractions built &quot;for future use&quot; with no current consumer (speculative generality)" data-zh="为“将来使用”而构建、却没有当前消费者的抽象(投机性通用化)" data-zhtw="為「將來使用」而構建、卻沒有當前消費者的抽象(投機性通用化)" data-ja="「将来のため」に作られたが現在の利用者がいない抽象(投機的一般化)" data-ko="현재 사용자가 없는데 「미래를 위해」 만든 추상화(투기적 일반화)" data-es="Abstracciones construidas «para uso futuro» sin ningún consumidor actual (generalidad especulativa)">Abstractions built "for future use" with no current consumer (speculative generality)</li>
<li data-en="Classes that barely justify their existence — a wrapper around a single call" data-zh="几乎无法证明自身存在价值的类——只是对单次调用的一层包装" data-zhtw="幾乎無法證明自身存在價值的類別——只是對單次呼叫的一層包裝" data-ja="存在をかろうじてしか正当化できないクラス——単一の呼び出しを包むだけのラッパー" data-ko="존재를 거의 정당화하지 못하는 클래스 — 단일 호출을 감싼 래퍼" data-es="Clases que apenas justifican su existencia — una envoltura en torno a una sola llamada">Classes that barely justify their existence — a wrapper around a single call</li>
<li data-en="Configuration, indirection, or patterns out of proportion to the actual requirement" data-zh="与实际需求不成比例的配置、间接层或设计模式" data-zhtw="與實際需求不成比例的設定、間接層或設計模式" data-ja="実際の要件に不釣り合いな設定、間接化、あるいはパターン" data-ko="실제 요구사항에 비해 과도한 설정, 간접 계층, 또는 패턴" data-es="Configuración, indirección o patrones desproporcionados respecto al requisito real">Configuration, indirection, or patterns out of proportion to the actual requirement</li>
</ul>
<p class="src" data-en="<b>Sources:</b> Brooks, <em>The Mythical Man-Month</em> (essential vs. accidental complexity) · Fowler, <em>Refactoring</em> (Speculative Generality) · Ousterhout, <em>A Philosophy of Software Design</em>." data-zh="<b>根源:</b>Brooks<em>The Mythical Man-Month</em>(本质复杂度与偶发复杂度)· Fowler<em>Refactoring</em>(投机性通用化)· Ousterhout<em>A Philosophy of Software Design</em>。" data-zhtw="<b>根源:</b>Brooks<em>The Mythical Man-Month</em>(本質複雜度與偶發複雜度)· Fowler<em>Refactoring</em>(投機性通用化)· Ousterhout<em>A Philosophy of Software Design</em>。" data-ja="<b>根源:</b>Brooks、<em>The Mythical Man-Month</em>(本質的複雑性と偶有的複雑性)· Fowler、<em>Refactoring</em>(投機的一般化)· Ousterhout、<em>A Philosophy of Software Design</em>。" data-ko="<b>근원:</b> Brooks, <em>The Mythical Man-Month</em>(본질적 대 우발적 복잡성) · Fowler, <em>Refactoring</em>(투기적 일반화) · Ousterhout, <em>A Philosophy of Software Design</em>." data-es="<b>Fuentes:</b> Brooks, <em>The Mythical Man-Month</em> (complejidad esencial vs. accidental) · Fowler, <em>Refactoring</em> (Generalidad especulativa) · Ousterhout, <em>A Philosophy of Software Design</em>."><b>Sources:</b> Brooks, <em>The Mythical Man-Month</em> (essential vs. accidental complexity) · Fowler, <em>Refactoring</em> (Speculative Generality) · Ousterhout, <em>A Philosophy of Software Design</em>.</p>
<h3 data-en="Remedy" data-zh="修复" data-zhtw="對策" data-ja="対策" data-ko="처방" data-es="Remedio">Remedy</h3>
<p data-en="Delete speculative abstractions until a second real consumer appears. Prefer the simplest design that solves today's problem — you can always add structure when the need is concrete." data-zh="在第二个真实消费者出现之前,删除那些投机性的抽象。优先选择能解决今天问题的最简设计——等需求变得具体时,你随时可以再加结构。" data-zhtw="在第二個真實消費者出現之前,刪除那些投機性的抽象。優先選擇能解決今天問題的最簡設計——等需求變得具體時,你隨時可以再加結構。" data-ja="二人目の本当の利用者が現れるまで、投機的な抽象は削除する。今日の問題を解く最もシンプルな設計を選ぶ——必要が具体的になれば、いつでも構造を足せる。" data-ko="두 번째 실제 사용자가 나타날 때까지 투기적 추상화를 삭제하라. 오늘의 문제를 푸는 가장 단순한 설계를 선호하라 — 필요가 구체화되면 언제든 구조를 더할 수 있다." data-es="Elimina las abstracciones especulativas hasta que aparezca un segundo consumidor real. Prefiere el diseño más simple que resuelva el problema de hoy — siempre puedes añadir estructura cuando la necesidad sea concreta.">Delete speculative abstractions until a second real consumer appears. Prefer the simplest design that solves today's problem — you can always add structure when the need is concrete.</p>
</div>
<h2 id="r5"><span data-en="5 · Dependency Disorder" data-zh="5 · 依赖失序" data-zhtw="5 · 依賴失序" data-ja="5 · 依存関係の無秩序" data-ko="5 · 의존성 무질서" data-es="5 · Desorden de dependencias">5 · Dependency Disorder</span> <span class="code">R5</span></h2>
<div class="risk">
<p class="q" data-en="Diagnostic question: Do dependencies flow in a consistent, predictable direction?" data-zh="诊断问题:依赖是否朝着一致、可预测的方向流动?" data-zhtw="診斷問題:依賴是否朝著一致、可預測的方向流動?" data-ja="診断的質問:依存は一貫した予測可能な方向に流れているか?" data-ko="진단 질문: 의존성이 일관되고 예측 가능한 방향으로 흐르는가?" data-es="Pregunta diagnóstica: ¿las dependencias fluyen en una dirección consistente y predecible?">Diagnostic question: Do dependencies flow in a consistent, predictable direction?</p>
<p data-en="Architecture is mostly about the direction of the arrows. When high-level policy depends on low-level detail, the detail starts driving the design." data-zh="架构在很大程度上就是关于箭头的方向。当高层策略依赖于低层细节时,细节就开始主导设计。" data-zhtw="架構在很大程度上就是關於箭頭的方向。當高層策略依賴於低層細節時,細節就開始主導設計。" data-ja="アーキテクチャとは、主に矢印の向きの問題です。高レベルの方針が低レベルの詳細に依存すると、詳細が設計を駆動し始めます。" data-ko="아키텍처는 대부분 화살표의 방향에 관한 것입니다. 고수준 정책이 저수준 세부사항에 의존하면, 세부사항이 설계를 주도하기 시작합니다." data-es="La arquitectura trata sobre todo de la dirección de las flechas. Cuando la política de alto nivel depende del detalle de bajo nivel, el detalle empieza a dirigir el diseño.">Architecture is mostly about the direction of the arrows. When high-level policy depends on low-level detail, the detail starts driving the design.</p>
<h3 data-en="Signature symptoms" data-zh="典型症状" data-zhtw="典型症狀" data-ja="典型的な症状" data-ko="대표적인 증상" data-es="Síntomas característicos">Signature symptoms</h3>
<ul>
<li data-en="Circular dependencies between modules or packages" data-zh="模块或包之间存在循环依赖" data-zhtw="模組或套件之間存在循環依賴" data-ja="モジュールやパッケージ間の循環依存" data-ko="모듈이나 패키지 간의 순환 의존성" data-es="Dependencias circulares entre módulos o paquetes">Circular dependencies between modules or packages</li>
<li data-en="High-level business logic importing directly from low-level infrastructure (DB drivers, HTTP clients)" data-zh="高层业务逻辑直接从低层基础设施(数据库驱动、HTTP 客户端)导入" data-zhtw="高層業務邏輯直接從低層基礎設施(資料庫驅動、HTTP 客戶端)匯入" data-ja="高レベルのビジネスロジックが低レベルのインフラ(DBドライバ、HTTPクライアント)から直接インポートしている" data-ko="고수준 비즈니스 로직이 저수준 인프라(DB 드라이버, HTTP 클라이언트)에서 직접 가져온다" data-es="Lógica de negocio de alto nivel que importa directamente de infraestructura de bajo nivel (drivers de BD, clientes HTTP)">High-level business logic importing directly from low-level infrastructure (DB drivers, HTTP clients)</li>
<li data-en="The domain layer reaching out to frameworks instead of the other way around" data-zh="领域层主动去依赖框架,而不是反过来" data-zhtw="領域層主動去依賴框架,而不是反過來" data-ja="ドメイン層がフレームワークに手を伸ばしている——本来は逆であるべき" data-ko="도메인 계층이 프레임워크에 손을 뻗는다 — 반대가 되어야 하는데" data-es="La capa de dominio recurriendo a los frameworks en vez de al revés">The domain layer reaching out to frameworks instead of the other way around</li>
</ul>
<p class="src" data-en="<b>Sources:</b> Martin, <em>Clean Architecture</em> (Dependency Inversion, the Dependency Rule) · Brooks, <em>The Mythical Man-Month</em> · Winters et al., <em>Software Engineering at Google</em>." data-zh="<b>根源:</b>Martin<em>Clean Architecture</em>(依赖倒置、依赖规则)· Brooks<em>The Mythical Man-Month</em> · Winters et al.<em>Software Engineering at Google</em>。" data-zhtw="<b>根源:</b>Martin<em>Clean Architecture</em>(依賴反轉、依賴規則)· Brooks<em>The Mythical Man-Month</em> · Winters et al.<em>Software Engineering at Google</em>。" data-ja="<b>根源:</b>Martin、<em>Clean Architecture</em>(依存性逆転、依存性のルール)· Brooks、<em>The Mythical Man-Month</em> · Winters et al.、<em>Software Engineering at Google</em>。" data-ko="<b>근원:</b> Martin, <em>Clean Architecture</em>(의존성 역전, 의존성 규칙) · Brooks, <em>The Mythical Man-Month</em> · Winters et al., <em>Software Engineering at Google</em>." data-es="<b>Fuentes:</b> Martin, <em>Clean Architecture</em> (Inversión de dependencias, la Regla de Dependencia) · Brooks, <em>The Mythical Man-Month</em> · Winters et al., <em>Software Engineering at Google</em>."><b>Sources:</b> Martin, <em>Clean Architecture</em> (Dependency Inversion, the Dependency Rule) · Brooks, <em>The Mythical Man-Month</em> · Winters et al., <em>Software Engineering at Google</em>.</p>
<h3 data-en="Remedy" data-zh="修复" data-zhtw="對策" data-ja="対策" data-ko="처방" data-es="Remedio">Remedy</h3>
<p data-en="Invert the dependency: define an interface the high-level code owns, and let infrastructure implement it. Break cycles by extracting the shared abstraction both sides can depend on." data-zh="倒置依赖:定义一个由高层代码拥有的接口,让基础设施去实现它。通过提炼出双方都能依赖的共享抽象来打破循环。" data-zhtw="反轉依賴:定義一個由高層程式碼擁有的介面,讓基礎設施去實作它。透過提煉出雙方都能依賴的共享抽象來打破循環。" data-ja="依存を逆転させる——高レベルのコードが所有するインターフェースを定義し、インフラにそれを実装させる。両者が依存できる共有の抽象を抽出して循環を断ち切る。" data-ko="의존성을 역전하라: 고수준 코드가 소유하는 인터페이스를 정의하고, 인프라가 그것을 구현하게 하라. 양쪽이 의존할 수 있는 공유 추상을 추출해 순환을 끊어라." data-es="Invierte la dependencia: define una interfaz que posea el código de alto nivel y deja que la infraestructura la implemente. Rompe los ciclos extrayendo la abstracción compartida de la que ambos lados puedan depender.">Invert the dependency: define an interface the high-level code owns, and let infrastructure implement it. Break cycles by extracting the shared abstraction both sides can depend on.</p>
</div>
<h2 id="r6"><span data-en="6 · Domain Model Distortion" data-zh="6 · 领域模型失真" data-zhtw="6 · 領域模型失真" data-ja="6 · ドメインモデルの歪み" data-ko="6 · 도메인 모델 왜곡" data-es="6 · Distorsión del modelo de dominio">6 · Domain Model Distortion</span> <span class="code">R6</span></h2>
<div class="risk">
<p class="q" data-en="Diagnostic question: Does the code faithfully represent the problem it is solving?" data-zh="诊断问题:代码是否忠实地表达了它正在解决的问题?" data-zhtw="診斷問題:程式碼是否忠實地表達了它正在解決的問題?" data-ja="診断的質問:コードは、それが解いている問題を忠実に表現しているか?" data-ko="진단 질문: 코드가 해결하고 있는 문제를 충실하게 표현하는가?" data-es="Pregunta diagnóstica: ¿el código representa fielmente el problema que está resolviendo?">Diagnostic question: Does the code faithfully represent the problem it is solving?</p>
<p data-en="When the model drifts from the domain, every reader has to translate in their head — and translation errors become bugs." data-zh="当模型与领域产生偏离时,每个读代码的人都得在脑子里做一次翻译——而翻译错误就会变成 bug。" data-zhtw="當模型與領域產生偏離時,每個讀程式碼的人都得在腦子裡做一次翻譯——而翻譯錯誤就會變成 bug。" data-ja="モデルがドメインから乖離すると、読み手は皆、頭の中で翻訳しなければならなくなり——翻訳ミスがバグになります。" data-ko="모델이 도메인에서 멀어지면, 모든 독자가 머릿속에서 번역을 해야 하고 — 번역 오류는 버그가 됩니다." data-es="Cuando el modelo se aleja del dominio, cada lector tiene que traducir mentalmente — y los errores de traducción se convierten en bugs.">When the model drifts from the domain, every reader has to translate in their head — and translation errors become bugs.</p>
<h3 data-en="Signature symptoms" data-zh="典型症状" data-zhtw="典型症狀" data-ja="典型的な症状" data-ko="대표적인 증상" data-es="Síntomas característicos">Signature symptoms</h3>
<ul>
<li data-en="Anemic models: business logic scattered across services while domain objects hold only getters and setters" data-zh="贫血模型:业务逻辑散落在各个服务中,而领域对象只持有 getter 和 setter" data-zhtw="貧血模型:業務邏輯散落在各個服務中,而領域物件只持有 getter 和 setter" data-ja="貧血モデル:ビジネスロジックがサービス全体に散らばり、ドメインオブジェクトは getter と setter しか持たない" data-ko="빈약한 모델: 비즈니스 로직이 여러 서비스에 흩어져 있고 도메인 객체는 getter와 setter만 가진다" data-es="Modelos anémicos: la lógica de negocio dispersa entre servicios mientras los objetos de dominio solo tienen getters y setters">Anemic models: business logic scattered across services while domain objects hold only getters and setters</li>
<li data-en="Names that don't match what business stakeholders actually call the concept" data-zh="命名与业务相关方对该概念的实际称呼不一致" data-zhtw="命名與業務相關方對該概念的實際稱呼不一致" data-ja="ビジネスの関係者が実際にその概念を呼ぶ名前と一致しない命名" data-ko="비즈니스 이해관계자가 실제로 그 개념을 부르는 이름과 맞지 않는 명명" data-es="Nombres que no coinciden con cómo los interesados del negocio llaman realmente al concepto">Names that don't match what business stakeholders actually call the concept</li>
<li data-en="Logic bugs hiding in code that <em>reads</em> plausibly but doesn't model reality (e.g. comparing a value to itself after overwriting it)" data-zh="逻辑 bug 藏在那些<em>读起来</em>合理却没有真实建模的代码里(例如在覆盖某个值之后又把它和自身比较)" data-zhtw="邏輯 bug 藏在那些<em>讀起來</em>合理卻沒有真實建模的程式碼裡(例如在覆寫某個值之後又把它和自身比較)" data-ja="<em>読めば</em>もっともらしいが現実をモデル化していないコードに潜む論理バグ(例:ある値を上書きした後にそれ自身と比較する)" data-ko="<em>읽기에는</em> 그럴듯하지만 현실을 모델링하지 못한 코드에 숨은 논리 버그(예: 어떤 값을 덮어쓴 뒤 자기 자신과 비교하기)" data-es="Errores de lógica ocultos en código que <em>se lee</em> de forma plausible pero no modela la realidad (p. ej. comparar un valor consigo mismo después de sobrescribirlo)">Logic bugs hiding in code that <em>reads</em> plausibly but doesn't model reality (e.g. comparing a value to itself after overwriting it)</li>
</ul>
<p class="src" data-en="<b>Sources:</b> Evans, <em>Domain-Driven Design</em> (rich models, ubiquitous language) · Fowler, <em>Refactoring</em> (Anemic Domain Model)." data-zh="<b>根源:</b>Evans<em>Domain-Driven Design</em>(充血模型、统一语言)· Fowler<em>Refactoring</em>(贫血领域模型)。" data-zhtw="<b>根源:</b>Evans<em>Domain-Driven Design</em>(充血模型、統一語言)· Fowler<em>Refactoring</em>(貧血領域模型)。" data-ja="<b>根源:</b>Evans、<em>Domain-Driven Design</em>(リッチモデル、ユビキタス言語)· Fowler、<em>Refactoring</em>(ドメインモデル貧血症)。" data-ko="<b>근원:</b> Evans, <em>Domain-Driven Design</em>(풍부한 모델, 유비쿼터스 언어) · Fowler, <em>Refactoring</em>(빈약한 도메인 모델)." data-es="<b>Fuentes:</b> Evans, <em>Domain-Driven Design</em> (modelos ricos, lenguaje ubicuo) · Fowler, <em>Refactoring</em> (Modelo de dominio anémico)."><b>Sources:</b> Evans, <em>Domain-Driven Design</em> (rich models, ubiquitous language) · Fowler, <em>Refactoring</em> (Anemic Domain Model).</p>
<h3 data-en="Remedy" data-zh="修复" data-zhtw="對策" data-ja="対策" data-ko="처방" data-es="Remedio">Remedy</h3>
<p data-en="Move behaviour onto the objects that own the data. Align every name with the language the business uses. Make illegal states unrepresentable." data-zh="把行为移动到拥有数据的对象上。让每个命名都与业务使用的语言对齐。让非法状态无法被表示。" data-zhtw="把行為移動到擁有資料的物件上。讓每個命名都與業務使用的語言對齊。讓非法狀態無法被表示。" data-ja="振る舞いを、データを所有するオブジェクトへ移す。あらゆる名前をビジネスが使う言葉に揃える。不正な状態を表現できないようにする。" data-ko="행위를 데이터를 소유한 객체로 옮겨라. 모든 이름을 비즈니스가 쓰는 언어에 맞춰라. 불가능한 상태를 표현할 수 없게 만들어라." data-es="Mueve el comportamiento a los objetos que poseen los datos. Alinea cada nombre con el lenguaje que usa el negocio. Haz que los estados ilegales sean irrepresentables.">Move behaviour onto the objects that own the data. Align every name with the language the business uses. Make illegal states unrepresentable.</p>
</div>
<h2 data-en="And the test suite decays too" data-zh="测试套件也会腐化" data-zhtw="測試套件也會衰退" data-ja="テストスイートもまた劣化する" data-ko="테스트 스위트도 쇠퇴한다" data-es="Y la suite de pruebas también se deteriora">And the test suite decays too</h2>
<p data-en="brooks-lint applies the same lens to tests, with six parallel risks (T1T6) drawn from <em>xUnit Test Patterns</em>, <em>The Art of Unit Testing</em>, <em>How Google Tests Software</em>, and <em>Working Effectively with Legacy Code</em>:" data-zh="brooks-lint 用同样的视角审视测试,提出六个对应的风险(T1–T6),取自 <em>xUnit Test Patterns</em>、<em>The Art of Unit Testing</em>、<em>How Google Tests Software</em> 和 <em>Working Effectively with Legacy Code</em>" data-zhtw="brooks-lint 用同樣的視角審視測試,提出六個對應的風險(T1–T6),取自 <em>xUnit Test Patterns</em>、<em>The Art of Unit Testing</em>、<em>How Google Tests Software</em> 和 <em>Working Effectively with Legacy Code</em>" data-ja="brooks-lint は同じレンズをテストにも当て、<em>xUnit Test Patterns</em>、<em>The Art of Unit Testing</em>、<em>How Google Tests Software</em>、<em>Working Effectively with Legacy Code</em> から導いた六つの並行するリスク(T1–T6)を扱います:" data-ko="brooks-lint은 같은 렌즈를 테스트에도 적용해, <em>xUnit Test Patterns</em>, <em>The Art of Unit Testing</em>, <em>How Google Tests Software</em>, <em>Working Effectively with Legacy Code</em>에서 끌어낸 여섯 가지 병렬 위험(T1–T6)을 다룹니다:" data-es="brooks-lint aplica la misma mirada a las pruebas, con seis riesgos paralelos (T1T6) extraídos de <em>xUnit Test Patterns</em>, <em>The Art of Unit Testing</em>, <em>How Google Tests Software</em> y <em>Working Effectively with Legacy Code</em>:">brooks-lint applies the same lens to tests, with six parallel risks (T1T6) drawn from <em>xUnit Test Patterns</em>, <em>The Art of Unit Testing</em>, <em>How Google Tests Software</em>, and <em>Working Effectively with Legacy Code</em>:</p>
<table>
<tr><th data-en="Risk" data-zh="风险" data-zhtw="風險" data-ja="リスク" data-ko="위험" data-es="Riesgo">Risk</th><th data-en="The question it asks" data-zh="它提出的问题" data-zhtw="它提出的問題" data-ja="それが問う質問" data-ko="그것이 던지는 질문" data-es="La pregunta que plantea">The question it asks</th></tr>
<tr><td data-en="Test Obscurity" data-zh="测试晦涩" data-zhtw="測試晦澀" data-ja="テストの不明瞭さ" data-ko="테스트 불명확성" data-es="Opacidad de las pruebas">Test Obscurity</td><td data-en="Can you tell what a test verifies without reading its implementation?" data-zh="不读实现就能看出一个测试在验证什么吗?" data-zhtw="不讀實作就能看出一個測試在驗證什麼嗎?" data-ja="実装を読まずに、そのテストが何を検証しているか分かるか?" data-ko="구현을 읽지 않고도 테스트가 무엇을 검증하는지 알 수 있는가?" data-es="¿Puedes saber qué verifica una prueba sin leer su implementación?">Can you tell what a test verifies without reading its implementation?</td></tr>
<tr><td data-en="Test Brittleness" data-zh="测试脆弱" data-zhtw="測試脆弱" data-ja="テストの脆弱性" data-ko="테스트 취약성" data-es="Fragilidad de las pruebas">Test Brittleness</td><td data-en="Does a refactor that preserves behaviour still break the test?" data-zh="一次保持行为不变的重构是否仍会让测试失败?" data-zhtw="一次保持行為不變的重構是否仍會讓測試失敗?" data-ja="振る舞いを保つリファクタリングでも、テストが壊れてしまうか?" data-ko="동작을 보존하는 리팩터링인데도 테스트가 깨지는가?" data-es="¿Una refactorización que preserva el comportamiento aún rompe la prueba?">Does a refactor that preserves behaviour still break the test?</td></tr>
<tr><td data-en="Test Duplication" data-zh="测试重复" data-zhtw="測試重複" data-ja="テストの重複" data-ko="테스트 중복" data-es="Duplicación de pruebas">Test Duplication</td><td data-en="Is the same setup or assertion copied across many tests?" data-zh="同样的 setup 或断言是否被复制到许多测试中?" data-zhtw="同樣的 setup 或斷言是否被複製到許多測試中?" data-ja="同じセットアップやアサーションが多くのテストにコピーされていないか?" data-ko="같은 셋업이나 단언이 여러 테스트에 복사되어 있는가?" data-es="¿La misma preparación o aserción se copia en muchas pruebas?">Is the same setup or assertion copied across many tests?</td></tr>
<tr><td data-en="Mock Abuse" data-zh="模拟滥用" data-zhtw="模擬濫用" data-ja="モックの乱用" data-ko="목 남용" data-es="Abuso de mocks">Mock Abuse</td><td data-en="Does the test verify interactions instead of outcomes?" data-zh="测试验证的是交互过程而非最终结果吗?" data-zhtw="測試驗證的是互動過程而非最終結果嗎?" data-ja="テストは結果ではなく相互作用を検証していないか?" data-ko="테스트가 결과 대신 상호작용을 검증하는가?" data-es="¿La prueba verifica interacciones en lugar de resultados?">Does the test verify interactions instead of outcomes?</td></tr>
<tr><td data-en="Coverage Illusion" data-zh="覆盖率幻觉" data-zhtw="覆蓋率幻覺" data-ja="カバレッジの幻想" data-ko="커버리지 착각" data-es="Ilusión de cobertura">Coverage Illusion</td><td data-en="Does high coverage hide tests that assert nothing meaningful?" data-zh="高覆盖率是否掩盖了那些没有做任何有意义断言的测试?" data-zhtw="高覆蓋率是否掩蓋了那些沒有做任何有意義斷言的測試?" data-ja="高いカバレッジが、意味のあるアサーションを何もしていないテストを隠していないか?" data-ko="높은 커버리지가 의미 있는 단언을 전혀 하지 않는 테스트를 가리고 있는가?" data-es="¿La alta cobertura oculta pruebas que no afirman nada significativo?">Does high coverage hide tests that assert nothing meaningful?</td></tr>
<tr><td data-en="Architecture Mismatch" data-zh="架构错配" data-zhtw="架構錯配" data-ja="アーキテクチャの不整合" data-ko="아키텍처 불일치" data-es="Desajuste de arquitectura">Architecture Mismatch</td><td data-en="Do the tests fight the code's seams instead of using them?" data-zh="测试是在对抗代码的接缝,而不是利用它们吗?" data-zhtw="測試是在對抗程式碼的接縫,而不是利用它們嗎?" data-ja="テストはコードの継ぎ目を使うのではなく、それと戦っていないか?" data-ko="테스트가 코드의 이음새를 활용하는 대신 그것과 싸우고 있는가?" data-es="¿Las pruebas luchan contra las costuras del código en vez de usarlas?">Do the tests fight the code's seams instead of using them?</td></tr>
</table>
<div class="cta">
<h3 data-en="See it run on your own code" data-zh="在你自己的代码上看看效果" data-zhtw="在你自己的程式碼上看看效果" data-ja="あなた自身のコードで動かしてみる" data-ko="당신의 코드에서 직접 실행해 보세요" data-es="Míralo funcionar en tu propio código">See it run on your own code</h3>
<p data-en="brooks-lint is a free, open-source plugin for Claude Code, Gemini CLI, and Codex. Install it and review any file in one command:" data-zh="brooks-lint 是一个免费、开源的插件,支持 Claude Code、Gemini CLI 和 Codex。安装后,一条命令即可评审任意文件:" data-zhtw="brooks-lint 是一個免費、開源的外掛,支援 Claude Code、Gemini CLI 和 Codex。安裝後,一條指令即可審查任意檔案:" data-ja="brooks-lint は Claude Code、Gemini CLI、Codex 向けの無料・オープンソースのプラグインです。インストールすれば、一つのコマンドで任意のファイルをレビューできます:" data-ko="brooks-lint은 Claude Code, Gemini CLI, Codex를 위한 무료 오픈소스 플러그인입니다. 설치하면 명령 하나로 어떤 파일이든 리뷰할 수 있습니다:" data-es="brooks-lint es un plugin gratuito y de código abierto para Claude Code, Gemini CLI y Codex. Instálalo y revisa cualquier archivo con un solo comando:">brooks-lint is a free, open-source plugin for Claude Code, Gemini CLI, and Codex. Install it and review any file in one command:</p>
<p data-en="<code>/plugin marketplace add hyhmrright/brooks-lint</code><br><code>/brooks-review</code>" data-zh="<code>/plugin marketplace add hyhmrright/brooks-lint</code><br><code>/brooks-review</code>" data-zhtw="<code>/plugin marketplace add hyhmrright/brooks-lint</code><br><code>/brooks-review</code>" data-ja="<code>/plugin marketplace add hyhmrright/brooks-lint</code><br><code>/brooks-review</code>" data-ko="<code>/plugin marketplace add hyhmrright/brooks-lint</code><br><code>/brooks-review</code>" data-es="<code>/plugin marketplace add hyhmrright/brooks-lint</code><br><code>/brooks-review</code>"><code>/plugin marketplace add hyhmrright/brooks-lint</code><br><code>/brooks-review</code></p>
<a href="https://github.com/hyhmrright/brooks-lint" data-en="⭐ Get it on GitHub" data-zh="⭐ 在 GitHub 上获取" data-zhtw="⭐ 在 GitHub 上取得" data-ja="⭐ GitHub で入手する" data-ko="⭐ GitHub에서 받기" data-es="⭐ Conseguir en GitHub">⭐ Get it on GitHub</a>
</div>
<footer>
<a href="index.html" data-en="Home" data-zh="首页" data-zhtw="首頁" data-ja="ホーム" data-ko="홈" data-es="Inicio">Home</a> · <a href="gallery.html" data-en="Worked-example gallery" data-zh="实战示例画廊" data-zhtw="實戰範例展示" data-ja="実例ギャラリー" data-ko="실전 예제 갤러리" data-es="Galería de ejemplos resueltos">Worked-example gallery</a> · <a href="https://github.com/hyhmrright/brooks-lint" data-en="Source &amp; docs" data-zh="源码与文档" data-zhtw="原始碼與文件" data-ja="ソースとドキュメント" data-ko="소스 및 문서" data-es="Código y documentación">Source &amp; docs</a><br>
<span data-en="brooks-lint — AI code reviews grounded in twelve classic engineering books · MIT licensed" data-zh="brooks-lint — 扎根于十二本经典工程著作的 AI 代码评审 · MIT 许可" data-zhtw="brooks-lint — 扎根於十二本經典工程著作的 AI 程式碼審查 · MIT 授權" data-ja="brooks-lint — 十二冊の古典的なエンジニアリング名著に基づく AI コードレビュー · MIT ライセンス" data-ko="brooks-lint — 열두 권의 고전 엔지니어링 명저에 기반한 AI 코드 리뷰 · MIT 라이선스" data-es="brooks-lint — revisiones de código con IA basadas en doce libros clásicos de ingeniería · licencia MIT">brooks-lint — AI code reviews grounded in twelve classic engineering books · MIT licensed</span>
</footer>
</div>
<script>
(function () {
var STORE = "brooks-lint-lang";
var HTML_LANG = { en:"en", zh:"zh-CN", zhtw:"zh-TW", ja:"ja", ko:"ko", es:"es" };
function apply(lang) {
document.documentElement.lang = HTML_LANG[lang] || "en";
document.querySelectorAll("[data-en]").forEach(function (el) {
var v = el.getAttribute("data-" + lang);
if (v != null) el.innerHTML = v;
});
document.querySelectorAll(".lang-toggle button").forEach(function (b) {
b.classList.toggle("active", b.getAttribute("data-set-lang") === lang);
});
try { localStorage.setItem(STORE, lang); } catch (e) {}
}
document.querySelectorAll("[data-set-lang]").forEach(function (b) {
b.addEventListener("click", function () { apply(b.getAttribute("data-set-lang")); });
});
var saved;
try { saved = localStorage.getItem(STORE); } catch (e) {}
if (!saved) {
var nav = (navigator.language || "").toLowerCase();
saved = (nav.indexOf("zh-tw")===0||nav.indexOf("zh-hant")===0||nav.indexOf("zh-hk")===0||nav.indexOf("zh-mo")===0) ? "zhtw"
: nav.indexOf("zh")===0 ? "zh"
: nav.indexOf("ja")===0 ? "ja"
: nav.indexOf("ko")===0 ? "ko"
: nav.indexOf("es")===0 ? "es"
: "en";
}
apply(saved);
})();
</script>
</body>
</html>