Catalog of reusable architectural primitives — boundaries, contracts, state machines, queues, caches, consistency models, and more. For each: what it is, when it's right, when it's WRONG. Use when selecting patterns for a design or evaluating whether a pattern fits.
复制安装指令,让 AI 自动完成配置 · 推荐新手
请帮我安装 askskill 上的 "architecture-primitives" 技能: 1. 下载 https://raw.githubusercontent.com/microsoft/amplifier-bundle-systems-design/main/skills/architecture-primitives/SKILL.md 2. 保存为 ~/.claude/skills/architecture-primitives/SKILL.md 3. 装好后重载技能,告诉我可以用了
An architect who knows many patterns is less useful than one who knows when each pattern is wrong.
For each primitive: what it is, when to use it, and when it will hurt you.
What it is. Drawing lines between components so each has a clear owner, clear interface, and can evolve independently.
When it's right. When different teams own different parts. When components have different scaling, deployment, or reliability requirements. When you need to limit blast radius.
When it's wrong. When the "boundary" creates more cross-boundary coordination than it prevents. When data that changes together is split across boundaries. When the team is small enough that communication overhead exceeds boundary value.
What it is. Explicit agreements between components about what they provide and expect — API schemas, message formats, SLAs, error codes.
When it's right. At every boundary. Between any components that evolve independently. When multiple consumers depend on the same provider.
When it's wrong. Premature contracts between components that are still being designed together. Overly rigid contracts that prevent necessary evolution. Contracts without versioning strategy.
What it is. For every piece of state, exactly one system is authoritative. All others are caches, replicas, or derived views.
When it's right. Always. Every system should be able to answer "where is the source of truth for X?"
When it's wrong. Never wrong as a concept — but wrong when applied as "one database for everything." Different data has different truth owners.
What it is. Sync: caller waits for response. Async: caller sends message and continues.
When sync is right. When the caller genuinely cannot proceed without the response. User-facing request/response flows. Reads that must be consistent.
When sync is wrong. When the caller doesn't need the result to continue. When the called service is slow or unreliable. When you're creating temporal coupling between services that don't need it.
When async is right. When work can be deferred. When you need to absorb load spikes. When producer and consumer should be independently deployable and scalable.
When async is wrong. When you need an immediate, consistent response. When the added complexity of message delivery, ordering, and failure handling exceeds the benefit.
What it is. Modeling entities as having explicit states with defined transitions. An order is "placed → confirmed → shipped → delivered," not a bag of boolean flags.
When it's right. When an entity has a lifecycle with distinct phases. When invalid state transitions are a real failure mode. When you need to audit or replay state changes.
When it's wrong. When the entity's behavior doesn't meaningfully vary by state. When the state space is too large to enumerate. When you're adding a state machine to something that is really just a CRUD record.
What it is. Decoupling producers from consumers with an intermediate buffer. Smooths out rate differences and absorbs spikes.
When it's right. When producer rate exceeds consumer rate temporarily. When consumer failures shouldn't block producers. When you need to prioritize or reorder work.
When it's wrong. When the queue grows unboundedly (you've moved the problem, not solved it). When end-to-end latency matters and the queue adds unacceptable delay. When queue failure becomes a single point of failure worse than direct coupling.
What it is. Storing computed or fetched results closer to the consumer to avoid repeated expensive operations.
When it's right. When reads vastly outnumber writes. When the source is slow and staleness is acceptable. When the working set fits in memory.
…
Domain-Driven Design as a lens for system architecture — bounded contexts, aggregates, ubiquitous language, context mapping, domain events, and strategic vs tactical patterns. Use when modeling complex business domains, defining service boundaries, or evaluating whether a system's structure reflects its domain.
The Unix/Linux design philosophy as a lens for system design — mechanism vs policy, composability, small tools, text streams, convention over configuration, and the principle of least surprise. Use when evaluating designs for composability, simplicity, or separation of concerns.
Object-oriented design principles as a lens for system architecture — SOLID, composition over inheritance, the actor model, design patterns (and when they're wrong), encapsulation, polymorphism, and responsibility-driven design. Use when evaluating code organization, module boundaries, or object/component relationships.
Domain patterns for Azure cloud architecture — compute selection, managed services, identity (Entra ID), networking, data platform, messaging, deployment, cost management, and operational patterns. Use when designing or evaluating a system deployed on Microsoft Azure.
Domain patterns for CLI tools and developer SDKs — command structure, configuration layering, plugin architecture, distribution, backward compatibility, shell integration, and failure modes. Use when designing or evaluating command-line tools, developer platforms, or SDK libraries.
Adversarial review of a system design from 6 critical perspectives -- SRE, security, staff engineer, finance, operator, and developer advocate. Produces a unified risk assessment. Use for INTERACTIVE on-demand reviews during a design conversation (/adversarial-review). For RECIPE-DRIVEN reviews (where prior step context is needed), use the systems-design-critic agent instead.