@booklib/core 2.0.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/.cursor/rules/booklib-standards.mdc +40 -0
- package/.gemini/context.md +372 -0
- package/AGENTS.md +166 -0
- package/CHANGELOG.md +226 -0
- package/CLAUDE.md +81 -0
- package/CODE_OF_CONDUCT.md +31 -0
- package/CONTRIBUTING.md +304 -0
- package/LICENSE +21 -0
- package/PLAN.md +28 -0
- package/README.ja.md +198 -0
- package/README.ko.md +198 -0
- package/README.md +503 -0
- package/README.pt-BR.md +198 -0
- package/README.uk.md +241 -0
- package/README.zh-CN.md +198 -0
- package/SECURITY.md +9 -0
- package/agents/architecture-reviewer.md +136 -0
- package/agents/booklib-reviewer.md +90 -0
- package/agents/data-reviewer.md +107 -0
- package/agents/jvm-reviewer.md +146 -0
- package/agents/python-reviewer.md +128 -0
- package/agents/rust-reviewer.md +115 -0
- package/agents/ts-reviewer.md +110 -0
- package/agents/ui-reviewer.md +117 -0
- package/assets/logo.svg +36 -0
- package/bin/booklib-mcp.js +304 -0
- package/bin/booklib.js +1705 -0
- package/bin/skills.cjs +1292 -0
- package/booklib-router.mdc +36 -0
- package/booklib.config.json +19 -0
- package/commands/animation-at-work.md +10 -0
- package/commands/clean-code-reviewer.md +10 -0
- package/commands/data-intensive-patterns.md +10 -0
- package/commands/data-pipelines.md +10 -0
- package/commands/design-patterns.md +10 -0
- package/commands/domain-driven-design.md +10 -0
- package/commands/effective-java.md +10 -0
- package/commands/effective-kotlin.md +10 -0
- package/commands/effective-python.md +10 -0
- package/commands/effective-typescript.md +10 -0
- package/commands/kotlin-in-action.md +10 -0
- package/commands/lean-startup.md +10 -0
- package/commands/microservices-patterns.md +10 -0
- package/commands/programming-with-rust.md +10 -0
- package/commands/refactoring-ui.md +10 -0
- package/commands/rust-in-action.md +10 -0
- package/commands/skill-router.md +10 -0
- package/commands/spring-boot-in-action.md +10 -0
- package/commands/storytelling-with-data.md +10 -0
- package/commands/system-design-interview.md +10 -0
- package/commands/using-asyncio-python.md +10 -0
- package/commands/web-scraping-python.md +10 -0
- package/community/registry.json +1616 -0
- package/hooks/hooks.json +23 -0
- package/hooks/posttooluse-capture.mjs +67 -0
- package/hooks/suggest.js +153 -0
- package/lib/agent-behaviors.js +40 -0
- package/lib/agent-detector.js +96 -0
- package/lib/config-loader.js +39 -0
- package/lib/conflict-resolver.js +148 -0
- package/lib/context-builder.js +574 -0
- package/lib/discovery-engine.js +298 -0
- package/lib/doctor/hook-installer.js +83 -0
- package/lib/doctor/usage-tracker.js +87 -0
- package/lib/engine/ai-features.js +253 -0
- package/lib/engine/auditor.js +103 -0
- package/lib/engine/bm25-index.js +178 -0
- package/lib/engine/capture.js +120 -0
- package/lib/engine/corrections.js +198 -0
- package/lib/engine/doctor.js +195 -0
- package/lib/engine/graph-injector.js +137 -0
- package/lib/engine/graph.js +161 -0
- package/lib/engine/handoff.js +405 -0
- package/lib/engine/indexer.js +242 -0
- package/lib/engine/parser.js +53 -0
- package/lib/engine/query-expander.js +42 -0
- package/lib/engine/reranker.js +40 -0
- package/lib/engine/rrf.js +59 -0
- package/lib/engine/scanner.js +151 -0
- package/lib/engine/searcher.js +139 -0
- package/lib/engine/session-coordinator.js +306 -0
- package/lib/engine/session-manager.js +429 -0
- package/lib/engine/synthesizer.js +70 -0
- package/lib/installer.js +70 -0
- package/lib/instinct-block.js +33 -0
- package/lib/mcp-config-writer.js +88 -0
- package/lib/paths.js +57 -0
- package/lib/profiles/design.md +19 -0
- package/lib/profiles/general.md +16 -0
- package/lib/profiles/research-analysis.md +22 -0
- package/lib/profiles/software-development.md +23 -0
- package/lib/profiles/writing-content.md +19 -0
- package/lib/project-initializer.js +916 -0
- package/lib/registry/skills.js +102 -0
- package/lib/registry-searcher.js +99 -0
- package/lib/rules/rules-manager.js +169 -0
- package/lib/skill-fetcher.js +333 -0
- package/lib/well-known-builder.js +70 -0
- package/lib/wizard/index.js +404 -0
- package/lib/wizard/integration-detector.js +41 -0
- package/lib/wizard/project-detector.js +100 -0
- package/lib/wizard/prompt.js +156 -0
- package/lib/wizard/registry-embeddings.js +107 -0
- package/lib/wizard/skill-recommender.js +69 -0
- package/llms-full.txt +254 -0
- package/llms.txt +70 -0
- package/package.json +45 -0
- package/research-reports/2026-04-01-current-architecture.md +160 -0
- package/research-reports/IDEAS.md +93 -0
- package/rules/common/clean-code.md +42 -0
- package/rules/java/effective-java.md +42 -0
- package/rules/kotlin/effective-kotlin.md +37 -0
- package/rules/python/effective-python.md +38 -0
- package/rules/rust/rust.md +37 -0
- package/rules/typescript/effective-typescript.md +42 -0
- package/scripts/gen-llms-full.mjs +36 -0
- package/scripts/gen-og.mjs +142 -0
- package/scripts/validate-frontmatter.js +25 -0
- package/skills/animation-at-work/SKILL.md +270 -0
- package/skills/animation-at-work/assets/example_asset.txt +1 -0
- package/skills/animation-at-work/evals/evals.json +44 -0
- package/skills/animation-at-work/evals/results.json +13 -0
- package/skills/animation-at-work/examples/after.md +64 -0
- package/skills/animation-at-work/examples/before.md +35 -0
- package/skills/animation-at-work/references/api_reference.md +369 -0
- package/skills/animation-at-work/references/review-checklist.md +79 -0
- package/skills/animation-at-work/scripts/audit_animations.py +295 -0
- package/skills/animation-at-work/scripts/example.py +1 -0
- package/skills/clean-code-reviewer/SKILL.md +444 -0
- package/skills/clean-code-reviewer/audit.json +35 -0
- package/skills/clean-code-reviewer/evals/evals.json +185 -0
- package/skills/clean-code-reviewer/evals/results.json +13 -0
- package/skills/clean-code-reviewer/examples/after.md +48 -0
- package/skills/clean-code-reviewer/examples/before.md +33 -0
- package/skills/clean-code-reviewer/references/api_reference.md +158 -0
- package/skills/clean-code-reviewer/references/practices-catalog.md +282 -0
- package/skills/clean-code-reviewer/references/review-checklist.md +254 -0
- package/skills/clean-code-reviewer/scripts/pre-review.py +206 -0
- package/skills/data-intensive-patterns/SKILL.md +267 -0
- package/skills/data-intensive-patterns/assets/example_asset.txt +1 -0
- package/skills/data-intensive-patterns/evals/evals.json +54 -0
- package/skills/data-intensive-patterns/evals/results.json +13 -0
- package/skills/data-intensive-patterns/examples/after.md +61 -0
- package/skills/data-intensive-patterns/examples/before.md +38 -0
- package/skills/data-intensive-patterns/references/api_reference.md +34 -0
- package/skills/data-intensive-patterns/references/patterns-catalog.md +551 -0
- package/skills/data-intensive-patterns/references/review-checklist.md +193 -0
- package/skills/data-intensive-patterns/scripts/adr.py +213 -0
- package/skills/data-intensive-patterns/scripts/example.py +1 -0
- package/skills/data-pipelines/SKILL.md +259 -0
- package/skills/data-pipelines/assets/example_asset.txt +1 -0
- package/skills/data-pipelines/evals/evals.json +45 -0
- package/skills/data-pipelines/evals/results.json +13 -0
- package/skills/data-pipelines/examples/after.md +97 -0
- package/skills/data-pipelines/examples/before.md +37 -0
- package/skills/data-pipelines/references/api_reference.md +301 -0
- package/skills/data-pipelines/references/review-checklist.md +181 -0
- package/skills/data-pipelines/scripts/example.py +1 -0
- package/skills/data-pipelines/scripts/new_pipeline.py +444 -0
- package/skills/design-patterns/SKILL.md +271 -0
- package/skills/design-patterns/assets/example_asset.txt +1 -0
- package/skills/design-patterns/evals/evals.json +46 -0
- package/skills/design-patterns/evals/results.json +13 -0
- package/skills/design-patterns/examples/after.md +52 -0
- package/skills/design-patterns/examples/before.md +29 -0
- package/skills/design-patterns/references/api_reference.md +1 -0
- package/skills/design-patterns/references/patterns-catalog.md +726 -0
- package/skills/design-patterns/references/review-checklist.md +173 -0
- package/skills/design-patterns/scripts/example.py +1 -0
- package/skills/design-patterns/scripts/scaffold.py +807 -0
- package/skills/domain-driven-design/SKILL.md +142 -0
- package/skills/domain-driven-design/assets/example_asset.txt +1 -0
- package/skills/domain-driven-design/evals/evals.json +48 -0
- package/skills/domain-driven-design/evals/results.json +13 -0
- package/skills/domain-driven-design/examples/after.md +80 -0
- package/skills/domain-driven-design/examples/before.md +43 -0
- package/skills/domain-driven-design/references/api_reference.md +1 -0
- package/skills/domain-driven-design/references/patterns-catalog.md +545 -0
- package/skills/domain-driven-design/references/review-checklist.md +158 -0
- package/skills/domain-driven-design/scripts/example.py +1 -0
- package/skills/domain-driven-design/scripts/scaffold.py +421 -0
- package/skills/effective-java/SKILL.md +227 -0
- package/skills/effective-java/assets/example_asset.txt +1 -0
- package/skills/effective-java/evals/evals.json +46 -0
- package/skills/effective-java/evals/results.json +13 -0
- package/skills/effective-java/examples/after.md +83 -0
- package/skills/effective-java/examples/before.md +37 -0
- package/skills/effective-java/references/api_reference.md +1 -0
- package/skills/effective-java/references/items-catalog.md +955 -0
- package/skills/effective-java/references/review-checklist.md +216 -0
- package/skills/effective-java/scripts/checkstyle_setup.py +211 -0
- package/skills/effective-java/scripts/example.py +1 -0
- package/skills/effective-kotlin/SKILL.md +271 -0
- package/skills/effective-kotlin/assets/example_asset.txt +1 -0
- package/skills/effective-kotlin/audit.json +29 -0
- package/skills/effective-kotlin/evals/evals.json +45 -0
- package/skills/effective-kotlin/evals/results.json +13 -0
- package/skills/effective-kotlin/examples/after.md +36 -0
- package/skills/effective-kotlin/examples/before.md +38 -0
- package/skills/effective-kotlin/references/api_reference.md +1 -0
- package/skills/effective-kotlin/references/practices-catalog.md +1228 -0
- package/skills/effective-kotlin/references/review-checklist.md +126 -0
- package/skills/effective-kotlin/scripts/example.py +1 -0
- package/skills/effective-python/SKILL.md +441 -0
- package/skills/effective-python/evals/evals.json +44 -0
- package/skills/effective-python/evals/results.json +13 -0
- package/skills/effective-python/examples/after.md +56 -0
- package/skills/effective-python/examples/before.md +40 -0
- package/skills/effective-python/ref-01-pythonic-thinking.md +202 -0
- package/skills/effective-python/ref-02-lists-and-dicts.md +146 -0
- package/skills/effective-python/ref-03-functions.md +186 -0
- package/skills/effective-python/ref-04-comprehensions-generators.md +211 -0
- package/skills/effective-python/ref-05-classes-interfaces.md +188 -0
- package/skills/effective-python/ref-06-metaclasses-attributes.md +209 -0
- package/skills/effective-python/ref-07-concurrency.md +213 -0
- package/skills/effective-python/ref-08-robustness-performance.md +248 -0
- package/skills/effective-python/ref-09-testing-debugging.md +253 -0
- package/skills/effective-python/ref-10-collaboration.md +175 -0
- package/skills/effective-python/references/api_reference.md +218 -0
- package/skills/effective-python/references/practices-catalog.md +483 -0
- package/skills/effective-python/references/review-checklist.md +190 -0
- package/skills/effective-python/scripts/lint.py +173 -0
- package/skills/effective-typescript/SKILL.md +262 -0
- package/skills/effective-typescript/audit.json +29 -0
- package/skills/effective-typescript/evals/evals.json +37 -0
- package/skills/effective-typescript/evals/results.json +13 -0
- package/skills/effective-typescript/examples/after.md +70 -0
- package/skills/effective-typescript/examples/before.md +47 -0
- package/skills/effective-typescript/references/api_reference.md +118 -0
- package/skills/effective-typescript/references/practices-catalog.md +371 -0
- package/skills/effective-typescript/scripts/review.py +169 -0
- package/skills/kotlin-in-action/SKILL.md +261 -0
- package/skills/kotlin-in-action/assets/example_asset.txt +1 -0
- package/skills/kotlin-in-action/evals/evals.json +43 -0
- package/skills/kotlin-in-action/evals/results.json +13 -0
- package/skills/kotlin-in-action/examples/after.md +53 -0
- package/skills/kotlin-in-action/examples/before.md +39 -0
- package/skills/kotlin-in-action/references/api_reference.md +1 -0
- package/skills/kotlin-in-action/references/practices-catalog.md +436 -0
- package/skills/kotlin-in-action/references/review-checklist.md +204 -0
- package/skills/kotlin-in-action/scripts/example.py +1 -0
- package/skills/kotlin-in-action/scripts/setup_detekt.py +224 -0
- package/skills/lean-startup/SKILL.md +160 -0
- package/skills/lean-startup/assets/example_asset.txt +1 -0
- package/skills/lean-startup/evals/evals.json +43 -0
- package/skills/lean-startup/evals/results.json +13 -0
- package/skills/lean-startup/examples/after.md +80 -0
- package/skills/lean-startup/examples/before.md +34 -0
- package/skills/lean-startup/references/api_reference.md +319 -0
- package/skills/lean-startup/references/review-checklist.md +137 -0
- package/skills/lean-startup/scripts/example.py +1 -0
- package/skills/lean-startup/scripts/new_experiment.py +286 -0
- package/skills/microservices-patterns/SKILL.md +384 -0
- package/skills/microservices-patterns/evals/evals.json +45 -0
- package/skills/microservices-patterns/evals/results.json +13 -0
- package/skills/microservices-patterns/examples/after.md +69 -0
- package/skills/microservices-patterns/examples/before.md +40 -0
- package/skills/microservices-patterns/references/patterns-catalog.md +391 -0
- package/skills/microservices-patterns/references/review-checklist.md +169 -0
- package/skills/microservices-patterns/scripts/new_service.py +583 -0
- package/skills/programming-with-rust/SKILL.md +209 -0
- package/skills/programming-with-rust/evals/evals.json +37 -0
- package/skills/programming-with-rust/evals/results.json +13 -0
- package/skills/programming-with-rust/examples/after.md +107 -0
- package/skills/programming-with-rust/examples/before.md +59 -0
- package/skills/programming-with-rust/references/api_reference.md +152 -0
- package/skills/programming-with-rust/references/practices-catalog.md +335 -0
- package/skills/programming-with-rust/scripts/review.py +142 -0
- package/skills/refactoring-ui/SKILL.md +362 -0
- package/skills/refactoring-ui/assets/example_asset.txt +1 -0
- package/skills/refactoring-ui/evals/evals.json +45 -0
- package/skills/refactoring-ui/evals/results.json +13 -0
- package/skills/refactoring-ui/examples/after.md +85 -0
- package/skills/refactoring-ui/examples/before.md +58 -0
- package/skills/refactoring-ui/references/api_reference.md +355 -0
- package/skills/refactoring-ui/references/review-checklist.md +114 -0
- package/skills/refactoring-ui/scripts/audit_css.py +250 -0
- package/skills/refactoring-ui/scripts/example.py +1 -0
- package/skills/rust-in-action/SKILL.md +350 -0
- package/skills/rust-in-action/evals/evals.json +38 -0
- package/skills/rust-in-action/evals/results.json +13 -0
- package/skills/rust-in-action/examples/after.md +156 -0
- package/skills/rust-in-action/examples/before.md +56 -0
- package/skills/rust-in-action/references/practices-catalog.md +346 -0
- package/skills/rust-in-action/scripts/review.py +147 -0
- package/skills/skill-router/SKILL.md +186 -0
- package/skills/skill-router/evals/evals.json +38 -0
- package/skills/skill-router/evals/results.json +13 -0
- package/skills/skill-router/examples/after.md +63 -0
- package/skills/skill-router/examples/before.md +39 -0
- package/skills/skill-router/references/api_reference.md +24 -0
- package/skills/skill-router/references/routing-heuristics.md +89 -0
- package/skills/skill-router/references/skill-catalog.md +174 -0
- package/skills/skill-router/scripts/route.py +266 -0
- package/skills/spring-boot-in-action/SKILL.md +340 -0
- package/skills/spring-boot-in-action/evals/evals.json +39 -0
- package/skills/spring-boot-in-action/evals/results.json +13 -0
- package/skills/spring-boot-in-action/examples/after.md +185 -0
- package/skills/spring-boot-in-action/examples/before.md +84 -0
- package/skills/spring-boot-in-action/references/practices-catalog.md +403 -0
- package/skills/spring-boot-in-action/scripts/review.py +184 -0
- package/skills/storytelling-with-data/SKILL.md +241 -0
- package/skills/storytelling-with-data/assets/example_asset.txt +1 -0
- package/skills/storytelling-with-data/evals/evals.json +47 -0
- package/skills/storytelling-with-data/evals/results.json +13 -0
- package/skills/storytelling-with-data/examples/after.md +50 -0
- package/skills/storytelling-with-data/examples/before.md +33 -0
- package/skills/storytelling-with-data/references/api_reference.md +379 -0
- package/skills/storytelling-with-data/references/review-checklist.md +111 -0
- package/skills/storytelling-with-data/scripts/chart_review.py +301 -0
- package/skills/storytelling-with-data/scripts/example.py +1 -0
- package/skills/system-design-interview/SKILL.md +233 -0
- package/skills/system-design-interview/assets/example_asset.txt +1 -0
- package/skills/system-design-interview/evals/evals.json +46 -0
- package/skills/system-design-interview/evals/results.json +13 -0
- package/skills/system-design-interview/examples/after.md +94 -0
- package/skills/system-design-interview/examples/before.md +27 -0
- package/skills/system-design-interview/references/api_reference.md +582 -0
- package/skills/system-design-interview/references/review-checklist.md +201 -0
- package/skills/system-design-interview/scripts/example.py +1 -0
- package/skills/system-design-interview/scripts/new_design.py +421 -0
- package/skills/using-asyncio-python/SKILL.md +290 -0
- package/skills/using-asyncio-python/assets/example_asset.txt +1 -0
- package/skills/using-asyncio-python/evals/evals.json +43 -0
- package/skills/using-asyncio-python/evals/results.json +13 -0
- package/skills/using-asyncio-python/examples/after.md +68 -0
- package/skills/using-asyncio-python/examples/before.md +39 -0
- package/skills/using-asyncio-python/references/api_reference.md +267 -0
- package/skills/using-asyncio-python/references/review-checklist.md +149 -0
- package/skills/using-asyncio-python/scripts/check_blocking.py +270 -0
- package/skills/using-asyncio-python/scripts/example.py +1 -0
- package/skills/web-scraping-python/SKILL.md +280 -0
- package/skills/web-scraping-python/assets/example_asset.txt +1 -0
- package/skills/web-scraping-python/evals/evals.json +46 -0
- package/skills/web-scraping-python/evals/results.json +13 -0
- package/skills/web-scraping-python/examples/after.md +109 -0
- package/skills/web-scraping-python/examples/before.md +40 -0
- package/skills/web-scraping-python/references/api_reference.md +393 -0
- package/skills/web-scraping-python/references/review-checklist.md +163 -0
- package/skills/web-scraping-python/scripts/example.py +1 -0
- package/skills/web-scraping-python/scripts/new_scraper.py +231 -0
- package/skills/writing-plans/audit.json +34 -0
- package/tests/agent-detector.test.js +83 -0
- package/tests/corrections.test.js +245 -0
- package/tests/doctor/hook-installer.test.js +72 -0
- package/tests/doctor/usage-tracker.test.js +140 -0
- package/tests/engine/benchmark-eval.test.js +31 -0
- package/tests/engine/bm25-index.test.js +85 -0
- package/tests/engine/capture-command.test.js +35 -0
- package/tests/engine/capture.test.js +17 -0
- package/tests/engine/graph-augmented-search.test.js +107 -0
- package/tests/engine/graph-injector.test.js +44 -0
- package/tests/engine/graph.test.js +216 -0
- package/tests/engine/hybrid-searcher.test.js +74 -0
- package/tests/engine/indexer-bm25.test.js +37 -0
- package/tests/engine/mcp-tools.test.js +73 -0
- package/tests/engine/project-initializer-mcp.test.js +99 -0
- package/tests/engine/query-expander.test.js +36 -0
- package/tests/engine/reranker.test.js +51 -0
- package/tests/engine/rrf.test.js +49 -0
- package/tests/engine/srag-prefix.test.js +47 -0
- package/tests/instinct-block.test.js +23 -0
- package/tests/mcp-config-writer.test.js +60 -0
- package/tests/project-initializer-new-agents.test.js +48 -0
- package/tests/rules/rules-manager.test.js +230 -0
- package/tests/well-known-builder.test.js +40 -0
- package/tests/wizard/integration-detector.test.js +31 -0
- package/tests/wizard/project-detector.test.js +51 -0
- package/tests/wizard/prompt-session.test.js +61 -0
- package/tests/wizard/prompt.test.js +16 -0
- package/tests/wizard/registry-embeddings.test.js +35 -0
- package/tests/wizard/skill-recommender.test.js +34 -0
- package/tests/wizard/slot-count.test.js +25 -0
- package/vercel.json +21 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
chart_review.py - Review a chart specification against Storytelling with Data principles.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python chart_review.py <spec-file.json>
|
|
7
|
+
|
|
8
|
+
Spec file format (JSON):
|
|
9
|
+
{
|
|
10
|
+
"title": "Sales by Region Q4",
|
|
11
|
+
"chart_type": "pie",
|
|
12
|
+
"data_points": 8,
|
|
13
|
+
"colors": ["#ff0000", "#00ff00"],
|
|
14
|
+
"has_gridlines": true,
|
|
15
|
+
"has_legend": true,
|
|
16
|
+
"has_direct_labels": false,
|
|
17
|
+
"is_3d": false,
|
|
18
|
+
"y_axis_starts_at_zero": true
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
All fields are optional. Unrecognised fields are ignored.
|
|
22
|
+
|
|
23
|
+
Based on "Storytelling with Data" by Cole Nussbaumer Knaflic.
|
|
24
|
+
Each finding references the relevant chapter.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import argparse
|
|
28
|
+
import json
|
|
29
|
+
import pathlib
|
|
30
|
+
import sys
|
|
31
|
+
from typing import Any
|
|
32
|
+
|
|
33
|
+
# Severity ordering for output
|
|
34
|
+
PRIORITY_ORDER = {"HIGH": 0, "MEDIUM": 1, "LOW": 2}
|
|
35
|
+
|
|
36
|
+
CHART_TYPE_ALIASES: dict[str, str] = {
|
|
37
|
+
"pie": "pie",
|
|
38
|
+
"donut": "pie",
|
|
39
|
+
"doughnut": "pie",
|
|
40
|
+
"bar": "bar",
|
|
41
|
+
"column": "bar",
|
|
42
|
+
"horizontal bar": "bar",
|
|
43
|
+
"stacked bar": "bar",
|
|
44
|
+
"line": "line",
|
|
45
|
+
"area": "line",
|
|
46
|
+
"scatter": "scatter",
|
|
47
|
+
"bubble": "scatter",
|
|
48
|
+
"table": "table",
|
|
49
|
+
"heatmap": "table",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Action verbs that indicate a title states a finding rather than just labelling axes.
|
|
53
|
+
INSIGHT_VERBS = {
|
|
54
|
+
"grew", "declined", "increased", "decreased", "outperformed", "underperformed",
|
|
55
|
+
"surpassed", "dropped", "rose", "fell", "exceeded", "missed", "reached",
|
|
56
|
+
"shows", "reveals", "demonstrates", "highlights", "indicates", "confirms",
|
|
57
|
+
"beats", "lags", "leads", "trails", "spikes", "dips",
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def load_spec(path: pathlib.Path) -> dict[str, Any]:
|
|
62
|
+
try:
|
|
63
|
+
text = path.read_text(encoding="utf-8")
|
|
64
|
+
except OSError as exc:
|
|
65
|
+
print(f"ERROR: Cannot read file: {exc}")
|
|
66
|
+
sys.exit(1)
|
|
67
|
+
try:
|
|
68
|
+
return json.loads(text)
|
|
69
|
+
except json.JSONDecodeError as exc:
|
|
70
|
+
print(f"ERROR: Invalid JSON in {path}: {exc}")
|
|
71
|
+
sys.exit(1)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def normalize_chart_type(raw: str) -> str:
|
|
75
|
+
return CHART_TYPE_ALIASES.get(raw.lower().strip(), raw.lower().strip())
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def title_is_action_oriented(title: str) -> bool:
|
|
79
|
+
"""Return True if the title starts with or contains an insight verb."""
|
|
80
|
+
first_word = title.strip().split()[0].lower().rstrip(".,;:") if title.strip() else ""
|
|
81
|
+
if first_word in INSIGHT_VERBS:
|
|
82
|
+
return True
|
|
83
|
+
# Also accept titles where an insight verb appears early (within first 4 words)
|
|
84
|
+
words = [w.lower().rstrip(".,;:") for w in title.strip().split()[:4]]
|
|
85
|
+
return any(w in INSIGHT_VERBS for w in words)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def check_spec(spec: dict[str, Any]) -> list[dict[str, str]]:
|
|
89
|
+
findings: list[dict[str, str]] = []
|
|
90
|
+
|
|
91
|
+
def add(priority: str, chapter: str, principle: str, detail: str, recommendation: str) -> None:
|
|
92
|
+
findings.append({
|
|
93
|
+
"priority": priority,
|
|
94
|
+
"chapter": chapter,
|
|
95
|
+
"principle": principle,
|
|
96
|
+
"detail": detail,
|
|
97
|
+
"recommendation": recommendation,
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
chart_type_raw = spec.get("chart_type", "")
|
|
101
|
+
chart_type = normalize_chart_type(chart_type_raw) if chart_type_raw else ""
|
|
102
|
+
data_points = spec.get("data_points")
|
|
103
|
+
colors = spec.get("colors", [])
|
|
104
|
+
has_gridlines = spec.get("has_gridlines", False)
|
|
105
|
+
has_legend = spec.get("has_legend", False)
|
|
106
|
+
has_direct_labels = spec.get("has_direct_labels", False)
|
|
107
|
+
is_3d = spec.get("is_3d", False)
|
|
108
|
+
y_axis_zero = spec.get("y_axis_starts_at_zero", True)
|
|
109
|
+
title = spec.get("title", "")
|
|
110
|
+
|
|
111
|
+
# Check 1: Pie charts with more than 4 slices
|
|
112
|
+
if chart_type == "pie" and data_points is not None and data_points > 4:
|
|
113
|
+
add(
|
|
114
|
+
priority="HIGH",
|
|
115
|
+
chapter="Chapter 2 - Choosing an Effective Visual",
|
|
116
|
+
principle="Avoid pie charts with many slices",
|
|
117
|
+
detail=f"Pie chart has {data_points} slices. Humans cannot accurately compare non-adjacent arc lengths.",
|
|
118
|
+
recommendation=(
|
|
119
|
+
"Use a horizontal bar chart sorted by value. "
|
|
120
|
+
"Bars make magnitude comparison trivial and scale to many categories."
|
|
121
|
+
),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Check 2: More than 5 colors
|
|
125
|
+
if len(colors) > 5:
|
|
126
|
+
add(
|
|
127
|
+
priority="HIGH",
|
|
128
|
+
chapter="Chapter 4 - Focus Your Audience's Attention",
|
|
129
|
+
principle="Use color strategically, not decoratively",
|
|
130
|
+
detail=f"{len(colors)} colors used. More than 5 colors overwhelm the eye and dilute emphasis.",
|
|
131
|
+
recommendation=(
|
|
132
|
+
"Grey out all categories except the one(s) you want to highlight. "
|
|
133
|
+
"Use a single accent color to draw the eye to the key insight."
|
|
134
|
+
),
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Check 3: Gridlines present
|
|
138
|
+
if has_gridlines:
|
|
139
|
+
add(
|
|
140
|
+
priority="MEDIUM",
|
|
141
|
+
chapter="Chapter 3 - Clutter Is Your Enemy",
|
|
142
|
+
principle="Remove chart junk and non-data ink",
|
|
143
|
+
detail="Gridlines are present. They add visual noise without adding information.",
|
|
144
|
+
recommendation=(
|
|
145
|
+
"Remove gridlines entirely, or replace with light grey (#e0e0e0) hairlines. "
|
|
146
|
+
"If reference values matter, use direct annotations on the data instead."
|
|
147
|
+
),
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# Check 4: Legend without direct labels
|
|
151
|
+
if has_legend and not has_direct_labels:
|
|
152
|
+
add(
|
|
153
|
+
priority="MEDIUM",
|
|
154
|
+
chapter="Chapter 5 - Think Like a Designer",
|
|
155
|
+
principle="Label data directly to reduce cognitive load",
|
|
156
|
+
detail=(
|
|
157
|
+
"A legend forces the reader to look away from the data to decode colors. "
|
|
158
|
+
"This interrupts the reading flow."
|
|
159
|
+
),
|
|
160
|
+
recommendation=(
|
|
161
|
+
"Place labels directly next to each data series or bar. "
|
|
162
|
+
"Remove the legend. Direct labelling reduces eye travel and speeds comprehension."
|
|
163
|
+
),
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
# Check 5: 3D charts
|
|
167
|
+
if is_3d:
|
|
168
|
+
add(
|
|
169
|
+
priority="HIGH",
|
|
170
|
+
chapter="Chapter 2 - Choosing an Effective Visual",
|
|
171
|
+
principle="Never use 3D visualisations",
|
|
172
|
+
detail=(
|
|
173
|
+
"3D perspective distorts relative bar/slice sizes due to foreshortening. "
|
|
174
|
+
"Viewers cannot accurately read values from a 3D chart."
|
|
175
|
+
),
|
|
176
|
+
recommendation=(
|
|
177
|
+
"Switch to a flat 2D version of the same chart type. "
|
|
178
|
+
"If depth is meant to encode a third variable, use facets or bubble size instead."
|
|
179
|
+
),
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Check 6: Title not action-oriented
|
|
183
|
+
if title:
|
|
184
|
+
if not title_is_action_oriented(title):
|
|
185
|
+
add(
|
|
186
|
+
priority="LOW",
|
|
187
|
+
chapter="Chapter 6 - Dissecting Model Visuals",
|
|
188
|
+
principle="Title should state the insight, not label the axes",
|
|
189
|
+
detail=(
|
|
190
|
+
f"Title '{title}' describes what the chart shows but does not communicate "
|
|
191
|
+
"the key takeaway. Readers must infer the insight themselves."
|
|
192
|
+
),
|
|
193
|
+
recommendation=(
|
|
194
|
+
"Rewrite the title as a one-sentence finding: e.g., "
|
|
195
|
+
"'APAC revenue grew 34% year-over-year, outpacing all other regions.' "
|
|
196
|
+
"This tells readers what to think before they look at the data."
|
|
197
|
+
),
|
|
198
|
+
)
|
|
199
|
+
else:
|
|
200
|
+
add(
|
|
201
|
+
priority="MEDIUM",
|
|
202
|
+
chapter="Chapter 6 - Dissecting Model Visuals",
|
|
203
|
+
principle="Every chart needs a title",
|
|
204
|
+
detail="No title field found in the spec. Untitled charts require readers to form their own interpretation.",
|
|
205
|
+
recommendation=(
|
|
206
|
+
"Add a descriptive, insight-oriented title that states the key finding directly."
|
|
207
|
+
),
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
# Check 7: Bar chart not starting at zero
|
|
211
|
+
if chart_type == "bar" and y_axis_zero is False:
|
|
212
|
+
add(
|
|
213
|
+
priority="HIGH",
|
|
214
|
+
chapter="Chapter 2 - Choosing an Effective Visual",
|
|
215
|
+
principle="Bar charts must start at zero",
|
|
216
|
+
detail=(
|
|
217
|
+
"The y-axis does not start at zero. Because bar length encodes value, "
|
|
218
|
+
"a truncated axis makes small differences appear dramatically large."
|
|
219
|
+
),
|
|
220
|
+
recommendation=(
|
|
221
|
+
"Set the y-axis baseline to zero. "
|
|
222
|
+
"If the differences are genuinely small, switch to a line chart, "
|
|
223
|
+
"which does not rely on bar length to encode magnitude."
|
|
224
|
+
),
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# Check 8: Pie chart for proportional data — general advisory
|
|
228
|
+
if chart_type == "pie":
|
|
229
|
+
add(
|
|
230
|
+
priority="LOW",
|
|
231
|
+
chapter="Chapter 2 - Choosing an Effective Visual",
|
|
232
|
+
principle="Pie charts are rarely the best choice",
|
|
233
|
+
detail=(
|
|
234
|
+
"Even well-formed pie charts are harder to read than bar charts "
|
|
235
|
+
"because humans are poor at judging angles and arc lengths."
|
|
236
|
+
),
|
|
237
|
+
recommendation=(
|
|
238
|
+
"Consider a single stacked bar (for part-to-whole) or a simple bar chart. "
|
|
239
|
+
"Use a pie only when: (a) there are 2-3 slices and (b) the exact proportions matter less than the part-to-whole story."
|
|
240
|
+
),
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
return findings
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def print_findings(findings: list[dict[str, str]]) -> None:
|
|
247
|
+
sorted_findings = sorted(findings, key=lambda f: PRIORITY_ORDER.get(f["priority"], 99))
|
|
248
|
+
|
|
249
|
+
if not sorted_findings:
|
|
250
|
+
print("No issues found. The chart spec looks good against Storytelling with Data principles.")
|
|
251
|
+
return
|
|
252
|
+
|
|
253
|
+
print(f"Found {len(sorted_findings)} issue(s):\n")
|
|
254
|
+
for i, finding in enumerate(sorted_findings, start=1):
|
|
255
|
+
priority = finding["priority"]
|
|
256
|
+
priority_display = f"[{priority}]"
|
|
257
|
+
print(f"{i}. {priority_display} {finding['principle']}")
|
|
258
|
+
print(f" Chapter : {finding['chapter']}")
|
|
259
|
+
print(f" Detail : {finding['detail']}")
|
|
260
|
+
print(f" Recommended : {finding['recommendation']}")
|
|
261
|
+
print()
|
|
262
|
+
|
|
263
|
+
counts = {"HIGH": 0, "MEDIUM": 0, "LOW": 0}
|
|
264
|
+
for f in findings:
|
|
265
|
+
counts[f["priority"]] = counts.get(f["priority"], 0) + 1
|
|
266
|
+
|
|
267
|
+
print("=" * 60)
|
|
268
|
+
print("PRIORITY SUMMARY")
|
|
269
|
+
print("=" * 60)
|
|
270
|
+
for level in ("HIGH", "MEDIUM", "LOW"):
|
|
271
|
+
if counts[level]:
|
|
272
|
+
print(f" {counts[level]:2d} {level}")
|
|
273
|
+
print(f" --")
|
|
274
|
+
print(f" {sum(counts.values()):2d} Total")
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def main() -> None:
|
|
278
|
+
parser = argparse.ArgumentParser(
|
|
279
|
+
description="Review a chart specification against Storytelling with Data principles."
|
|
280
|
+
)
|
|
281
|
+
parser.add_argument(
|
|
282
|
+
"spec_file",
|
|
283
|
+
help="Path to a JSON chart specification file.",
|
|
284
|
+
)
|
|
285
|
+
args = parser.parse_args()
|
|
286
|
+
|
|
287
|
+
spec_path = pathlib.Path(args.spec_file)
|
|
288
|
+
if not spec_path.exists():
|
|
289
|
+
print(f"ERROR: File not found: {spec_path}")
|
|
290
|
+
sys.exit(1)
|
|
291
|
+
|
|
292
|
+
spec = load_spec(spec_path)
|
|
293
|
+
findings = check_spec(spec)
|
|
294
|
+
print_findings(findings)
|
|
295
|
+
|
|
296
|
+
has_high = any(f["priority"] == "HIGH" for f in findings)
|
|
297
|
+
sys.exit(2 if has_high else (1 if findings else 0))
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
if __name__ == "__main__":
|
|
301
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: system-design-interview
|
|
3
|
+
version: "1.0"
|
|
4
|
+
license: MIT
|
|
5
|
+
tags: [architecture, distributed-systems, scalability]
|
|
6
|
+
description: >
|
|
7
|
+
Apply system design principles from System Design Interview by Alex Xu.
|
|
8
|
+
Covers scaling (load balancing, DB replication, sharding, caching, CDN),
|
|
9
|
+
estimation (QPS, storage, bandwidth), the 4-step framework, and 12 real
|
|
10
|
+
designs: rate limiter, consistent hashing, key-value store, unique ID
|
|
11
|
+
generator, URL shortener, web crawler, notification system, news feed,
|
|
12
|
+
chat system, search autocomplete, YouTube, Google Drive. Trigger on
|
|
13
|
+
"system design", "scale", "high-level design", "distributed system",
|
|
14
|
+
"rate limiter", "consistent hashing", "back-of-envelope", "QPS",
|
|
15
|
+
"sharding", "load balancer", "CDN", "cache", "message queue",
|
|
16
|
+
"web crawler", "news feed", "chat system", "autocomplete", "URL shortener".
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# System Design Interview Skill
|
|
20
|
+
|
|
21
|
+
You are an expert system design advisor grounded in the 16 chapters from
|
|
22
|
+
*System Design Interview* by Alex Xu. You help in two modes:
|
|
23
|
+
|
|
24
|
+
1. **Design Application** — Apply system design principles to architect solutions for real problems
|
|
25
|
+
2. **Design Review** — Analyze existing system architectures and recommend improvements
|
|
26
|
+
|
|
27
|
+
## How to Decide Which Mode
|
|
28
|
+
|
|
29
|
+
- If the user asks to *design*, *architect*, *build*, *scale*, or *plan* a system → **Design Application**
|
|
30
|
+
- If the user asks to *review*, *evaluate*, *audit*, *assess*, or *improve* an existing design → **Design Review**
|
|
31
|
+
- If ambiguous, ask briefly which mode they'd prefer
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Mode 1: Design Application
|
|
36
|
+
|
|
37
|
+
When helping design systems, follow this decision flow:
|
|
38
|
+
|
|
39
|
+
### Step 1 — Understand the Context
|
|
40
|
+
|
|
41
|
+
Ask (or infer from context):
|
|
42
|
+
|
|
43
|
+
- **What system?** — What type of system are we designing?
|
|
44
|
+
- **What scale?** — Expected users, QPS, storage, bandwidth?
|
|
45
|
+
- **What constraints?** — Latency requirements, availability target, cost budget?
|
|
46
|
+
- **What scope?** — Full system or specific component?
|
|
47
|
+
|
|
48
|
+
### Step 2 — Apply the 4-Step Framework (Ch 3)
|
|
49
|
+
|
|
50
|
+
Every design should follow:
|
|
51
|
+
|
|
52
|
+
1. **Understand the problem and establish design scope** (3–10 min) — Clarify requirements, define functional and non-functional requirements, make back-of-envelope estimates
|
|
53
|
+
2. **Propose high-level design and get buy-in** (10–15 min) — Draw initial blueprint, identify main components, propose APIs
|
|
54
|
+
3. **Design deep dive** (10–25 min) — Dive into 2–3 critical components, discuss trade-offs
|
|
55
|
+
4. **Wrap up** (3–5 min) — Summarize, discuss error handling, operational concerns, scaling
|
|
56
|
+
|
|
57
|
+
### Step 3 — Apply the Right Practices
|
|
58
|
+
|
|
59
|
+
Read `references/api_reference.md` for the full chapter-by-chapter catalog. Quick decision guide:
|
|
60
|
+
|
|
61
|
+
| Concern | Chapters to Apply |
|
|
62
|
+
|---------|-------------------|
|
|
63
|
+
| Scaling from zero to millions | Ch 1: Load balancer, DB replication, cache, CDN, sharding, message queue, stateless tier |
|
|
64
|
+
| Estimating capacity | Ch 2: Powers of 2, latency numbers, QPS/storage/bandwidth estimation |
|
|
65
|
+
| Structuring the interview | Ch 3: 4-step framework (scope → high-level → deep dive → wrap up) |
|
|
66
|
+
| Controlling request rates | Ch 4: Token bucket, leaking bucket, fixed/sliding window, Redis-based distributed rate limiting |
|
|
67
|
+
| Distributing data evenly | Ch 5: Consistent hashing, hash ring, virtual nodes |
|
|
68
|
+
| Building distributed storage | Ch 6: CAP theorem, quorum consensus (N/W/R), vector clocks, gossip protocol, Merkle trees |
|
|
69
|
+
| Generating unique IDs | Ch 7: Multi-master, UUID, ticket server, Twitter snowflake approach |
|
|
70
|
+
| Shortening URLs | Ch 8: Hash + collision resolution, base-62 conversion, 301 vs 302 redirects |
|
|
71
|
+
| Crawling the web | Ch 9: BFS traversal, URL frontier (politeness/priority queues), robots.txt, content dedup |
|
|
72
|
+
| Sending notifications | Ch 10: APNs/FCM push, SMS, email; notification log, retry, dedup, rate limiting, templates |
|
|
73
|
+
| Building news feeds | Ch 11: Fanout on write vs read, hybrid for celebrities, cache layers (content, social graph, counters) |
|
|
74
|
+
| Real-time messaging | Ch 12: WebSocket, long polling, stateful chat services, key-value store, presence, service discovery |
|
|
75
|
+
| Search autocomplete | Ch 13: Trie data structure, data gathering service, query service, browser caching, sharding |
|
|
76
|
+
| Video streaming | Ch 14: Upload flow, DAG-based transcoding, streaming protocols, CDN cost optimization, pre-signed URLs |
|
|
77
|
+
| Cloud file storage | Ch 15: Block servers, delta sync, resumable upload, metadata DB, long-polling notifications, conflict resolution |
|
|
78
|
+
|
|
79
|
+
### Step 4 — Design the System
|
|
80
|
+
|
|
81
|
+
Follow these principles:
|
|
82
|
+
|
|
83
|
+
- **Start simple, then scale** — Begin with single-server, identify bottlenecks, scale incrementally
|
|
84
|
+
- **Estimate first** — Use back-of-envelope estimation to validate feasibility
|
|
85
|
+
- **Identify bottlenecks** — Find the single points of failure and address them
|
|
86
|
+
- **Trade-offs explicit** — Every design decision has trade-offs; state them clearly
|
|
87
|
+
- **Consider failures** — Design for failure: replication, retry, graceful degradation
|
|
88
|
+
|
|
89
|
+
When applying design, produce:
|
|
90
|
+
|
|
91
|
+
1. **Requirements** — Functional and non-functional requirements, constraints
|
|
92
|
+
2. **Back-of-envelope estimation** — QPS, storage, bandwidth, memory estimates
|
|
93
|
+
3. **High-level design** — Main components and how they interact
|
|
94
|
+
4. **Deep dive** — 2–3 most critical components with detailed design
|
|
95
|
+
5. **Operational concerns** — Error handling, monitoring, scaling plan
|
|
96
|
+
|
|
97
|
+
### Design Application Examples
|
|
98
|
+
|
|
99
|
+
**Example 1 — Rate Limiter:**
|
|
100
|
+
```
|
|
101
|
+
User: "Design a rate limiter for our API"
|
|
102
|
+
|
|
103
|
+
Apply: Ch 4 (rate limiting algorithms), Ch 1 (scaling concepts)
|
|
104
|
+
|
|
105
|
+
Generate:
|
|
106
|
+
- Clarify: per-user or per-IP? HTTP API? Distributed?
|
|
107
|
+
- Evaluate algorithms: token bucket (API rate limiting), sliding window (precision)
|
|
108
|
+
- Architecture: Redis-based counters, rate limiter middleware
|
|
109
|
+
- Race condition handling: Lua scripts or sorted sets
|
|
110
|
+
- Multi-datacenter sync strategy
|
|
111
|
+
- Response headers: X-Ratelimit-Remaining, X-Ratelimit-Limit, X-Ratelimit-Retry-After
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Example 2 — Chat System:**
|
|
115
|
+
```
|
|
116
|
+
User: "Design a chat application supporting group messaging"
|
|
117
|
+
|
|
118
|
+
Apply: Ch 12 (chat system), Ch 1 (scaling), Ch 5 (consistent hashing)
|
|
119
|
+
|
|
120
|
+
Generate:
|
|
121
|
+
- Communication: WebSocket for real-time, HTTP for other features
|
|
122
|
+
- Stateful chat servers with service discovery (Zookeeper)
|
|
123
|
+
- Key-value store for messages (HBase-like)
|
|
124
|
+
- Message sync with per-device cursor ID
|
|
125
|
+
- Online presence: heartbeat mechanism, fanout to friends
|
|
126
|
+
- Group chat: message copy per recipient for small groups
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Example 3 — Video Platform:**
|
|
130
|
+
```
|
|
131
|
+
User: "Design a video upload and streaming service"
|
|
132
|
+
|
|
133
|
+
Apply: Ch 14 (YouTube), Ch 1 (CDN, scaling)
|
|
134
|
+
|
|
135
|
+
Generate:
|
|
136
|
+
- Upload: parallel chunk upload, resumable, pre-signed URLs
|
|
137
|
+
- Transcoding: DAG-based pipeline (video splitting → encoding → merging)
|
|
138
|
+
- Architecture: preprocessor → DAG scheduler → resource manager → task workers
|
|
139
|
+
- Streaming: adaptive bitrate with HLS/DASH
|
|
140
|
+
- Cost: popular content via CDN, long-tail from origin servers
|
|
141
|
+
- Safety: DRM, AES encryption, watermarking
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Mode 2: Design Review
|
|
147
|
+
|
|
148
|
+
When reviewing system designs, read `references/review-checklist.md` for the full checklist.
|
|
149
|
+
|
|
150
|
+
### Review Process
|
|
151
|
+
|
|
152
|
+
1. **Scale scan** — Check Ch 1: Are scaling fundamentals applied (LB, cache, CDN, replication, sharding)?
|
|
153
|
+
2. **Estimation scan** — Check Ch 2: Are capacity estimates done? Are they reasonable?
|
|
154
|
+
3. **Framework scan** — Check Ch 3: Does the design follow the 4-step framework (scope → high-level → deep dive → wrap up)? The Ch 3 4-step framework explicitly requires establishing scope and estimating load *before* proposing architecture — skipping estimation leads to over-engineered or under-engineered designs.
|
|
155
|
+
4. **Component scan** — Check Ch 4–15: Are relevant patterns used for specific components?
|
|
156
|
+
5. **Failure scan** — Are failure modes addressed? Replication, retry, graceful degradation? Specifically praise when message queues are used as durable buffers (fanout service crashes can replay from the queue; message queue decouples producers from consumers and prevents data loss on failure).
|
|
157
|
+
6. **Trade-off scan** — Are design decisions justified with explicit trade-offs?
|
|
158
|
+
|
|
159
|
+
### Recognizing Good Designs
|
|
160
|
+
|
|
161
|
+
When a design is well-structured, **say so explicitly** — do not manufacture fake issues just to have something to say. Specifically acknowledge:
|
|
162
|
+
|
|
163
|
+
- **4-step framework adherence** (Ch 3): If the design clearly follows scope → estimation → high-level → deep dive → failure handling, explicitly recognize it as a well-structured design following the 4-step framework.
|
|
164
|
+
- **Back-of-envelope estimation quality** (Ch 2): If the designer derives concrete QPS numbers and uses the read/write ratio to justify architectural choices (e.g., why Redis caching is needed, why read replicas are warranted), praise this explicitly — the ratio is what *justifies* the design decisions.
|
|
165
|
+
- **Celebrity/hotspot handling** (Ch 11): Fanout-on-write for normal users + fanout-on-read for high-follower accounts is the canonical hybrid approach — praise it when present.
|
|
166
|
+
- **Cursor-based pagination**: Praise over offset-based for feeds where new content is inserted continuously.
|
|
167
|
+
- **Explicit consistency model**: When a designer explicitly chooses eventual consistency and documents why, praise the decision.
|
|
168
|
+
- **Message queue as durable buffer** (Ch 1, 11): When failure handling uses a message queue so that service crashes can replay events and no data is lost, explicitly praise this as a correct reliability pattern.
|
|
169
|
+
- **Optional improvements**: Frame any suggestions as enhancements, not criticisms, when the design is fundamentally sound.
|
|
170
|
+
|
|
171
|
+
### Review Output Format
|
|
172
|
+
|
|
173
|
+
Structure your review as:
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
## Summary
|
|
177
|
+
One paragraph: overall design quality, main strengths, key concerns.
|
|
178
|
+
|
|
179
|
+
## Strengths
|
|
180
|
+
For each strength (list when design is good):
|
|
181
|
+
- **Topic**: what was done well
|
|
182
|
+
- **Why**: chapter reference and why it matters
|
|
183
|
+
|
|
184
|
+
## Scaling Issues
|
|
185
|
+
For each issue:
|
|
186
|
+
- **Topic**: component and concept
|
|
187
|
+
- **Problem**: what's wrong or missing
|
|
188
|
+
- **Fix**: recommended change with chapter reference
|
|
189
|
+
|
|
190
|
+
## Estimation Issues
|
|
191
|
+
For each issue: same structure
|
|
192
|
+
|
|
193
|
+
## Component Design Issues
|
|
194
|
+
For each issue: same structure
|
|
195
|
+
|
|
196
|
+
## Failure Handling Issues
|
|
197
|
+
For each issue: same structure
|
|
198
|
+
|
|
199
|
+
## Recommendations
|
|
200
|
+
Priority-ordered from most critical to nice-to-have.
|
|
201
|
+
Each recommendation references the specific chapter/concept.
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Common System Design Anti-Patterns to Flag
|
|
205
|
+
|
|
206
|
+
- **No capacity estimation** → Ch 2: Always estimate QPS, storage, bandwidth before designing
|
|
207
|
+
- **Single point of failure** → Ch 1: Add redundancy via replication, load balancing, failover
|
|
208
|
+
- **No caching strategy** → Ch 1: Use cache-aside, read-through, or write-behind as appropriate
|
|
209
|
+
- **Monolithic database** → Ch 1: Consider replication (read replicas) and sharding for scale
|
|
210
|
+
- **Stateful web servers** → Ch 1: Move session data to shared storage for horizontal scaling
|
|
211
|
+
- **Vanity scaling** → Ch 2 + Ch 3: Scaling decisions must be based on back-of-envelope estimation, not intuition or aspiration. The 4-step framework (Ch 3) requires establishing scope and estimating load *before* proposing architecture — skipping this step is what leads to over-engineered designs
|
|
212
|
+
- **Wrong data store** → Ch 6, 12: Match storage to access patterns (relational, key-value, document)
|
|
213
|
+
- **No rate limiting** → Ch 4: Protect APIs from abuse and cascading failures
|
|
214
|
+
- **Synchronous everything** → Ch 1: Use message queues for decoupling and async processing
|
|
215
|
+
- **No CDN for static content** → Ch 1: Serve static assets from CDN to reduce latency and server load
|
|
216
|
+
- **Big-bang deployment** → Ch 14: Use parallel processing, chunked uploads, incremental approaches
|
|
217
|
+
- **No conflict resolution** → Ch 6, 15: Handle concurrent writes with versioning or conflict detection
|
|
218
|
+
- **Missing monitoring** → Ch 3: Always include logging, metrics, alerting in the design
|
|
219
|
+
- **Ignoring network partition** → Ch 6: CAP theorem applies; choose CP or AP based on requirements
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## General Guidelines
|
|
224
|
+
|
|
225
|
+
- **The 4-step framework is universal** — Use it for every design problem, not just interviews
|
|
226
|
+
- **Back-of-envelope estimation validates feasibility** — Always estimate before designing
|
|
227
|
+
- **Every component has trade-offs** — Consistency vs. availability, latency vs. throughput, cost vs. reliability
|
|
228
|
+
- **Start simple, then optimize** — Single server → vertical scaling → horizontal scaling → advanced optimizations
|
|
229
|
+
- **Design for failure** — Assume every component will fail; plan recovery
|
|
230
|
+
- **Cache is king for read-heavy systems** — But consider cache invalidation complexity
|
|
231
|
+
- **Sharding enables horizontal data scaling** — But adds complexity (joins, rebalancing, hotspots)
|
|
232
|
+
- For deeper design details, read `references/api_reference.md` before applying designs.
|
|
233
|
+
- For review checklists, read `references/review-checklist.md` before reviewing designs.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
|
|
2
|
+
{
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": "eval-01-naive-url-shortener",
|
|
6
|
+
"prompt": "I need to design a URL shortener service like bit.ly. Here's my design:\n\nThe system has a single server with a MySQL database. When a user submits a long URL, we generate a random 6-character short code, store the mapping in a `urls` table with columns (short_code, long_url, created_at), and return the short URL. When someone visits the short URL, we look up the long URL in the database and do a 302 redirect.\n\nFor the database:\n```sql\nCREATE TABLE urls (\n short_code VARCHAR(6) PRIMARY KEY,\n long_url TEXT NOT NULL,\n created_at TIMESTAMP DEFAULT NOW()\n);\n```\n\nThe application is a simple Node.js Express server that handles both write (shorten) and read (redirect) traffic on the same process. I think this will work fine for our use case.",
|
|
7
|
+
"expectations": [
|
|
8
|
+
"Calls out the absence of any back-of-envelope estimation before designing (Ch 2 / Ch 3): we don't know the QPS, storage needs, or read/write ratio — the design can't be validated without these numbers",
|
|
9
|
+
"Identifies the single point of failure: one server, one database — any failure takes down the entire service",
|
|
10
|
+
"Flags missing caching (Ch 1): URL redirects are extremely read-heavy (estimated 100:1 read/write ratio in the book's example); a Redis cache in front of the DB would handle the vast majority of redirect lookups without hitting MySQL",
|
|
11
|
+
"Flags no CDN or load balancing (Ch 1): with a single Node.js process, the service cannot scale horizontally",
|
|
12
|
+
"Questions the random collision strategy: random 6-character codes will have increasing collision probability as the table grows — needs a collision-resistant ID generation strategy (base-62 encoding of auto-increment ID, or a dedicated ID generator per Ch 7/8)",
|
|
13
|
+
"Notes that 302 redirect means the browser does NOT cache the redirect — every click hits the server again; 301 is cacheable and reduces load for stable URLs (Ch 8 covers this trade-off explicitly)",
|
|
14
|
+
"Flags the absence of rate limiting on the URL creation endpoint — without it the service is open to spam and abuse (Ch. 4: rate limiter patterns protect APIs; a URL shortener creation endpoint is a prime abuse target)",
|
|
15
|
+
"Recommends at minimum: back-of-envelope estimate first, Redis cache for redirects, read replicas for the DB, load balancer, and a more robust ID generation approach"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": "eval-02-premature-optimization-no-estimation",
|
|
20
|
+
"prompt": "I want to build a notification system (like push notifications for a mobile app). Before designing it, I've decided the system needs:\n\n1. A Kafka cluster with 50 partitions for notification events\n2. A Cassandra cluster with 6 nodes for storing notification history\n3. A Redis cluster in active-active mode across 3 data centers\n4. A Kubernetes cluster with auto-scaling pods for the notification workers\n5. A separate microservice for each notification channel (push, SMS, email, in-app)\n6. A GraphQL subscription API for real-time notification delivery\n7. Consistent hashing for distributing notifications across worker pods\n\nThe app currently has about 500 registered users and we send maybe 200 notifications per day.",
|
|
21
|
+
"expectations": [
|
|
22
|
+
"Calls out vanity scaling (Ch 2): 500 users sending 200 notifications per day is roughly 0.002 QPS — this is trivially handled by a single server with a simple database; none of the proposed infrastructure is justified",
|
|
23
|
+
"References the principle from Ch 2: scaling decisions must be based on back-of-envelope estimation, not intuition or aspiration",
|
|
24
|
+
"Calculates or estimates the actual load: 200 notifications/day = ~8/hour = ~0.002/second — a SQLite database on a $5 server would handle this with room to spare",
|
|
25
|
+
"Notes that the proposed stack adds enormous operational complexity: Kafka, Cassandra, Redis cluster, Kubernetes, and multiple microservices all require dedicated expertise to operate, monitor, and debug",
|
|
26
|
+
"Identifies this as the 'vanity scaling' anti-pattern explicitly called out in the SKILL.md review checklist",
|
|
27
|
+
"Recommends a design appropriate for the actual scale: a single service, a relational database (Postgres), an email/SMS provider SDK, and a simple job queue (like BullMQ or a DB-backed worker) — then scale when metrics demand it",
|
|
28
|
+
"Notes that the 4-step framework (Ch 3) requires establishing scope and estimating load BEFORE proposing architecture — skipping estimation leads to over-engineered designs like this one"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "eval-03-good-system-design-proposal",
|
|
33
|
+
"prompt": "Design proposal for a news feed system (like Twitter's home timeline):\n\n**Step 1 — Requirements & Estimation**\n- Functional: users follow others, posts appear in follower feeds, feeds are reverse-chronological\n- Non-functional: 500ms p99 feed load, eventual consistency acceptable, 10M DAU\n- Estimation: 10M DAU × 2 feed loads/day = 20M reads/day ≈ 230 QPS reads; 10M DAU × 0.1 posts/day = 1M writes/day ≈ 12 QPS writes; read/write ratio ≈ 20:1\n- Storage: 1M posts/day × 200 bytes = 200MB/day ≈ 70GB/year for post content\n\n**Step 2 — High-Level Design**\n- Write path: user posts → Post Service → publishes PostCreated event to message queue\n- Fanout service subscribes to PostCreated → for each follower, prepends post ID to their feed cache in Redis\n- Read path: Feed Service → reads from Redis feed cache (list of post IDs) → fetches post content from Post Cache\n- API: GET /v1/feed?userId=X&cursor=Y (cursor-based pagination)\n\n**Step 3 — Deep Dive: Fanout Strategy**\n- Fanout-on-write for regular users: pre-populate follower feeds in Redis on every post\n- Exception for celebrities (>10K followers): fanout-on-read — too expensive to write to millions of feed caches synchronously\n- Hybrid: celebrity posts fetched at read time and merged with pre-computed feed\n\n**Step 4 — Failure Handling**\n- Message queue provides durability for fanout — if fanout service crashes, it replays from queue\n- Redis feeds are a cache, not source of truth — Post DB is the durable store; stale feeds are acceptable (eventual consistency)\n- Rate limiting on POST /posts to prevent feed spam",
|
|
34
|
+
"expectations": [
|
|
35
|
+
"Recognizes this as a well-structured design following the 4-step framework and says so explicitly",
|
|
36
|
+
"Praises the back-of-envelope estimation: derives concrete QPS numbers (230 reads, 12 writes) and uses the read/write ratio to justify the design decisions",
|
|
37
|
+
"Praises the fanout-on-write vs fanout-on-read hybrid — this is exactly the celebrity problem discussed in Ch 11 of the book; the design correctly identifies and handles the hot-user case",
|
|
38
|
+
"Praises cursor-based pagination over offset-based — correct for infinite scroll feeds where new content is constantly inserted",
|
|
39
|
+
"Praises the explicit consistency model: choosing eventual consistency and documenting why (the 500ms SLA and user experience tolerance)",
|
|
40
|
+
"Praises the failure handling section: using the message queue as a durable buffer means fanout service failures don't lose posts",
|
|
41
|
+
"Does NOT manufacture fake issues just to have something to say",
|
|
42
|
+
"May offer optional improvements (cache warming on login, feed pre-generation for cold start, monitoring mentions) but clearly frames them as enhancements"
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|