mcpField
C
convention-over-configuration

convention-over-configuration

github.com/jordancoin开发1167 次安装35 周前更新
代码仓库

关于 convention-over-configuration

面向软件项目的开发技能,指导团队采用约定优于配置的原则。它倡导记录并统一可预测的默认做法,同时为确有差异的情况保留显式配置。

主要功能

  1. 01记录项目约定
  2. 02遵循框架惯例
  3. 03采用可预测的命名
  4. 04优先使用合理默认值
  5. 05将配置作为代码审查
  6. 06识别配置反模式

适用场景

  1. 01统一各模块的项目结构
  2. 02减少不必要的项目配置
  3. 03检查代码是否遵循约定

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jordancoin/codingskills --skill convention-over-configuration

安装后在 Claude Code 中输入/convention-over-configuration确认已加载。

详细介绍

约定优于配置

开始应用前

如果存在 .agents/stack-context.md,请先阅读。针对检测到的技术栈,采用符合其习惯的模式。有关框架特定的细节,请使用 context7 MCP 或网络搜索——不要猜测。

原则

采用合理的默认值和一致的模式,让决策只需制定一次,便能在各处应用。只有在确实需要偏离默认值时,才进行显式配置。

这对生产环境为何重要

每个配置选项都是一项决策,必须有人做出、记录、理解并维护。配置错误是导致生产事故的主要原因之一——环境变量有误、YAML 中出现拼写错误、服务之间的设置相互冲突。

由约定驱动的系统具有可预测性。新团队成员只需查看一个模块,就能了解其他模块的工作方式。不必担心“这个服务的实现不一样,是因为 18 个月前有人做了那样的配置”。

配置应该是例外,而不是默认做法。当一切都可以配置时,就没有什么是标准化的。

规则

  1. 尽早确立项目约定并记录下来。 文件结构、命名模式、错误处理风格、测试组织方式——一次决定,处处遵循。将这些内容写入一份持续更新的文档(例如 CLAUDE.md 或 CONTRIBUTING.md)。
  2. 照常采用框架约定。 如果框架规定路由放在 routes/、模型放在 models/、测试放在 tests/,就遵循这些约定。除非框架的约定确实不适用,否则不要自行设计布局。
  3. 采用可预测的命名。 如果用户表对应的处理程序叫作 users.rs,测试就应放在 users_test.rs 中,迁移应引用 users,API 端点应为 /users。可预测的命名是一种能省去搜索的约定。
  4. 默认采用常见情况。 配置选项应提供合理的默认值,满足 90% 的使用场景。只有对确实存在差异的 10% 场景,才要求显式配置。
  5. 尽量减少特定环境的配置。 开发、预发布和生产环境之间的差异应尽可能小。特定环境的配置是导致“在我的机器上能运行”这类 Bug 的主要原因之一。
  6. 将配置视为代码。 配置文件应像代码一样纳入版本控制、接受审查并经过测试。如果更改某个配置值可能导致服务中断,就应像审查代码变更一样严格审查。

反模式

  • 配置驱动的架构: 系统行为由 YAML 文件中数以百计、无人能完全理解的配置项决定
  • 不一致的项目结构: 每个模块的组织方式都不同,因为“开发者更喜欢那样”
  • 重复造轮子: 在已有且足够适用的标准工具可用时,仍自行编写构建脚本、测试运行器和部署工具
  • 事事都用功能标志: 把每个决策都包装成功能标志,“以便以后更改”,尽管决策早已确定
  • 未记录的约定: 代码库中存在某些模式,却没有写下来,导致新团队成员在不知情的情况下违反这些约定

示例

-- Over-configured: every handler specifies its own middleware stack
app.route("/users", handler=users, middleware=[auth, logging, rate_limit, cors])
app.route("/orders", handler=orders, middleware=[auth, logging, rate_limit, cors])
app.route("/products", handler=products, middleware=[logging, cors])  # oops, forgot auth

-- Convention: default middleware applied globally, exceptions are explicit
app.use([auth, logging, rate_limit, cors])   # convention: all routes get this
app.route("/users", handler=users)
app.route("/orders", handler=orders)
app.route("/health", handler=health, skip=[auth])  # explicit exception
-- Over-configured: every test specifies database setup
def test_create_user():
    db = connect("postgres://localhost:5432/test")
    db.migrate()
    db.seed("users.sql")
    ...

-- Convention: test framework handles setup, tests just test
def test_create_user(db):   # db fixture provided by convention
    user = create_user(db, name="Alice")
    assert user.name == "Alice"

边界

  • 约定不代表僵化。 随着团队和项目的发展,约定也应随之演进。定期审查并更新约定。
  • 有些内容必须配置。 数据库 URL、API 密钥、用于逐步推出的功能标志,以及特定环境的设置,确实需要配置。本原则旨在尽量减少不必要的配置,而不是彻底消除配置。
  • 约定必须易于发现。 只存在于某位开发者脑海中的约定不算约定,而是陷阱。请将它们写下来。
  • 与灵活性的张力: 面向多样化使用场景的库和框架,适当增加配置是合理的。应用代码中的配置则越少越好。

代码审查清单

  • 此更改是否遵循项目既定的模式和约定?
  • 如果引入了新模式,是否对其进行了记录并说明理由?
  • 是否可以用合理的默认值替代某些配置选项?
  • 文件/模块结构是否与项目的其他部分保持一致?
  • 新团队成员能否根据项目约定预判这段代码的位置和结构?

相关技能

  • boy-scout-rule:用于逐步维护约定
  • separation-of-concerns:用于结构约定本身
  • kiss:用于约定应默认采用更简单的选项时

评论

支持 Markdown