Files
core/skills/references/development.md
T

10 KiB
Raw Blame History

项目开发

新建最小项目:

dever new my_app
dever fmt my_app --check
dever check my_app
dever test my_app
dever run my_app -- hello.greeting.greet '{"name":"Dever"}'
dever build my_app --output my_app/program
./my_app/program hello.greeting.greet '{"name":"Dever"}'

创建 Markdown 项目用 dever new my_app --markdown。两种模板使用相同代码和行为,Markdown 另加编译器校验的说明。目标目录必须不存在,父目录必须已存在;不接受向现有项目合并或覆盖。build 输出也必须不存在。

模板只包含 CMD、App、配置、一个测试和开发指引,无需数据库或 HTTP 服务。实际项目在它的目录合同上扩展,替换演示领域,删除不再使用的示例与测试。添加 HTTP 时须完成 站点与身份配置,不能只把 cmd 换成 get。

my_app/
  AGENTS.md
  README.md
  config/setting.json
  module/
    news/article/
      app.dever
      domain.dever
      model.dever
      port.dever
      adapter.dever
      job.dever
      api/
        admin/manage.dever
        front/browse.dever
  test/news/article/publish.dever

这是可用职责位置,不是要求创建全部文件。component、domain 和文件主题使用有业务意义的 ASCII 小写蛇形命名;类型用 PascalCase,方法和字段用 snake_case。不要增加任意第三层领域目录。组件按业务能力划分,领域按一致的数据和业务边界划分。组件、领域和主题不能命名为 common/shared/utils/helper/helpers/base/service/services 等编译器禁止的通用桶。

位置 责任和访问规则
App 跨领域公开能力,校验与业务编排;同领域用 app.publish,外部用 news.article.publish
Domain 同领域内部业务规则;纯计算优先放这里,不承接数据库/外部 I/O
Model 存储字段、索引、关系、迁移、Seed、静态 SQL;同领域 App 使用 ORM
Port 外部能力的类型、操作与失败合同
Adapter 实现 Port;私有,不反调 App/Domain/Model
API HTTP/CMD 入口绑定与自动 REST,无业务函数体
Job 持久任务声明,绑定同领域 App
Test 文件同名、零输入零输出的唯一测试入口

文件与函数组织

简单领域保留角色单文件;复杂角色可以拆为 app/publish.dever、app/search.dever 等内聚主题,调用名不带文件名。非 API topic 目录不递归。App/Domain/Port/Adapter/Job 单文件与同名目录二选一,选择目录时至少有两个内聚主题文件;Model/API 主文件与 topic 目录可按编译器合同共存,不受这个最少文件数限制。只有 api/ 可按站点和资源继续嵌套,目录会影响 URL。

一个文件可以包含多个相关类型、函数和分句。按完整业务主题命名,不机械地一个函数一个文件,也不为尚不存在的需求创建空 App、Domain、Port 或 Adapter。

抽取函数应表达独立业务规则、维护明确的不变量、复用已有逻辑,或隔离难以理解的复杂流程。只使用一次的函数也可以有这些作用;不能只因几行代码能起名字就再加一层。职责内聚的代码不按行数强拆,也不通过把所有逻辑塞进一个长函数来规避碎片化。

情况 处理方式
parse_id 重新手写数字解析并把失败悄悄变成 0 复用已有解析、名义 ID 和明确失败合同,不复制算法
trim_name 只原样转发一次标准 trim,没有新增合同 在使用处调用标准能力
page_slice 重复 Model 已有的分页规则 使用 Model 分页,不在各领域复制一份
publish 组织发布条件、状态变化和后续任务 保留完整 App 能力,把内聚业务规则放同领域 Domain
单次使用的规则需要独立表达有效期或状态不变量 可以抽取并按业务含义命名
两处相似代码承担不同规则、未来变化原因不同 保持各自归属,不为表面相似增加通用调度层

相同规则先复用现有所有者;只有真实共享的逻辑才抽象。跨领域共享能力由负责该业务的 App 提供,不直接调用对方私有实现,不为缩短调用名建立空转发链。普通 CRUD 直接用 Model 和 rest model;需要超出 Model 字段合同的输入转换、业务校验、关联操作或输出合同才增加 App 编排,具体见 应用规则。

配置与硬编码

数据或规则 归属
随部署变化的服务地址、端口、数据库连接、凭据 config/setting.json,不增加环境变量配置,不提交真实秘密
当前用户、租户、权限及资源归属 可信认证上下文、核心授权与 Model 策略,不接受客户端自报身份
有固定业务含义的状态、范围和规则 类型、互斥分句、字段约束或内聚 Domain 定义,复用同一规则
需要用户或运营维护的业务数据 项目 Model 与相应业务流程,不把具体记录写进源码分支
测试 ID、样例地址和固定结果 测试夹具,不作为生产失败时的兜底

