pragmatic-programmer by wondelai/skills
npx skills add https://github.com/wondelai/skills --skill pragmatic-programmer源自 Hunt & Thomas《实用程序员》(20周年纪念版)的系统级软件工艺方法。在设计系统、评审架构、编写代码或提供工程文化建议时应用这些原则。本框架关注元层面:如何思考软件,而不仅仅是编写软件。
关心你的技艺。 软件开发是一门需要持续学习、严格实践和个人责任的技艺。实用程序员会超越眼前的问题进行思考——他们会考虑每个技术决策的背景、权衡和长期后果。
基础: 优秀的软件源于优秀的习惯。实用程序员保持广泛的知识储备,清晰沟通,无情地避免重复,保持组件正交性,并将每一行代码都视为必须证明其价值的活资产。目标不是完美——而是构建易于更改、易于理解和易于信任的系统。
目标:10/10。 在评审或创建软件设计、架构或代码时,根据对以下原则的遵循程度进行 0-10 分评分。10/10 表示完全符合所有准则;较低的分数表示存在需要解决的差距。始终提供当前分数以及达到 10/10 所需的具体改进措施。
构建持久软件的七大元原则:
核心理念: 系统中的每一条知识都必须有单一、明确、权威的表示。DRY 是关于知识,而不是代码——重复的逻辑、业务规则或配置远比重复的语法更危险。
为何有效: 当知识被重复时,变更必须在多个地方进行。最终会遗漏一处,从而引入不一致性。DRY 减少了错误的表面积,并使系统更易于更改。
关键见解:
代码应用:
| 上下文 | 模式 |
|---|
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 示例 |
|---|
| 配置值 | 单一事实来源 | 在一个环境文件中定义数据库连接,各处引用 |
| 验证规则 | 共享模式 | 使用 JSON Schema 或 Zod 模式进行客户端和服务器端验证 |
| API 契约 | 从规范生成 | OpenAPI 规范生成类型、文档和客户端代码 |
| 业务逻辑 | 领域模块 | 税收计算在一个模块中,而不是分散在各个控制器中 |
| 数据库模式 | 迁移驱动 | 模式在迁移中定义,ORM 模型从数据库生成 |
核心理念: 如果两个组件中一个的变化不影响另一个,则它们是正交的。设计系统时,应使组件自包含、独立,并具有单一、定义明确的目的。
为何有效: 正交系统更易于测试、更易于更改,并且产生的副作用更少。当你更改数据库层时,UI 不应崩溃。当你更改身份验证提供者时,业务逻辑不应受到影响。
关键见解:
代码应用:
| 上下文 | 模式 | 示例 |
|---|---|---|
| 架构 | 分层分离 | Controller -> Service -> Repository,每一层都可替换 |
| 依赖关系 | 依赖注入 | 传递 Notifier 接口,而不是 SlackClient 具体类 |
| 测试 | 隔离的单元测试 | 无需数据库、网络或文件系统即可测试业务逻辑 |
| 配置 | 环境驱动 | 配置中的功能开关,而非业务逻辑中的 if 分支 |
| 部署 | 独立服务 | 部署身份验证服务而无需重新部署支付服务 |
核心理念: 曳光弹是连接系统所有层的端到端实现,具有最小的功能。与原型(可丢弃的)不同,曳光弹代码是生产代码——精简但真实。
为何有效: 曳光弹提供即时反馈。在投入精力填充每个功能之前,你可以看到系统的端到端面貌。用户可以看到真实的东西,开发者有一个可以构建的框架,集成问题会尽早暴露。
关键见解:
代码应用:
| 上下文 | 模式 | 示例 |
|---|---|---|
| 新项目 | 垂直切片 | 构建一个端到端的功能:按钮 -> API -> DB -> 响应 |
| 不确定的技术 | 探索性原型 | 在确定使用前测试 WebSocket 性能是否足够 |
| 框架评估 | 贯穿技术栈的曳光弹 | 在选择框架前,通过完整框架构建登录流程 |
| 微服务 | 行走骨架 | 通过完整的 CI/CD 流水线部署一个 hello-world 服务 |
| 数据管道 | 端到端流程 | 一条记录从摄取、转换到输出的完整流程 |
核心理念: 通过前置条件(调用前必须为真)、后置条件(调用后保证为真)和类不变式(始终为真)来定义和执行软件模块的权利与责任。当契约被违反时,立即并明确地失败。
为何有效: 契约使假设变得明确。系统不会默默地破坏数据或在无效状态下勉强运行,而是在问题点崩溃——使错误可见且可追踪。死程序不说谎。
关键见解:
代码应用:
| 上下文 | 模式 | 示例 |
|---|---|---|
| 函数入口 | 前置条件守卫 | 在函数开始时使用 assert age >= 0, "年龄不能为负" |
| 函数出口 | 后置条件检查 | 返回前验证返回的列表已排序 |
| 类状态 | 不变式验证 | 每次状态变更后调用 validate! 方法 |
| API 边界 | 模式验证 | 在处理前根据模式验证请求体 |
| 数据管道 | 阶段断言 | 断言 ETL 转换后的行数符合预期 |
核心理念: 一扇破窗——一段设计糟糕的代码、一个糟糕的管理决策、一个"我们稍后会修复"的临时方案——会开始腐烂。一旦系统显示出被忽视的迹象,熵就会加速,纪律就会崩溃。
为何有效: 心理学。当代码干净且维护良好时,开发者会感受到保持这种状态的社会压力。当代码已经混乱时,添加更多混乱的阈值就降为零。质量是团队习惯,而非个人的英雄主义努力。
关键见解:
代码应用:
| 上下文 | 模式 | 示例 |
|---|---|---|
| 遗留代码 | 封堵破窗 | 在添加功能前,用干净的接口包装糟糕的代码 |
| 代码审查 | 对新债务零容忍 | 拒绝添加 // TODO: 稍后修复 但没有工单的 PR |
| 技术债务 | 债务预算 | 每个冲刺分配 20% 的时间来修复破窗 |
| 新团队成员 | 干净的入职路径 | 第一个任务:修复一个破窗以了解代码库 |
| 监控 | 熵指标 | 跟踪代码规范违规、测试覆盖率随时间的变化趋势 |
核心理念: 没有最终的决定。构建易于改变你对数据库、框架、供应商、架构和部署目标想法的系统。变更的成本应与变更的范围成正比。
为何有效: 需求会变。供应商会被收购。技术会过时。如果你的架构对这些有任何硬编码的假设,那么每次变更都会变成一次重写。灵活的架构将决策视为配置,而非结构。
关键见解:
代码应用:
| 上下文 | 模式 | 示例 |
|---|---|---|
| 数据库 | 仓储模式 | 业务逻辑调用 repo.save(user),而不是 pg.query(...) |
| 外部 API | 适配器/包装器 | PaymentGateway 接口包装 Stripe;稍后可换到 Braintree |
| 功能开关 | 运行时切换 | 新结账流程放在开关后面,几秒钟内即可回滚 |
| 架构 | 事件驱动解耦 | 服务通过事件通信,而非直接的 HTTP 调用 |
| 部署 | 容器抽象 | Docker 化的应用可以在 AWS、GCP 或裸机上无更改运行 |
核心理念: 通过理解范围、构建模型、分解为组件并分配范围来学习可靠地估算。像管理金融投资组合一样管理你的学习:定期投资、多样化并重新平衡。
为何有效: 诚实的估算能建立与利益相关者的信任("1-3 周"比"正好 2 周"更好)。知识组合确保你在技术变迁时保持相关性——停止学习的程序员将不再高效。
关键见解:
代码应用:
| 上下文 | 模式 | 示例 |
|---|---|---|
| 冲刺规划 | 范围估算 | "3-5 天"并附带置信水平,而不是单一数字 |
| 新技术 | 限时探索 | "我将花 2 天时间评估;然后我才能正确估算" |
| 大型项目 | 自底向上分解 | 分解为 < 1 天的任务,求和并加上集成缓冲 |
| 学习 | 每周投资 | 每周 1 小时学习新语言、工具或领域 |
| 职业成长 | 组合多样化 | 深度(专业知识)和广度(相邻技能)的混合 |
| 错误 | 为何失败 | 修复方法 |
|---|---|---|
| 对服务于不同目的但看起来相似的代码进行 DRY | 在无关概念之间创建耦合;更改一个会破坏另一个 | 只对知识进行 DRY,而非巧合的代码相似性 |
| 跳过曳光弹并逐层构建 | 集成问题出现较晚;直到最后才有端到端反馈 | 首先构建一个精简的垂直切片 |
| 忽视破窗"因为我们稍后会重构" | 熵加速;"稍后"永远不会来;团队士气下降 | 立即修复或用带追踪的工单封堵 |
| 将估算作为单点承诺 | 产生虚假的精确性;错过时侵蚀信任 | 始终提供带有置信水平的范围 |
| 预先使所有东西都"灵活" | 过度工程;YAGNI;没有需求证据的抽象 | 当你有具体证据表明需要时再添加灵活性 |
| 移除生产环境中的断言"为了性能" | 断言本应捕获的错误现在会默默地破坏数据 | 保留关键断言;在移除任何断言前进行基准测试 |
| 全局状态"为了方便" | 破坏正交性;每个模块都与所有东西耦合 | 使用依赖注入和显式参数 |
| 问题 | 如果答案为否 | 行动 |
|---|---|---|
| 我能否在不触及业务逻辑的情况下更改数据库? | 违反正交性 | 引入仓储/适配器模式 |
| 我是否有一个端到端的切片在运行? | 缺少曳光弹 | 在扩展前构建一个垂直切片 |
| 每个业务规则是否都只在一个地方定义? | 违反 DRY | 识别权威来源并移除重复项 |
| 新开发者会称这个代码库"干净"吗? | 存在破窗 | 安排一个专门的清理冲刺 |
| 我的估算是否包含范围和置信水平? | 估算问题 | 切换到 PERT 或基于范围的估算 |
| 我能否在 5 分钟内回滚此部署? | 可逆性差距 | 添加功能开关和蓝绿部署 |
| 我每周都在学习新东西吗? | 知识组合停滞 | 安排每周学习时间并跟踪 |
Andrew Hunt 是一位程序员、作家和出版商。他共同创立了 Pragmatic Bookshelf,并且是敏捷宣言最初的 17 位作者之一。他的工作专注于软件开发中人的一面——团队如何学习、沟通并长期保持质量。
David Thomas 是一位程序员和作家,共同创立了 Pragmatic Bookshelf。他创造了术语"DRY"(不要重复自己)和"Code Kata"。他是 Ruby 在日本以外地区采用的先驱,合著了《Programming Ruby》(Pickaxe 书),并花费数十年倡导开发者的实用主义而非教条主义。
每周安装量
244
代码仓库
GitHub 星标数
260
首次出现
Feb 23, 2026
安全审计
安装于
codex235
opencode233
gemini-cli231
github-copilot231
amp231
kimi-cli231
A systems-level approach to software craftsmanship from Hunt & Thomas' "The Pragmatic Programmer" (20th Anniversary Edition). Apply these principles when designing systems, reviewing architecture, writing code, or advising on engineering culture. This framework addresses the meta-level: how to think about software, not just how to write it.
Care about your craft. Software development is a craft that demands continuous learning, disciplined practice, and personal responsibility. Pragmatic programmers think beyond the immediate problem -- they consider context, trade-offs, and long-term consequences of every technical decision.
The foundation: Great software comes from great habits. A pragmatic programmer maintains a broad knowledge portfolio, communicates clearly, avoids duplication ruthlessly, keeps components orthogonal, and treats every line of code as a living asset that must earn its place. The goal is not perfection -- it is building systems that are easy to change, easy to understand, and easy to trust.
Goal: 10/10. When reviewing or creating software designs, architecture, or code, rate it 0-10 based on adherence to the principles below. A 10/10 means full alignment with all guidelines; lower scores indicate gaps to address. Always provide the current score and specific improvements needed to reach 10/10.
Seven meta-principles for building software that lasts:
Core concept: Every piece of knowledge must have a single, unambiguous, authoritative representation within a system. DRY is about knowledge, not code -- duplicated logic, business rules, or configuration are far more dangerous than duplicated syntax.
Why it works: When knowledge is duplicated, changes must be made in multiple places. Eventually one gets missed, introducing inconsistency. DRY reduces the surface area for bugs and makes systems easier to change.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Config values | Single source of truth | Define DB connection in one env file, reference everywhere |
| Validation rules | Shared schema | Use JSON Schema or Zod schema for both client and server validation |
| API contracts | Generate from spec | OpenAPI spec generates types, docs, and client code |
| Business logic | Domain module | Tax calculation in one module, not scattered across controllers |
| Database schema | Migration-driven | Schema defined in migrations, ORM models generated from DB |
See: references/dry-orthogonality.md
Core concept: Two components are orthogonal if changes in one do not affect the other. Design systems where components are self-contained, independent, and have a single, well-defined purpose.
Why it works: Orthogonal systems are easier to test, easier to change, and produce fewer side effects. When you change the database layer, the UI should not break. When you change the auth provider, the business logic should not care.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Architecture | Layered separation | Controller -> Service -> Repository, each replaceable |
| Dependencies | Dependency injection | Pass a Notifier interface, not a SlackClient concrete class |
| Testing | Isolated unit tests | Test business logic without database, network, or filesystem |
| Configuration | Environment-driven | Feature flags in config, not if branches in business logic |
| Deployment | Independent services | Deploy auth service without redeploying payment service |
See: references/dry-orthogonality.md
Core concept: Tracer bullets are end-to-end implementations that connect all layers of the system with minimal functionality. Unlike prototypes (which are throwaway), tracer bullet code is production code -- thin but real.
Why it works: Tracer bullets give immediate feedback. You see what the system looks like end-to-end before investing in filling out every feature. Users can see something real, developers have a framework to build on, and integration issues surface early.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| New project | Vertical slice | Build one feature end-to-end: button -> API -> DB -> response |
| Uncertain tech | Spike prototype | Test if WebSocket performance is sufficient before committing |
| Framework eval | Tracer through stack | Build login flow through the full framework before choosing it |
| Microservice | Walking skeleton | Deploy a hello-world service through the full CI/CD pipeline |
| Data pipeline | End-to-end flow | One record from ingestion through transformation to output |
See: references/tracer-bullets.md
Core concept: Define and enforce the rights and responsibilities of software modules through preconditions (what must be true before), postconditions (what is guaranteed after), and class invariants (what is always true). When a contract is violated, fail immediately and loudly.
Why it works: Contracts make assumptions explicit. Instead of silently corrupting data or limping along in an invalid state, the system crashes at the point of the problem -- making bugs visible and traceable. Dead programs tell no lies.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Function entry | Precondition guard | assert age >= 0, "Age cannot be negative" at function start |
| Function exit | Postcondition check | Verify returned list is sorted before returning |
| Class state | Invariant validation | validate! method called after every state mutation |
| API boundary | Schema validation | Validate request body against schema before processing |
| Data pipeline | Stage assertions | Assert row count after ETL transform matches expectation |
See: references/contracts-assertions.md
Core concept: One broken window -- a badly designed piece of code, a poor management decision, a hack that "we'll fix later" -- starts the rot. Once a system shows neglect, entropy accelerates and discipline collapses.
Why it works: Psychology. When code is clean and well-maintained, developers feel social pressure to keep it that way. When code is already messy, the threshold for adding more mess drops to zero. Quality is a team habit, not an individual heroic effort.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Legacy code | Board up windows | Wrap bad code in a clean interface before adding features |
| Code review | Zero-tolerance for new debt | Reject PRs that add // TODO: fix later without a ticket |
| Tech debt | Debt budget | Allocate 20% of each sprint to fixing broken windows |
| New team member | Clean onboarding path | First task: fix a broken window to learn the codebase |
| Monitoring | Entropy metrics | Track linting violations, test coverage trends over time |
See: references/broken-windows.md
Core concept: There are no final decisions. Build systems that make it easy to change your mind about databases, frameworks, vendors, architecture, and deployment targets. The cost of change should be proportional to the scope of change.
Why it works: Requirements change. Vendors get acquired. Technologies fall out of favor. If your architecture has hard-coded assumptions about any of these, every change becomes a rewrite. Flexible architecture treats decisions as configuration, not structure.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Database | Repository pattern | Business logic calls repo.save(user), not pg.query(...) |
| External API | Adapter/wrapper | PaymentGateway interface wraps Stripe; swap to Braintree later |
| Feature flags | Runtime toggles | New checkout flow behind a flag, rollback in seconds |
| Architecture | Event-driven decoupling | Services communicate via events, not direct HTTP calls |
| Deployment | Container abstraction | Dockerized app runs on AWS, GCP, or bare metal unchanged |
See: references/reversibility.md
Core concept: Learn to estimate reliably by understanding scope, building models, decomposing into components, and assigning ranges. Manage your learning like a financial portfolio: invest regularly, diversify, and rebalance.
Why it works: Estimation builds trust with stakeholders when done honestly ("1-3 weeks" is better than "2 weeks exactly"). A knowledge portfolio ensures you stay relevant as technologies shift -- the programmer who stops learning stops being effective.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Sprint planning | Range estimates | "3-5 days" with confidence level, not a single number |
| New technology | Time-boxed spike | "I'll spend 2 days evaluating; then I can estimate properly" |
| Large project | Bottom-up decomposition | Break into tasks < 1 day, sum with buffer for integration |
| Learning | Weekly investment | 1 hour/week on a new language, tool, or domain |
| Career growth | Portfolio diversification | Mix of depth (expertise) and breadth (adjacent skills) |
See: references/estimation-portfolio.md
| Mistake | Why It Fails | Fix |
|---|---|---|
| DRY-ing similar-looking code that serves different purposes | Creates coupling between unrelated concepts; changes to one break the other | Only DRY knowledge, not coincidental code similarity |
| Skipping tracer bullets and building layer-by-layer | Integration issues surface late; no end-to-end feedback until the end | Build one thin vertical slice first |
| Ignoring broken windows "because we'll refactor later" | Entropy accelerates; later never comes; team morale drops | Fix immediately or board up with a tracked ticket |
| Estimates as single-point commitments | Creates false precision; erodes trust when missed | Always give ranges with confidence levels |
| Making everything "flexible" upfront | Over-engineering; YAGNI; abstraction without evidence of need | Add flexibility when you have concrete evidence you'll need it |
| Assertions in production removed "for performance" | Bugs that assertions would catch now silently corrupt data | Keep critical assertions; benchmark before removing any |
| Global state "for convenience" | Destroys orthogonality; every module coupled to everything |
| Question | If No | Action |
|---|---|---|
| Can I change the database without touching business logic? | Orthogonality violation | Introduce repository/adapter pattern |
| Do I have an end-to-end slice working? | Missing tracer bullet | Build one vertical slice before expanding |
| Is every business rule defined in exactly one place? | DRY violation | Identify the authoritative source and remove duplicates |
| Would a new developer call this codebase "clean"? | Broken windows present | Schedule a dedicated cleanup sprint |
| Do my estimates include ranges and confidence levels? | Estimation problem | Switch to PERT or range-based estimates |
| Can I roll back this deployment in under 5 minutes? | Reversibility gap | Add feature flags and blue-green deploys |
| Am I learning something new every week? | Knowledge portfolio stagnant | Schedule weekly learning time and track it |
Andrew Hunt is a programmer, author, and publisher. He co-founded the Pragmatic Bookshelf and was one of the 17 original authors of the Agile Manifesto. His work focuses on the human side of software development -- how teams learn, communicate, and maintain quality over time.
David Thomas is a programmer and author who co-founded the Pragmatic Bookshelf. He coined the term "DRY" (Don't Repeat Yourself) and "Code Kata." A pioneer in Ruby adoption outside Japan, he co-authored "Programming Ruby" (the Pickaxe book) and has spent decades advocating for developer pragmatism over dogma.
Weekly Installs
244
Repository
GitHub Stars
260
First Seen
Feb 23, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex235
opencode233
gemini-cli231
github-copilot231
amp231
kimi-cli231
Flutter状态管理教程:MVVM与Provider实现单向数据流和架构模式
1,100 周安装
| Use dependency injection and explicit parameters |