mcpField
C
clojure-write

clojure-write

github.com/metabase开发49.9k2.0k 次安装今天更新
代码仓库

关于 clojure-write

面向 Metabase 贡献者的 Clojure 开发技能,指导通过 REPL 编写和测试代码,并提供文档字符串、代码编辑和模块边界方面的项目规范。

主要功能

  1. 01优先使用可用的 clojure-mcp 工具
  2. 02通过 REPL 编写并测试函数
  3. 03编写面向调用者的文档字符串
  4. 04Clojure 编辑与模块边界检查

适用场景

  1. 01开发和测试小型 Clojure 函数
  2. 02编写或修改函数文档字符串
  3. 03按项目规范编辑代码

MCP 相关

该技能建议在可用时使用 `clojure_eval`、`clojure_edit` 等 clojure-mcp 工具;否则使用 `./bin/mage`。

安装

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

$npx skills add https://github.com/metabase/metabase --skill clojure-write

安装后在 Claude Code 中输入/clojure-write确认已加载。

详细介绍

Clojure 开发技能

工具偏好

当 clojure-mcp 工具可用时(例如 clojure_eval、clojure_edit),始终使用它们, 而不是像 ./bin/mage -repl 这样的 shell 命令。MCP 工具提供:

  • 直接集成 REPL,没有 shell 转义问题
  • 更好的错误信息和反馈
  • 结构化 Clojure 编辑,防止语法错误

只有在 clojure-mcp 不可用时,才回退到 ./bin/mage 命令。

@./../_shared/development-workflow.md @./../_shared/clojure-style-guide.md @./../_shared/clojure-commands.md

REPL 驱动开发工作流

  • 从小而基础的功能开始:
  • 确定任务所需的核心功能或特性。
  • 将每个特性拆分为可以独立开发和测试的最小、最基础的功能。
  • 在 REPL 中编写并测试:
    • 直接在 REPL(Read-Eval-Print Loop)中编写每个小功能的代码。
    • 使用各种输入对其进行充分测试,包括典型用例和相关边界情况,以确保其 行为符合预期。
  • 集成到源代码中:
    • 一旦某个功能在 REPL 中正常工作,就将其从 REPL 环境移到你的源代码文件中(例如, 放入适当的命名空间)。
  • 逐步增加复杂度:
    • 在已测试的基础功能之上构建更复杂的功能或组件。
    • 将较小的功能组合在一起,在 REPL 中测试每一个新的组合,逐步验证正确性。
  • 确保依赖测试:
    • 确保每个功能在被其他功能依赖之前,都已在 REPL 中经过充分测试。
    • 这样可以确保应用程序的每一层在你在其之上构建之前都是可靠的。
  • 充分利用 REPL:
    • 将 REPL 作为你的主要工具,用来尝试不同方法、快速迭代,并即时 获得代码反馈。
  • 遵循函数式编程原则:
    • 保持功能小而专注、可组合。
    • 使用 Clojure 的函数式编程特性——例如不可变性、高阶函数和标准 库——来编写简洁、有效的代码。

如何评估代码

自底向上的开发循环
  1. 将代码写入文件。
  2. 评估该文件的命名空间,并确保它能正确加载:
./bin/mage -repl --namespace metabase.app-db.connection
  1. 使用测试输入调用该命名空间中的功能,并观察输出是否正确 随时可以使用 deftest 和 is 将这些 REPL 会话试验复制到实际测试用例中。
  2. 一旦你确认这些功能没问题,就回到第 1 步,将它们组合成你需要构建的任务。

编写文档字符串

文档字符串是面向调用方的契约,而不是实现者的日记。它说明函数做什么、接收什么、返回什么、抛出什么,以及调用方必须遵守的前置条件/不变式。这些保证和要求理应放在那里 —— 它们正是调用方需要在 IDE 中看到的内容。

当你发现文档字符串中包含实现上下文时,默认做法是将其迁移,而不是删除 —— 把它移到函数体中真正相关位置的inline comment。这些上下文往往确实有价值;只是放错了地方(调用方不应该读它;站在那一行的实现者才应该读它)。只有当它是废话时才直接删除:自我吹嘘、复述显而易见的内容,或记录一个本应默认具备的属性。

关于最后一种情况 —— 像"可在所有受支持的 appdb 间移植"这样的属性叙述不配占一句话。如果它不可移植,那要么是个 bug,要么意味着调用方必须自行处理每种情况 —— 而在那种情况下,需要记录的是该属性的缺失。记录与预期的偏差,而不是对预期的符合。

启发式方法 —— 只有当一句话同时通过以下两项测试时,它才配出现在文档字符串中:

  1. 重写测试(必要但不充分):如果用具有相同契约的不同实现重写函数体会使该句变为假,那么它描述的是实现,而不是契约。将它迁移到函数体中它适用的位置,作为inline comment。

  2. 归属测试:如果该句陈述的是关于此函数并不拥有的代码的事实 —— 被调方的行为、某个库的保证 —— 那么它在任何重写下都轻松成立,这正是仅靠重写测试不够的原因。如果此函数体依赖该事实,那它就是实现上下文:将它迁移到调用点。如果这里没有任何代码依赖它,那它就是关于别人代码的废话:删除它,让被调方自己的文档字符串来回答。

每个事实只说一次。重复的文字就是提前写好的过期注释:当事实发生变化时,一处被更新,其余各处悄悄腐烂。这甚至适用于你自己拥有的代码 —— 一个命名空间文档字符串反复总结自己的多重方法,三个同级函数带着关于重试行为的同一段文字。给每个事实一个归宿,其他地方提及它即可,而不是复述它。

多行文档字符串并非被禁止 —— 代码不得不应对的真正不显而易见的约束可能值得解释。但要谨慎;失败模式是细节过多。当你想写多段式解释性文档字符串时,先与用户确认。并且宁可用测试而非文字:如果未来的读者认为"这是个愚蠢的做法"并改了它,测试应该失败并告诉他们原因。如果这种破坏反复发生,那才是需要注释的信号。

编辑的关键规则

  • 编辑 Clojure 代码时要小心括号计数
  • 每次修改 Clojure 代码后,用 -check-readable 验证可读性
  • 所有文件以换行符结尾
  • 编辑表格化代码时,若各列对齐,尽量保持对齐
  • 行末没有内容时不允许有空格
  • 更改模块边界后(添加/删除/重命名 src 命名空间、跨模块 require 或 :model/X 引用,或新增模块),运行 ./bin/mage fix-modules-config 以重新生成 .clj-kondo/config/modules/config.edn 并保持 metabase.core.modules-test 通过。若无偏差则为无操作; 参见项目 CLAUDE.md 中的"Module Boundaries"。

评论

支持 Markdown