禁止按某个账号、租户、记录的裸 ID、名字或地址开特例,例如用 user_id == 1 代替管理员授权。普通查询参数可以标识目标记录,但不能因此成为操作者身份或访问权限。

避免硬编码不等于搬走所有字面量。局部的 0、1、提示文字和稳定协议常量可以保留;有业务意义、难以理解或反复出现的值由现有类型或领域定义表达。只有确需运行时变化的值才增加配置。官方发行源是工具链固定合同,不能塞进业务 setting.json。

禁止绕过检查

  • 不添加假入口、无意义调用或仅供测试触达的调用,掩盖生产入口不可达的 App/Domain。删除本次废弃代码或接通真实业务调用链。
  • 不把重复业务逻辑转移到 Adapter、Python、JS 或 Go 来避开 Dever 检查。外部实现的质量同样需要审查。
  • 不吞掉失败、用空值或假数据冒充成功;有业务依据的恢复须使用明确结果合同,并验证恢复行为。
  • 不为通过检查擅自改 dever.api、删失败测试、弱化断言或关闭权限、类型及沙箱限制。确需改变公开合同,先说明调用方影响,在用户授权范围内同步实现、基线与测试。
  • 普通应用开发不修改编译器或核心库来容纳违规代码;语言或核心维护须有相应任务授权。只处理当前改动相关问题,不借机重写无关代码。

测试与检查

test/hello/greeting/greet.dever:

greet() () {
  assert_eq(hello.greeting.greet("Dever"), "Hello, Dever")
}

模板中的实际字符串以生成文件为准。测试只执行文件同名函数,不需要 main 或注解。assert 接受 Bool,assert_eq 要求同类型。测试可访问同领域 App/Domain,跨领域仅 App,不能直接写 Model CRUD。使用 Model 时运行器使用临时 SQLite;不使用 Model 时不需要数据库。它不会读取生产 setting.json 或生产 data。对业务失败使用 result(call) 配合 choice 分句验证。

常用命令:fmt --check 查格式,check 查语法/类型/目录/分句/配置,api 输出 API 合同,test 运行应用套件,run 开发执行,build 生成独立程序。不要发明 test --filter、run api 或 dever init。

验证范围

检查 能证明的范围
dever fmt <root> --check 源码格式;不证明类型或业务正确
dever check <root> 静态语法、类型、目录、命名、分句、相关配置、已有 API 基线,以及应用入口可达性和冗余硬检查;不执行应用
dever test <root> 当前项目全部应用测试的实际断言;没有筛选参数,不证明生产入口完整
dever run/build 通过与 check 相同的应用硬检查,再准备本地编译资源并执行或编译;成功不等于部署或性能验收
AI 审查 业务含义、职责拆分、复用、硬编码与验证范围,不能替代程序检查

check/run/build 共用 C016,拒绝生产入口不可达的 App/Domain,以及符合现有判定条件的私有空转发和 Model CRUD 包装;并非任意角色、所有函数或全部 CRUD 包装都能检出。check 不准备 Worker 或 runtime pack,不进行原生编译,不启动应用、服务或数据库。test 保持独立的测试入口与 Port fake 检查,不执行生产入口可达性检查;不能用测试调用掩盖生产死代码,也不能把静态检查当作运行验收。

W001–W005 等诊断包含未使用赋值、部分冗余条件、相同私有实现、重复纯调用和空转发建议,警告本身不会使命令失败。审查本次引入的诊断,修正有证据的问题;不能声称编译器能判定全部硬编码或业务价值。skill 中的开发要求不自动变成编译器硬错误。

选择与改动相符且已获授权的检查。新模板的小套件可以完整运行;已有大项目不默认运行全量 dever test,也不默认启动服务、连接真实数据库或压测。需要但尚未运行的检查要说明原因和剩余证据,不能伪报通过。已有 dever.api 时保留基线约束;dever api <root> --output <新文件> 可以导出待比较合同,不覆盖原文件。

源码放 module/,测试放 test/,部署配置放 config/,运行数据放 data/。生成程序从二进制同级 config/setting.json 读取配置。应用无需打包编译器;使用外部 Lib 时相关 runtime/依赖由 build 嵌入。只读 check 不证明真实数据库或部署验收。

核心与业务的区别

源码仓库 中,crates/dever-core 负责语言检查/编译,crates/dever-runtime 负责运行时,crates/dever-cli 负责命令,library/ 是随版本提供的标准 Dever 源码。维护中的完整业务示例是 examples/cms/dever 与 examples/cms/md;examples/old 是历史回归,不作新项目模板。

开发普通应用无需复制或修改这些核心目录。可复用业务组件作为 Dever Package;外部 Python/JS/Go 生态称 Lib。多个项目共享机器安装的 Dever。