@phuc1403/musketeer 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALLATION.md +52 -52
- package/README.md +49 -49
- package/bin/musketeer.js +168 -168
- package/manifest.json +333 -301
- package/package.json +48 -48
- package/src/dotnet-scaffold-copier.js +79 -79
- package/src/provisioner/detect.js +93 -93
- package/src/self-update.js +77 -77
- package/template/.claude/agents/code-reviewer.md +182 -166
- package/template/.claude/agents/git-manager.md +18 -18
- package/template/.claude/agents/hallmark-auditor.md +78 -78
- package/template/.claude/agents/researcher.md +33 -33
- package/template/.claude/hooks/block-unsafe-adr-title.cjs +85 -85
- package/template/.claude/hooks/git-skill-reminder.cjs +53 -0
- package/template/.claude/hooks/init-adr-dir.cjs +173 -173
- package/template/.claude/hooks/inject-adr-flags.cjs +94 -94
- package/template/.claude/hooks/lib/adr/command-scan.cjs +115 -115
- package/template/.claude/hooks/lib/characteristics/checker.cjs +357 -357
- package/template/.claude/hooks/lib/colors.cjs +180 -122
- package/template/.claude/hooks/lib/git-info-cache.cjs +191 -191
- package/template/.claude/hooks/lib/transcript-parser.cjs +300 -277
- package/template/.claude/hooks/sync-adr-toc.cjs +146 -146
- package/template/.claude/hooks/{usage-context-awareness.cjs → usage-quota-cache-refresh.cjs} +166 -166
- package/template/.claude/hooks/validate-characteristics-hook.cjs +66 -66
- package/template/.claude/hooks/validate-cml-hook.js +145 -145
- package/template/.claude/skills/adr-writer/SKILL.md +48 -48
- package/template/.claude/skills/adr-writer/references/adr-example.md +35 -35
- package/template/.claude/skills/architecture-characteristic-writer/SKILL.md +215 -215
- package/template/.claude/skills/architecture-characteristic-writer/assets/worksheet-template.md +29 -29
- package/template/.claude/skills/architecture-characteristic-writer/references/characteristics-catalog.md +40 -40
- package/template/.claude/skills/architecture-characteristic-writer/scripts/ranking-table.cjs +171 -171
- package/template/.claude/skills/code-review/SKILL.md +201 -54
- package/template/.claude/skills/code-review/references/checklist-workflow.md +96 -0
- package/template/.claude/skills/code-review/references/checklists/api.md +52 -52
- package/template/.claude/skills/code-review/references/checklists/base.md +100 -100
- package/template/.claude/skills/code-review/references/checklists/web-app.md +54 -54
- package/template/.claude/skills/code-review/references/code-review-reception.md +113 -0
- package/template/.claude/skills/code-review/references/codebase-scan-workflow.md +30 -0
- package/template/.claude/skills/code-review/references/edge-case-scouting.md +119 -0
- package/template/.claude/skills/code-review/references/input-mode-resolution.md +135 -0
- package/template/.claude/skills/code-review/references/parallel-review-workflow.md +76 -0
- package/template/.claude/skills/code-review/references/requesting-code-review.md +116 -0
- package/template/.claude/skills/code-review/references/spec-compliance-review.md +43 -0
- package/template/.claude/skills/code-review/references/task-management-reviews.md +140 -0
- package/template/.claude/skills/code-review/references/verification-before-completion.md +139 -0
- package/template/.claude/skills/context-map/SKILL.md +80 -80
- package/template/.claude/skills/context-map/example.cml +106 -106
- package/template/.claude/skills/context-map/reference/Bounded Context/Bounded Context.md +40 -40
- package/template/.claude/skills/context-map/reference/Bounded Context/businessModel.md +5 -5
- package/template/.claude/skills/context-map/reference/Bounded Context/domainVisionStatement.md +2 -2
- package/template/.claude/skills/context-map/reference/Bounded Context/evolution.md +5 -5
- package/template/.claude/skills/context-map/reference/Bounded Context/implementationTechnology.md +1 -1
- package/template/.claude/skills/context-map/reference/Bounded Context/implements.md +1 -1
- package/template/.claude/skills/context-map/reference/Bounded Context/knowledgeLevel.md +4 -4
- package/template/.claude/skills/context-map/reference/Bounded Context/realizes.md +9 -9
- package/template/.claude/skills/context-map/reference/Bounded Context/refines.md +10 -10
- package/template/.claude/skills/context-map/reference/Bounded Context/responsibilities.md +26 -26
- package/template/.claude/skills/context-map/reference/Bounded Context/type.md +23 -23
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Anticorruption Layer.md +5 -5
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Bounded Context Relationship.md +12 -12
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Conformist.md +5 -5
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Customer-Supplier (C-S).md +22 -22
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Open Host Service.md +4 -4
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Partnership (P).md +13 -13
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Published Language.md +4 -4
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Shared Kernel (SK).md +12 -12
- package/template/.claude/skills/context-map/reference/Context Map.md +62 -62
- package/template/.claude/skills/context-map/reference/Domain/Domain.md +30 -30
- package/template/.claude/skills/context-map/reference/Domain/supports.md +33 -33
- package/template/.claude/skills/context-map/reference/Domain/type.md +3 -3
- package/template/.claude/skills/context-map/reference/Semantic Rules.md +32 -32
- package/template/.claude/skills/git/SKILL.md +131 -115
- package/template/.claude/skills/git/references/branch-management.md +88 -88
- package/template/.claude/skills/git/references/commit-standards.md +46 -46
- package/template/.claude/skills/git/references/context-efficiency.md +54 -0
- package/template/.claude/skills/git/references/gh-cli-guide.md +109 -109
- package/template/.claude/skills/git/references/safety-protocols.md +69 -69
- package/template/.claude/skills/git/references/workflow-commit.md +58 -58
- package/template/.claude/skills/git/references/workflow-merge-pr.md +136 -0
- package/template/.claude/skills/git/references/workflow-merge.md +48 -48
- package/template/.claude/skills/git/references/workflow-pr.md +58 -58
- package/template/.claude/skills/git/references/workflow-push.md +52 -52
- package/template/.claude/skills/hallmark/SKILL.md +552 -552
- package/template/.claude/skills/hallmark/references/anti-patterns.md +412 -412
- package/template/.claude/skills/hallmark/references/assets.md +406 -406
- package/template/.claude/skills/hallmark/references/color.md +95 -95
- package/template/.claude/skills/hallmark/references/component-cookbook.md +256 -256
- package/template/.claude/skills/hallmark/references/components/c1-outlined-chip.md +12 -12
- package/template/.claude/skills/hallmark/references/components/c2-inline-form-as-cta.md +16 -16
- package/template/.claude/skills/hallmark/references/components/c3-typographic-link.md +8 -8
- package/template/.claude/skills/hallmark/references/components/c4-sticky-bottom-bar.md +16 -16
- package/template/.claude/skills/hallmark/references/components/f1-bento-grid.md +20 -20
- package/template/.claude/skills/hallmark/references/components/f2-sticky-scroll-stack.md +20 -20
- package/template/.claude/skills/hallmark/references/components/f3-tabular-spec-sheet.md +11 -11
- package/template/.claude/skills/hallmark/references/components/f4-step-sequence.md +11 -11
- package/template/.claude/skills/hallmark/references/components/f5-annotated-screenshot.md +11 -11
- package/template/.claude/skills/hallmark/references/components/f6-product-card-grid.md +41 -41
- package/template/.claude/skills/hallmark/references/components/ft1-mast-headed.md +13 -13
- package/template/.claude/skills/hallmark/references/components/ft2-inline-rule-single-line.md +10 -10
- package/template/.claude/skills/hallmark/references/components/ft3-index-style-category-list.md +12 -12
- package/template/.claude/skills/hallmark/references/components/ft4-dense-typographic.md +10 -10
- package/template/.claude/skills/hallmark/references/components/ft5-statement.md +21 -21
- package/template/.claude/skills/hallmark/references/components/ft6-letter-close.md +19 -19
- package/template/.claude/skills/hallmark/references/components/ft7-newsletter-first.md +27 -27
- package/template/.claude/skills/hallmark/references/components/ft8-marquee-scroll.md +25 -25
- package/template/.claude/skills/hallmark/references/components/h1-marquee.md +15 -15
- package/template/.claude/skills/hallmark/references/components/h2-split-diptych.md +15 -15
- package/template/.claude/skills/hallmark/references/components/h3-quote-led.md +11 -11
- package/template/.claude/skills/hallmark/references/components/h4-stat-led.md +14 -14
- package/template/.claude/skills/hallmark/references/components/h5-letter-hero.md +11 -11
- package/template/.claude/skills/hallmark/references/components/h6-photographic-fold.md +16 -16
- package/template/.claude/skills/hallmark/references/components/h7-demo-video-clipped-by-viewport-edge.md +27 -27
- package/template/.claude/skills/hallmark/references/components/h8-mockup-split-browser-framed.md +23 -23
- package/template/.claude/skills/hallmark/references/components/h9-custom-illustration-centerpiece.md +27 -27
- package/template/.claude/skills/hallmark/references/components/n1-wordmark-2-links.md +12 -12
- package/template/.claude/skills/hallmark/references/components/n10-floating-on-scroll-morph.md +19 -19
- package/template/.claude/skills/hallmark/references/components/n2-floating-chip.md +14 -14
- package/template/.claude/skills/hallmark/references/components/n3-side-rail.md +14 -14
- package/template/.claude/skills/hallmark/references/components/n4-hidden-behind-k.md +9 -9
- package/template/.claude/skills/hallmark/references/components/n5-floating-pill.md +28 -28
- package/template/.claude/skills/hallmark/references/components/n6-newspaper-masthead.md +24 -24
- package/template/.claude/skills/hallmark/references/components/n7-brutal-slab.md +22 -22
- package/template/.claude/skills/hallmark/references/components/n8-terminal-command.md +21 -21
- package/template/.claude/skills/hallmark/references/components/n9-edge-aligned-minimal.md +17 -17
- package/template/.claude/skills/hallmark/references/components/s1-left-margin-numbered.md +15 -15
- package/template/.claude/skills/hallmark/references/components/s2-hanging.md +13 -13
- package/template/.claude/skills/hallmark/references/components/s3-sticky-pinned.md +19 -19
- package/template/.claude/skills/hallmark/references/components/s4-inline-no-break.md +11 -11
- package/template/.claude/skills/hallmark/references/components/s5-bottom-anchored.md +13 -13
- package/template/.claude/skills/hallmark/references/components/t1-pull-quote-with-marginalia.md +12 -12
- package/template/.claude/skills/hallmark/references/components/t2-logo-wall-hairline.md +19 -19
- package/template/.claude/skills/hallmark/references/components/t3-single-huge-quote.md +11 -11
- package/template/.claude/skills/hallmark/references/components/t4-numbered-stat-strip.md +14 -14
- package/template/.claude/skills/hallmark/references/contract.md +24 -24
- package/template/.claude/skills/hallmark/references/copy.md +182 -182
- package/template/.claude/skills/hallmark/references/custom-craft.md +626 -626
- package/template/.claude/skills/hallmark/references/custom-theme.md +329 -329
- package/template/.claude/skills/hallmark/references/design-md.md +116 -116
- package/template/.claude/skills/hallmark/references/export-formats.md +328 -328
- package/template/.claude/skills/hallmark/references/floating-nav.md +89 -89
- package/template/.claude/skills/hallmark/references/genres/atmospheric.md +65 -65
- package/template/.claude/skills/hallmark/references/genres/editorial.md +70 -70
- package/template/.claude/skills/hallmark/references/genres/modern-minimal.md +67 -67
- package/template/.claude/skills/hallmark/references/genres/playful.md +65 -65
- package/template/.claude/skills/hallmark/references/hero-enrichment.md +474 -474
- package/template/.claude/skills/hallmark/references/imagery-kit.md +170 -170
- package/template/.claude/skills/hallmark/references/interaction-and-states.md +207 -207
- package/template/.claude/skills/hallmark/references/layout-and-space.md +111 -111
- package/template/.claude/skills/hallmark/references/macrostructures/01-bento-grid.md +35 -35
- package/template/.claude/skills/hallmark/references/macrostructures/02-long-document.md +34 -34
- package/template/.claude/skills/hallmark/references/macrostructures/03-marquee-hero.md +31 -31
- package/template/.claude/skills/hallmark/references/macrostructures/04-stat-led.md +32 -32
- package/template/.claude/skills/hallmark/references/macrostructures/05-workbench.md +32 -32
- package/template/.claude/skills/hallmark/references/macrostructures/06-conversational-faq.md +33 -33
- package/template/.claude/skills/hallmark/references/macrostructures/07-manifesto.md +32 -32
- package/template/.claude/skills/hallmark/references/macrostructures/08-photographic.md +34 -34
- package/template/.claude/skills/hallmark/references/macrostructures/09-quote-led.md +32 -32
- package/template/.claude/skills/hallmark/references/macrostructures/10-specimen.md +32 -32
- package/template/.claude/skills/hallmark/references/macrostructures/11-catalogue.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/12-letter.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/13-index-first.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/14-narrative-workflow.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/15-split-studio.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/16-feature-stack.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/17-type-specimen.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/18-portfolio-grid.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/19-map-diagram.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/20-ecosystem-index.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/21-component-playground.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures.md +89 -89
- package/template/.claude/skills/hallmark/references/microinteractions.md +260 -260
- package/template/.claude/skills/hallmark/references/motion.md +109 -109
- package/template/.claude/skills/hallmark/references/preview-examples.md +49 -49
- package/template/.claude/skills/hallmark/references/responsive.md +138 -138
- package/template/.claude/skills/hallmark/references/slop-test.md +205 -205
- package/template/.claude/skills/hallmark/references/structure.md +164 -164
- package/template/.claude/skills/hallmark/references/study.md +511 -511
- package/template/.claude/skills/hallmark/references/typography.md +243 -243
- package/template/.claude/skills/hallmark/references/verbs/audit.md +25 -25
- package/template/.claude/skills/hallmark/references/verbs/redesign.md +269 -269
- package/template/.claude/skills/hallmark-loop/SKILL.md +105 -105
- package/template/.claude/skills/hallmark-loop/references/auditor-call.md +60 -60
- package/template/.claude/skills/hallmark-loop/references/capture.md +78 -78
- package/template/.claude/skills/hallmark-loop/references/loop-control.md +79 -79
- package/template/.claude/skills/handoff/SKILL.md +15 -15
- package/template/.claude/skills/knowledge-crunching/SKILL.md +94 -94
- package/template/.claude/skills/research/SKILL.md +69 -69
- package/template/.claude/skills/skill-creator/LICENSE.txt +201 -201
- package/template/.claude/skills/skill-creator/SKILL.md +154 -149
- package/template/.claude/skills/skill-creator/agents/analyzer.md +274 -274
- package/template/.claude/skills/skill-creator/agents/comparator.md +202 -202
- package/template/.claude/skills/skill-creator/agents/grader.md +223 -223
- package/template/.claude/skills/skill-creator/assets/eval_review.html +146 -146
- package/template/.claude/skills/skill-creator/eval-viewer/generate_review.py +471 -471
- package/template/.claude/skills/skill-creator/eval-viewer/viewer.html +1325 -1325
- package/template/.claude/skills/skill-creator/references/benchmark-optimization-guide.md +86 -86
- package/template/.claude/skills/skill-creator/references/distribution-guide.md +79 -79
- package/template/.claude/skills/skill-creator/references/eval-infrastructure-guide.md +129 -129
- package/template/.claude/skills/skill-creator/references/eval-schemas.md +121 -121
- package/template/.claude/skills/skill-creator/references/mcp-skills-integration.md +71 -71
- package/template/.claude/skills/skill-creator/references/metadata-quality-criteria.md +94 -94
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-hosting.md +104 -104
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-overview.md +89 -89
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-schema.md +93 -93
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-sources.md +103 -103
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-troubleshooting.md +76 -76
- package/template/.claude/skills/skill-creator/references/script-quality-criteria.md +106 -106
- package/template/.claude/skills/skill-creator/references/skill-anatomy-and-requirements.md +77 -77
- package/template/.claude/skills/skill-creator/references/skill-creation-workflow.md +152 -151
- package/template/.claude/skills/skill-creator/references/skill-design-patterns.md +75 -75
- package/template/.claude/skills/skill-creator/references/skillmark-benchmark-criteria.md +102 -102
- package/template/.claude/skills/skill-creator/references/structure-organization-criteria.md +114 -114
- package/template/.claude/skills/skill-creator/references/testing-and-iteration.md +78 -78
- package/template/.claude/skills/skill-creator/references/token-efficiency-criteria.md +74 -74
- package/template/.claude/skills/skill-creator/references/troubleshooting-guide.md +81 -81
- package/template/.claude/skills/skill-creator/references/validation-checklist.md +83 -83
- package/template/.claude/skills/skill-creator/references/writing-effective-instructions.md +88 -88
- package/template/.claude/skills/skill-creator/references/yaml-frontmatter-reference.md +92 -92
- package/template/.claude/skills/skill-creator/scripts/aggregate_benchmark.py +401 -401
- package/template/.claude/skills/skill-creator/scripts/encoding_utils.py +36 -36
- package/template/.claude/skills/skill-creator/scripts/generate_report.py +326 -326
- package/template/.claude/skills/skill-creator/scripts/improve_description.py +248 -248
- package/template/.claude/skills/skill-creator/scripts/init_skill.py +360 -360
- package/template/.claude/skills/skill-creator/scripts/package_skill.py +143 -143
- package/template/.claude/skills/skill-creator/scripts/quick_validate.py +110 -110
- package/template/.claude/skills/skill-creator/scripts/run_eval.py +310 -310
- package/template/.claude/skills/skill-creator/scripts/run_loop.py +332 -332
- package/template/.claude/skills/skill-creator/scripts/utils.py +47 -47
- package/template/.claude/skills/tdd/SKILL.md +142 -142
- package/template/.claude/skills/tdd/deep-modules.md +15 -15
- package/template/.claude/skills/tdd/interface-design.md +31 -31
- package/template/.claude/skills/tdd/mocking.md +59 -59
- package/template/.claude/skills/tdd/refactoring.md +10 -10
- package/template/.claude/skills/tdd/tests.md +61 -61
- package/template/.claude/statusline.cjs +0 -0
- package/template/.claude/skills/code-review/references/adversarial-review.md +0 -223
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
"""Shared utilities for skill-creator scripts."""
|
|
2
|
-
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def parse_skill_md(skill_path: Path) -> tuple[str, str, str]:
|
|
8
|
-
"""Parse a SKILL.md file, returning (name, description, full_content)."""
|
|
9
|
-
content = (skill_path / "SKILL.md").read_text()
|
|
10
|
-
lines = content.split("\n")
|
|
11
|
-
|
|
12
|
-
if lines[0].strip() != "---":
|
|
13
|
-
raise ValueError("SKILL.md missing frontmatter (no opening ---)")
|
|
14
|
-
|
|
15
|
-
end_idx = None
|
|
16
|
-
for i, line in enumerate(lines[1:], start=1):
|
|
17
|
-
if line.strip() == "---":
|
|
18
|
-
end_idx = i
|
|
19
|
-
break
|
|
20
|
-
|
|
21
|
-
if end_idx is None:
|
|
22
|
-
raise ValueError("SKILL.md missing frontmatter (no closing ---)")
|
|
23
|
-
|
|
24
|
-
name = ""
|
|
25
|
-
description = ""
|
|
26
|
-
frontmatter_lines = lines[1:end_idx]
|
|
27
|
-
i = 0
|
|
28
|
-
while i < len(frontmatter_lines):
|
|
29
|
-
line = frontmatter_lines[i]
|
|
30
|
-
if line.startswith("name:"):
|
|
31
|
-
name = line[len("name:"):].strip().strip('"').strip("'")
|
|
32
|
-
elif line.startswith("description:"):
|
|
33
|
-
value = line[len("description:"):].strip()
|
|
34
|
-
# Handle YAML multiline indicators (>, |, >-, |-)
|
|
35
|
-
if value in (">", "|", ">-", "|-"):
|
|
36
|
-
continuation_lines: list[str] = []
|
|
37
|
-
i += 1
|
|
38
|
-
while i < len(frontmatter_lines) and (frontmatter_lines[i].startswith(" ") or frontmatter_lines[i].startswith("\t")):
|
|
39
|
-
continuation_lines.append(frontmatter_lines[i].strip())
|
|
40
|
-
i += 1
|
|
41
|
-
description = " ".join(continuation_lines)
|
|
42
|
-
continue
|
|
43
|
-
else:
|
|
44
|
-
description = value.strip('"').strip("'")
|
|
45
|
-
i += 1
|
|
46
|
-
|
|
47
|
-
return name, description, content
|
|
1
|
+
"""Shared utilities for skill-creator scripts."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def parse_skill_md(skill_path: Path) -> tuple[str, str, str]:
|
|
8
|
+
"""Parse a SKILL.md file, returning (name, description, full_content)."""
|
|
9
|
+
content = (skill_path / "SKILL.md").read_text()
|
|
10
|
+
lines = content.split("\n")
|
|
11
|
+
|
|
12
|
+
if lines[0].strip() != "---":
|
|
13
|
+
raise ValueError("SKILL.md missing frontmatter (no opening ---)")
|
|
14
|
+
|
|
15
|
+
end_idx = None
|
|
16
|
+
for i, line in enumerate(lines[1:], start=1):
|
|
17
|
+
if line.strip() == "---":
|
|
18
|
+
end_idx = i
|
|
19
|
+
break
|
|
20
|
+
|
|
21
|
+
if end_idx is None:
|
|
22
|
+
raise ValueError("SKILL.md missing frontmatter (no closing ---)")
|
|
23
|
+
|
|
24
|
+
name = ""
|
|
25
|
+
description = ""
|
|
26
|
+
frontmatter_lines = lines[1:end_idx]
|
|
27
|
+
i = 0
|
|
28
|
+
while i < len(frontmatter_lines):
|
|
29
|
+
line = frontmatter_lines[i]
|
|
30
|
+
if line.startswith("name:"):
|
|
31
|
+
name = line[len("name:"):].strip().strip('"').strip("'")
|
|
32
|
+
elif line.startswith("description:"):
|
|
33
|
+
value = line[len("description:"):].strip()
|
|
34
|
+
# Handle YAML multiline indicators (>, |, >-, |-)
|
|
35
|
+
if value in (">", "|", ">-", "|-"):
|
|
36
|
+
continuation_lines: list[str] = []
|
|
37
|
+
i += 1
|
|
38
|
+
while i < len(frontmatter_lines) and (frontmatter_lines[i].startswith(" ") or frontmatter_lines[i].startswith("\t")):
|
|
39
|
+
continuation_lines.append(frontmatter_lines[i].strip())
|
|
40
|
+
i += 1
|
|
41
|
+
description = " ".join(continuation_lines)
|
|
42
|
+
continue
|
|
43
|
+
else:
|
|
44
|
+
description = value.strip('"').strip("'")
|
|
45
|
+
i += 1
|
|
46
|
+
|
|
47
|
+
return name, description, content
|
|
@@ -1,142 +1,142 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: tdd
|
|
3
|
-
description: Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Test-Driven Development
|
|
7
|
-
|
|
8
|
-
## Philosophy
|
|
9
|
-
|
|
10
|
-
**Core principle**: Tests should verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't.
|
|
11
|
-
|
|
12
|
-
**Good tests** are integration-style: they exercise real code paths through public APIs. They describe _what_ the system does, not _how_ it does it. A good test reads like a specification - "user can checkout with valid cart" tells you exactly what capability exists. These tests survive refactors because they don't care about internal structure.
|
|
13
|
-
|
|
14
|
-
**Bad tests** are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (like querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior.
|
|
15
|
-
|
|
16
|
-
Note: "integration-_style_" here means _through the public surface_ — it is **not** the same as an out-of-process "integration test" (real HTTP + real DB). Which layer uses which is settled in [Build inside-out, and match the test to the layer](#build-inside-out-and-match-the-test-to-the-layer) below.
|
|
17
|
-
|
|
18
|
-
See [tests.md](tests.md) for examples and [mocking.md](mocking.md) for mocking guidelines.
|
|
19
|
-
|
|
20
|
-
## Anti-Pattern: Horizontal Slices
|
|
21
|
-
|
|
22
|
-
**DO NOT write all tests first, then all implementation.** This is "horizontal slicing" - treating RED as "write all tests" and GREEN as "write all code."
|
|
23
|
-
|
|
24
|
-
This produces **crap tests**:
|
|
25
|
-
|
|
26
|
-
- Tests written in bulk test _imagined_ behavior, not _actual_ behavior
|
|
27
|
-
- You end up testing the _shape_ of things (data structures, function signatures) rather than user-facing behavior
|
|
28
|
-
- Tests become insensitive to real changes - they pass when behavior breaks, fail when behavior is fine
|
|
29
|
-
- You outrun your headlights, committing to test structure before understanding the implementation
|
|
30
|
-
|
|
31
|
-
**Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat. Each test responds to what you learned from the previous cycle. Because you just wrote the code, you know exactly what behavior matters and how to verify it.
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
WRONG (horizontal):
|
|
35
|
-
RED: test1, test2, test3, test4, test5
|
|
36
|
-
GREEN: impl1, impl2, impl3, impl4, impl5
|
|
37
|
-
|
|
38
|
-
RIGHT (vertical):
|
|
39
|
-
RED→GREEN: test1→impl1
|
|
40
|
-
RED→GREEN: test2→impl2
|
|
41
|
-
RED→GREEN: test3→impl3
|
|
42
|
-
...
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Build inside-out, and match the test to the layer
|
|
46
|
-
|
|
47
|
-
Grow a feature from the **domain core outward** — never build the whole stack and test at the end.
|
|
48
|
-
Test-drive each layer as you reach it; the _kind_ of first test follows the layer:
|
|
49
|
-
|
|
50
|
-
| Layer | First test | Project |
|
|
51
|
-
|---|---|---|
|
|
52
|
-
| Domain | **unit** | `*.Domain.UnitTests` |
|
|
53
|
-
| Application (handlers) | **unit**, mocking only boundaries (repository, clock, LLM) | `*.Application.UnitTests` |
|
|
54
|
-
| Contracts | **unit** only if they carry logic | — |
|
|
55
|
-
| Infrastructure + API (outer edge) | **integration** — one suite, real HTTP + real DB | `*.IntegrationTests` |
|
|
56
|
-
|
|
57
|
-
Order: **domain → application → outer edge.** The integration suite boots the _composed app_, so the
|
|
58
|
-
real EF mapping/repository only runs through it — there is no separate infra test before the API.
|
|
59
|
-
|
|
60
|
-
"Integration-_style_" (Philosophy: through the public surface) ≠ "integration _test_" (out-of-process,
|
|
61
|
-
real HTTP + DB). Don't conflate them.
|
|
62
|
-
|
|
63
|
-
See [test-per-layer.md](test-per-layer.md): why "first" is per-layer and red-green-refactor stays
|
|
64
|
-
intact; why integration tests are few-but-load-bearing, not cosmetic; and how many ACs to
|
|
65
|
-
integration-test.
|
|
66
|
-
|
|
67
|
-
## Build configuration (strict gates)
|
|
68
|
-
|
|
69
|
-
Treat the build as a quality gate, not just "it compiled". The solution should enforce
|
|
70
|
-
warnings-as-errors, code-style, and full security analysis via a root `Directory.Build.props`
|
|
71
|
-
(`TreatWarningsAsErrors`, `EnforceCodeStyleInBuild`, `AnalysisLevel=latest-recommended`,
|
|
72
|
-
`AnalysisModeSecurity=All`). Ensure these are present — see
|
|
73
|
-
[dotnet-build-config.md](dotnet-build-config.md) (reference: [assets/Directory.Build.props](assets/Directory.Build.props)).
|
|
74
|
-
|
|
75
|
-
## Workflow
|
|
76
|
-
|
|
77
|
-
### 1. Planning
|
|
78
|
-
|
|
79
|
-
When exploring the codebase, use the project's domain glossary so that test names and interface vocabulary match the project's language, and respect ADRs in the area you're touching.
|
|
80
|
-
|
|
81
|
-
**Default to the full flow. Do not ask the user to approve the plan or choose scope — decide and build.** When the task names a behavior (e.g. a story/AC set), implement the entire vertical slice for it: domain → application → outer edge, every layer that the behavior touches, inside-out (see the layer table). "Backend only" / "frontend only" scopes the stack, not the depth — go all the way down the named side. Pick the sensible default for any open decision, state it in one line, and proceed. Only stop to ask if a choice is genuinely irreversible or the requirements truly contradict each other — not merely because more than one option exists.
|
|
82
|
-
|
|
83
|
-
Before writing any code, work this out for yourself (no approval gate):
|
|
84
|
-
|
|
85
|
-
- [ ] Decide what interface changes are needed
|
|
86
|
-
- [ ] List the behaviors to test, ordered (not implementation steps) — cover every AC of the named work
|
|
87
|
-
- [ ] Identify opportunities for [deep modules](deep-modules.md) (small interface, deep implementation)
|
|
88
|
-
- [ ] Design interfaces for [testability](interface-design.md)
|
|
89
|
-
- [ ] Identify the layer(s) you're touching and the matching first-test type (see the layer table)
|
|
90
|
-
|
|
91
|
-
State the plan in one short message, then immediately start the tracer-bullet loop in the same turn.
|
|
92
|
-
|
|
93
|
-
**You can't test everything**, but the named behavior's ACs are all in scope. Focus extra effort on critical paths and complex logic; don't burn cycles on every theoretical edge case beyond the spec.
|
|
94
|
-
|
|
95
|
-
### 2. Tracer Bullet
|
|
96
|
-
|
|
97
|
-
Write ONE test that confirms ONE thing about the system:
|
|
98
|
-
|
|
99
|
-
```
|
|
100
|
-
RED: Write test for first behavior → test fails
|
|
101
|
-
GREEN: Write minimal code to pass → test passes
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
This is your tracer bullet - proves the path works end-to-end.
|
|
105
|
-
|
|
106
|
-
### 3. Incremental Loop
|
|
107
|
-
|
|
108
|
-
For each remaining behavior:
|
|
109
|
-
|
|
110
|
-
```
|
|
111
|
-
RED: Write next test → fails
|
|
112
|
-
GREEN: Minimal code to pass → passes
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
Rules:
|
|
116
|
-
|
|
117
|
-
- One test at a time
|
|
118
|
-
- Only enough code to pass current test
|
|
119
|
-
- Don't anticipate future tests
|
|
120
|
-
- Keep tests focused on observable behavior
|
|
121
|
-
|
|
122
|
-
### 4. Refactor
|
|
123
|
-
|
|
124
|
-
After all tests pass, look for [refactor candidates](refactoring.md):
|
|
125
|
-
|
|
126
|
-
- [ ] Extract duplication
|
|
127
|
-
- [ ] Deepen modules (move complexity behind simple interfaces)
|
|
128
|
-
- [ ] Apply SOLID principles where natural
|
|
129
|
-
- [ ] Consider what new code reveals about existing code
|
|
130
|
-
- [ ] Run tests after each refactor step
|
|
131
|
-
|
|
132
|
-
**Never refactor while RED.** Get to GREEN first.
|
|
133
|
-
|
|
134
|
-
## Checklist Per Cycle
|
|
135
|
-
|
|
136
|
-
```
|
|
137
|
-
[ ] Test describes behavior, not implementation
|
|
138
|
-
[ ] Test uses public interface only
|
|
139
|
-
[ ] Test would survive internal refactor
|
|
140
|
-
[ ] Code is minimal for this test
|
|
141
|
-
[ ] No speculative features added
|
|
142
|
-
```
|
|
1
|
+
---
|
|
2
|
+
name: tdd
|
|
3
|
+
description: Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test-Driven Development
|
|
7
|
+
|
|
8
|
+
## Philosophy
|
|
9
|
+
|
|
10
|
+
**Core principle**: Tests should verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't.
|
|
11
|
+
|
|
12
|
+
**Good tests** are integration-style: they exercise real code paths through public APIs. They describe _what_ the system does, not _how_ it does it. A good test reads like a specification - "user can checkout with valid cart" tells you exactly what capability exists. These tests survive refactors because they don't care about internal structure.
|
|
13
|
+
|
|
14
|
+
**Bad tests** are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (like querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior.
|
|
15
|
+
|
|
16
|
+
Note: "integration-_style_" here means _through the public surface_ — it is **not** the same as an out-of-process "integration test" (real HTTP + real DB). Which layer uses which is settled in [Build inside-out, and match the test to the layer](#build-inside-out-and-match-the-test-to-the-layer) below.
|
|
17
|
+
|
|
18
|
+
See [tests.md](tests.md) for examples and [mocking.md](mocking.md) for mocking guidelines.
|
|
19
|
+
|
|
20
|
+
## Anti-Pattern: Horizontal Slices
|
|
21
|
+
|
|
22
|
+
**DO NOT write all tests first, then all implementation.** This is "horizontal slicing" - treating RED as "write all tests" and GREEN as "write all code."
|
|
23
|
+
|
|
24
|
+
This produces **crap tests**:
|
|
25
|
+
|
|
26
|
+
- Tests written in bulk test _imagined_ behavior, not _actual_ behavior
|
|
27
|
+
- You end up testing the _shape_ of things (data structures, function signatures) rather than user-facing behavior
|
|
28
|
+
- Tests become insensitive to real changes - they pass when behavior breaks, fail when behavior is fine
|
|
29
|
+
- You outrun your headlights, committing to test structure before understanding the implementation
|
|
30
|
+
|
|
31
|
+
**Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat. Each test responds to what you learned from the previous cycle. Because you just wrote the code, you know exactly what behavior matters and how to verify it.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
WRONG (horizontal):
|
|
35
|
+
RED: test1, test2, test3, test4, test5
|
|
36
|
+
GREEN: impl1, impl2, impl3, impl4, impl5
|
|
37
|
+
|
|
38
|
+
RIGHT (vertical):
|
|
39
|
+
RED→GREEN: test1→impl1
|
|
40
|
+
RED→GREEN: test2→impl2
|
|
41
|
+
RED→GREEN: test3→impl3
|
|
42
|
+
...
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Build inside-out, and match the test to the layer
|
|
46
|
+
|
|
47
|
+
Grow a feature from the **domain core outward** — never build the whole stack and test at the end.
|
|
48
|
+
Test-drive each layer as you reach it; the _kind_ of first test follows the layer:
|
|
49
|
+
|
|
50
|
+
| Layer | First test | Project |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| Domain | **unit** | `*.Domain.UnitTests` |
|
|
53
|
+
| Application (handlers) | **unit**, mocking only boundaries (repository, clock, LLM) | `*.Application.UnitTests` |
|
|
54
|
+
| Contracts | **unit** only if they carry logic | — |
|
|
55
|
+
| Infrastructure + API (outer edge) | **integration** — one suite, real HTTP + real DB | `*.IntegrationTests` |
|
|
56
|
+
|
|
57
|
+
Order: **domain → application → outer edge.** The integration suite boots the _composed app_, so the
|
|
58
|
+
real EF mapping/repository only runs through it — there is no separate infra test before the API.
|
|
59
|
+
|
|
60
|
+
"Integration-_style_" (Philosophy: through the public surface) ≠ "integration _test_" (out-of-process,
|
|
61
|
+
real HTTP + DB). Don't conflate them.
|
|
62
|
+
|
|
63
|
+
See [test-per-layer.md](test-per-layer.md): why "first" is per-layer and red-green-refactor stays
|
|
64
|
+
intact; why integration tests are few-but-load-bearing, not cosmetic; and how many ACs to
|
|
65
|
+
integration-test.
|
|
66
|
+
|
|
67
|
+
## Build configuration (strict gates)
|
|
68
|
+
|
|
69
|
+
Treat the build as a quality gate, not just "it compiled". The solution should enforce
|
|
70
|
+
warnings-as-errors, code-style, and full security analysis via a root `Directory.Build.props`
|
|
71
|
+
(`TreatWarningsAsErrors`, `EnforceCodeStyleInBuild`, `AnalysisLevel=latest-recommended`,
|
|
72
|
+
`AnalysisModeSecurity=All`). Ensure these are present — see
|
|
73
|
+
[dotnet-build-config.md](dotnet-build-config.md) (reference: [assets/Directory.Build.props](assets/Directory.Build.props)).
|
|
74
|
+
|
|
75
|
+
## Workflow
|
|
76
|
+
|
|
77
|
+
### 1. Planning
|
|
78
|
+
|
|
79
|
+
When exploring the codebase, use the project's domain glossary so that test names and interface vocabulary match the project's language, and respect ADRs in the area you're touching.
|
|
80
|
+
|
|
81
|
+
**Default to the full flow. Do not ask the user to approve the plan or choose scope — decide and build.** When the task names a behavior (e.g. a story/AC set), implement the entire vertical slice for it: domain → application → outer edge, every layer that the behavior touches, inside-out (see the layer table). "Backend only" / "frontend only" scopes the stack, not the depth — go all the way down the named side. Pick the sensible default for any open decision, state it in one line, and proceed. Only stop to ask if a choice is genuinely irreversible or the requirements truly contradict each other — not merely because more than one option exists.
|
|
82
|
+
|
|
83
|
+
Before writing any code, work this out for yourself (no approval gate):
|
|
84
|
+
|
|
85
|
+
- [ ] Decide what interface changes are needed
|
|
86
|
+
- [ ] List the behaviors to test, ordered (not implementation steps) — cover every AC of the named work
|
|
87
|
+
- [ ] Identify opportunities for [deep modules](deep-modules.md) (small interface, deep implementation)
|
|
88
|
+
- [ ] Design interfaces for [testability](interface-design.md)
|
|
89
|
+
- [ ] Identify the layer(s) you're touching and the matching first-test type (see the layer table)
|
|
90
|
+
|
|
91
|
+
State the plan in one short message, then immediately start the tracer-bullet loop in the same turn.
|
|
92
|
+
|
|
93
|
+
**You can't test everything**, but the named behavior's ACs are all in scope. Focus extra effort on critical paths and complex logic; don't burn cycles on every theoretical edge case beyond the spec.
|
|
94
|
+
|
|
95
|
+
### 2. Tracer Bullet
|
|
96
|
+
|
|
97
|
+
Write ONE test that confirms ONE thing about the system:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
RED: Write test for first behavior → test fails
|
|
101
|
+
GREEN: Write minimal code to pass → test passes
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
This is your tracer bullet - proves the path works end-to-end.
|
|
105
|
+
|
|
106
|
+
### 3. Incremental Loop
|
|
107
|
+
|
|
108
|
+
For each remaining behavior:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
RED: Write next test → fails
|
|
112
|
+
GREEN: Minimal code to pass → passes
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Rules:
|
|
116
|
+
|
|
117
|
+
- One test at a time
|
|
118
|
+
- Only enough code to pass current test
|
|
119
|
+
- Don't anticipate future tests
|
|
120
|
+
- Keep tests focused on observable behavior
|
|
121
|
+
|
|
122
|
+
### 4. Refactor
|
|
123
|
+
|
|
124
|
+
After all tests pass, look for [refactor candidates](refactoring.md):
|
|
125
|
+
|
|
126
|
+
- [ ] Extract duplication
|
|
127
|
+
- [ ] Deepen modules (move complexity behind simple interfaces)
|
|
128
|
+
- [ ] Apply SOLID principles where natural
|
|
129
|
+
- [ ] Consider what new code reveals about existing code
|
|
130
|
+
- [ ] Run tests after each refactor step
|
|
131
|
+
|
|
132
|
+
**Never refactor while RED.** Get to GREEN first.
|
|
133
|
+
|
|
134
|
+
## Checklist Per Cycle
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
[ ] Test describes behavior, not implementation
|
|
138
|
+
[ ] Test uses public interface only
|
|
139
|
+
[ ] Test would survive internal refactor
|
|
140
|
+
[ ] Code is minimal for this test
|
|
141
|
+
[ ] No speculative features added
|
|
142
|
+
```
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
# Deep Modules Summary
|
|
2
|
-
|
|
3
|
-
The concept of deep modules comes from "A Philosophy of Software Design" and contrasts two design approaches:
|
|
4
|
-
|
|
5
|
-
**Deep modules** feature a "small interface + lots of implementation." They expose minimal methods and parameters while concealing substantial internal complexity. This design reduces cognitive load for users of the module.
|
|
6
|
-
|
|
7
|
-
**Shallow modules** present the opposite problem: they expose many methods with complex parameters but provide little substantive logic—essentially acting as thin wrappers.
|
|
8
|
-
|
|
9
|
-
When designing module interfaces, the guidance is to consider three key questions:
|
|
10
|
-
|
|
11
|
-
- Can the number of exposed methods be reduced?
|
|
12
|
-
- Can parameter signatures be simplified?
|
|
13
|
-
- Can additional complexity be internalized rather than exposed?
|
|
14
|
-
|
|
15
|
-
The deep module approach represents superior software design because it maximizes the value delivered relative to the interface burden imposed on developers using that code.
|
|
1
|
+
# Deep Modules Summary
|
|
2
|
+
|
|
3
|
+
The concept of deep modules comes from "A Philosophy of Software Design" and contrasts two design approaches:
|
|
4
|
+
|
|
5
|
+
**Deep modules** feature a "small interface + lots of implementation." They expose minimal methods and parameters while concealing substantial internal complexity. This design reduces cognitive load for users of the module.
|
|
6
|
+
|
|
7
|
+
**Shallow modules** present the opposite problem: they expose many methods with complex parameters but provide little substantive logic—essentially acting as thin wrappers.
|
|
8
|
+
|
|
9
|
+
When designing module interfaces, the guidance is to consider three key questions:
|
|
10
|
+
|
|
11
|
+
- Can the number of exposed methods be reduced?
|
|
12
|
+
- Can parameter signatures be simplified?
|
|
13
|
+
- Can additional complexity be internalized rather than exposed?
|
|
14
|
+
|
|
15
|
+
The deep module approach represents superior software design because it maximizes the value delivered relative to the interface burden imposed on developers using that code.
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
# Interface Design for Testability
|
|
2
|
-
|
|
3
|
-
Good interfaces make testing natural:
|
|
4
|
-
|
|
5
|
-
1. **Accept dependencies, don't create them**
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
// Testable
|
|
9
|
-
function processOrder(order, paymentGateway) {}
|
|
10
|
-
|
|
11
|
-
// Hard to test
|
|
12
|
-
function processOrder(order) {
|
|
13
|
-
const gateway = new StripeGateway();
|
|
14
|
-
}
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
2. **Return results, don't produce side effects**
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
// Testable
|
|
21
|
-
function calculateDiscount(cart): Discount {}
|
|
22
|
-
|
|
23
|
-
// Hard to test
|
|
24
|
-
function applyDiscount(cart): void {
|
|
25
|
-
cart.total -= discount;
|
|
26
|
-
}
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
3. **Small surface area**
|
|
30
|
-
- Fewer methods = fewer tests needed
|
|
31
|
-
- Fewer params = simpler test setup
|
|
1
|
+
# Interface Design for Testability
|
|
2
|
+
|
|
3
|
+
Good interfaces make testing natural:
|
|
4
|
+
|
|
5
|
+
1. **Accept dependencies, don't create them**
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// Testable
|
|
9
|
+
function processOrder(order, paymentGateway) {}
|
|
10
|
+
|
|
11
|
+
// Hard to test
|
|
12
|
+
function processOrder(order) {
|
|
13
|
+
const gateway = new StripeGateway();
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
2. **Return results, don't produce side effects**
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// Testable
|
|
21
|
+
function calculateDiscount(cart): Discount {}
|
|
22
|
+
|
|
23
|
+
// Hard to test
|
|
24
|
+
function applyDiscount(cart): void {
|
|
25
|
+
cart.total -= discount;
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
3. **Small surface area**
|
|
30
|
+
- Fewer methods = fewer tests needed
|
|
31
|
+
- Fewer params = simpler test setup
|
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
# When to Mock
|
|
2
|
-
|
|
3
|
-
Mock at **system boundaries** only:
|
|
4
|
-
|
|
5
|
-
- External APIs (payment, email, etc.)
|
|
6
|
-
- Databases (sometimes - prefer test DB)
|
|
7
|
-
- Time/randomness
|
|
8
|
-
- File system (sometimes)
|
|
9
|
-
|
|
10
|
-
Don't mock:
|
|
11
|
-
|
|
12
|
-
- Your own classes/modules
|
|
13
|
-
- Internal collaborators
|
|
14
|
-
- Anything you control
|
|
15
|
-
|
|
16
|
-
## Designing for Mockability
|
|
17
|
-
|
|
18
|
-
At system boundaries, design interfaces that are easy to mock:
|
|
19
|
-
|
|
20
|
-
**1. Use dependency injection**
|
|
21
|
-
|
|
22
|
-
Pass external dependencies in rather than creating them internally:
|
|
23
|
-
|
|
24
|
-
```typescript
|
|
25
|
-
// Easy to mock
|
|
26
|
-
function processPayment(order, paymentClient) {
|
|
27
|
-
return paymentClient.charge(order.total);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Hard to mock
|
|
31
|
-
function processPayment(order) {
|
|
32
|
-
const client = new StripeClient(process.env.STRIPE_KEY);
|
|
33
|
-
return client.charge(order.total);
|
|
34
|
-
}
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
**2. Prefer SDK-style interfaces over generic fetchers**
|
|
38
|
-
|
|
39
|
-
Create specific functions for each external operation instead of one generic function with conditional logic:
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
// GOOD: Each function is independently mockable
|
|
43
|
-
const api = {
|
|
44
|
-
getUser: (id) => fetch(`/users/${id}`),
|
|
45
|
-
getOrders: (userId) => fetch(`/users/${userId}/orders`),
|
|
46
|
-
createOrder: (data) => fetch('/orders', { method: 'POST', body: data }),
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// BAD: Mocking requires conditional logic inside the mock
|
|
50
|
-
const api = {
|
|
51
|
-
fetch: (endpoint, options) => fetch(endpoint, options),
|
|
52
|
-
};
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
The SDK approach means:
|
|
56
|
-
- Each mock returns one specific shape
|
|
57
|
-
- No conditional logic in test setup
|
|
58
|
-
- Easier to see which endpoints a test exercises
|
|
59
|
-
- Type safety per endpoint
|
|
1
|
+
# When to Mock
|
|
2
|
+
|
|
3
|
+
Mock at **system boundaries** only:
|
|
4
|
+
|
|
5
|
+
- External APIs (payment, email, etc.)
|
|
6
|
+
- Databases (sometimes - prefer test DB)
|
|
7
|
+
- Time/randomness
|
|
8
|
+
- File system (sometimes)
|
|
9
|
+
|
|
10
|
+
Don't mock:
|
|
11
|
+
|
|
12
|
+
- Your own classes/modules
|
|
13
|
+
- Internal collaborators
|
|
14
|
+
- Anything you control
|
|
15
|
+
|
|
16
|
+
## Designing for Mockability
|
|
17
|
+
|
|
18
|
+
At system boundaries, design interfaces that are easy to mock:
|
|
19
|
+
|
|
20
|
+
**1. Use dependency injection**
|
|
21
|
+
|
|
22
|
+
Pass external dependencies in rather than creating them internally:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// Easy to mock
|
|
26
|
+
function processPayment(order, paymentClient) {
|
|
27
|
+
return paymentClient.charge(order.total);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Hard to mock
|
|
31
|
+
function processPayment(order) {
|
|
32
|
+
const client = new StripeClient(process.env.STRIPE_KEY);
|
|
33
|
+
return client.charge(order.total);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**2. Prefer SDK-style interfaces over generic fetchers**
|
|
38
|
+
|
|
39
|
+
Create specific functions for each external operation instead of one generic function with conditional logic:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// GOOD: Each function is independently mockable
|
|
43
|
+
const api = {
|
|
44
|
+
getUser: (id) => fetch(`/users/${id}`),
|
|
45
|
+
getOrders: (userId) => fetch(`/users/${userId}/orders`),
|
|
46
|
+
createOrder: (data) => fetch('/orders', { method: 'POST', body: data }),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// BAD: Mocking requires conditional logic inside the mock
|
|
50
|
+
const api = {
|
|
51
|
+
fetch: (endpoint, options) => fetch(endpoint, options),
|
|
52
|
+
};
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The SDK approach means:
|
|
56
|
+
- Each mock returns one specific shape
|
|
57
|
+
- No conditional logic in test setup
|
|
58
|
+
- Easier to see which endpoints a test exercises
|
|
59
|
+
- Type safety per endpoint
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# Refactor Candidates
|
|
2
|
-
|
|
3
|
-
After TDD cycle, look for:
|
|
4
|
-
|
|
5
|
-
- **Duplication** → Extract function/class
|
|
6
|
-
- **Long methods** → Break into private helpers (keep tests on public interface)
|
|
7
|
-
- **Shallow modules** → Combine or deepen
|
|
8
|
-
- **Feature envy** → Move logic to where data lives
|
|
9
|
-
- **Primitive obsession** → Introduce value objects
|
|
10
|
-
- **Existing code** the new code reveals as problematic
|
|
1
|
+
# Refactor Candidates
|
|
2
|
+
|
|
3
|
+
After TDD cycle, look for:
|
|
4
|
+
|
|
5
|
+
- **Duplication** → Extract function/class
|
|
6
|
+
- **Long methods** → Break into private helpers (keep tests on public interface)
|
|
7
|
+
- **Shallow modules** → Combine or deepen
|
|
8
|
+
- **Feature envy** → Move logic to where data lives
|
|
9
|
+
- **Primitive obsession** → Introduce value objects
|
|
10
|
+
- **Existing code** the new code reveals as problematic
|