• 这里是沃基

    今天介绍一个在ai时代非常重要的实践

    现在因为有了ai,代码变得非常便宜,一个模块写完的时间可能只有几十分钟,代码写好了,可能也会写单测,看着通过率100%很美好,但是最后发现,他测试的根本不是你想测试的东西

    什么是TDD

    在说这次分享最重要的东西前,先简单介绍一下tdd,tdd的中文名字是 测试驱动开发 ,意思是用一个非常简单的循环来测试一个很小的模块或者流程

    这里介绍一下设计到的名词:

    红测:必定失败的测试用例,在开发某个需求前维护

    绿测:在需求写完后进行测试,如果成功了代表通过

    TDD 真正的产物不是测试本身,而是你写出测试所体现出来的设计意义:

    首先如果你能为一段逻辑写出简洁的测试时,说明它的边界是清晰的、职责是单一的。如果写不出来可能就是你设计的不行

    红测的必要性

    经过刚刚的抛砖引玉,现在开始进入正题

    在旧时代(指的是ai发展以前),这个东西用的比较少,是因为单测很多时候写的太慢了,而且很繁琐,需要专人去写,非常麻烦,但是现在ai发展了写的非常快,但是也带来了一些问题

    为什么需要红测

    1,ai代码带来的不可靠性

    人写代码的时候,速度本身不快,并且自己本来就会有审查的机会,但是agent不会,一小时几千行都是洒洒水,如果agent写出来自认为对的代码,就会带来很多的线上问题

    2,"假绿"的结果,我说对就是对的

    我认为这里是这篇分享最最最核心的地方,什么意思呢,你让ai写一个单测,他是基于代码写出来的,他是一个揣着结果来为了结果构造出来的结果,就像是一场比赛,如果他又当运动员又当裁判,那就没救了,写出来的单测都不好意思叫单测了

    Agent 无法靠自己验证"我们是不是在做对的东西,它只能验证代码是否符合用例

    我们应该怎么做

    1,在正确的时期写正确的东西

    在计划期写用例,写一些必定失败的用例,这就是红测,代表你在实现需求前,一定是不满足的,可以显著避免agent沉迷在自我的幻想里面

    我们要把bug或者是需求,当成检查.如果一开始写的红测居然绿了,那么有问题的就不是agent而是使用者了,你现在就应该停下写代码,来好好看看是不是哪里错了

    2,用前后的结果架起前后的联系

    当需求/bug写完了之后,重新跑同一个单测,发现由红转绿,就说明你改的东西是生效的,是影响单测的根本原因,如果还是红的,说明你的代码实现的有问题

    这里最重要的是,绿测只代表了结果态,而红测代表了起始态,如果结合到了一起才代表了你的需求/缺陷的状态流转

    为什么要写单测

    这里分享一些题外话,没有必要去一味的追求单测什么的,单测的用处很多就是要报错的,你现在写的单测代表了现在的agent的思考,未来报错了,就说明老的agent和新的agent产生了思考的碰撞,单测也是一个长期的设计,也许有一些实现的问题有一些问题,比如

    选择错jdk了,然后当成红测

    什么时候应该用单测,什么时候应该连数据库做自动化测试

    前后端,可能因为前端的问题导致接口报错

    等问题,这些问题,本文暂不讲如何解决,仅针对思考.

    总体而言,tdd在ai时代是一个利大于弊的设计,期待给各位佬友带来启发

    主楼
  • LaiMing

    请教一下,实际案例,同样的需求,我用的是deepseek,然后使用的sdd,吭哧吭哧的花了不少钱才完成的项目,我朋友用豆包,半天就实现了,当然他就是实现的功能,而且他还不是程序员。这个打击和挫败感太让人悲愤了,大佬些怎么看这事呢?

    #1
  • 这里是沃基

    首先,功能是不是一样的,设计思路是不是也是一样的吗,如果仅仅只是为了一个需求而不考虑后面,其实没有什么用,以及为什么会有这个问题,是他的需求描述的更清晰吗?这些都有考量的

    #2
  • Doubleflower

    不需要对比啊佬,做自己认为正确的就行 ^-^

    #3
  • errorcode

    根据实战经验让ai做了一些重构检查的提示词,其中比较有用的是,业务驱动重构审查。

    内容很多,我复制其中一段:```


    name: business-driven-architecture-review
    description: >-
    业务驱动架构评审与扩展 (Business-Driven Architecture Review & Extensibility)。
    用于对代码库进行业务驱动的架构评审、接口解耦、依赖分析与扩展性重构。
    提供“收敛无序变化、规整为灵活扩展”的思考模型与“双维依赖拓扑分析”(架构层单向无环图 vs 业务层因果/事实/生命周期依赖)。
    针对商业化、国际化、多租户等 A/B 差异场景,提供四把架构探针与三层 Context 收敛;
    针对系统演进期新旧对象共存与数据迁移难题,提供“防腐网关(ACL)”、“渐进式委派替换(单向委派外壳)”、“多活动实例状态分歧防范(单实例原则)”
    与“JIT 级联读时自愈零双写”等工程协议。
    当用户提到“架构评审”、“解耦”、“策略模式”、“业务扩展”、“接口重构”、“防腐网关”、“破坏性重构”、“兼容性升级”、“依赖分析”或“收敛变化”时激活。


    业务驱动架构评审与扩展 (Business-Driven Architecture Review)

    本技能为架构师和高级开发人员提供一套“从业务需求与代码现状出发,识别无序变化,规整为灵活扩展与最小侵入架构”的系统化方法论与思考技巧。


    核心心智模型:无序变化收敛法则 (Disorderly Variation Convergence)

    在需求演进中,业务变化往往以“无序”形态涌入:增加海外版、增加企业租户、增加自研提示词、增加支付渠道等。
    开发人员最常犯的错误是将变化直接追加到现有函数入参或核心流程的 if-else 中,导致接口腐烂与抽象泄漏。

    架构师必须掌握以下五大核心思考技巧:


    思考技巧一:识别无序变化的“四把架构探针” (The Four Probes)

    当审查现有接口、评估新业务 A/B 扩展或分析模块间复用性时,强制对目标函数/接口运行以下四项检查:

    1. 参数不对称度探针 (Parameter Asymmetry Probe)

    • 检测机制:检查接口入参中,是否有参数在某个具体实现中被使用,而在其他实现中完全闲置、传 None、或被直接丢弃?
    • 判定法则:只要出现不对称参数(如国内版不需要 stripe_token,海外版不需要 invoice_tax_number),即证明**特定实现细节已经逆向绑架了

    公共契约**。
    * 危险信号:方法形参列表中出现超过 3 个可选参数(如 arg1=None, arg2=None)。

    2. 专有名词泄漏探针 (Leaky Abstraction Probe)

    • 检测机制:扫描接口方法名、形参名是否包含了第三方供应商名称、具体地理区域、或特定底层技术?
    • 判定法则:如出现 stripe_token、wechat_pay、us_zipcode、openai_key,说明该接口不是面向调用者的业务意图,而是面向具体的供应商/

    技术实现。通用契约必须剥离此类专有名词。

    3. 新增场景冲击推演探针 (Ripple Effect / Churn Simulation)

    * 推演机制:进行思想实验:

    “假设明天新增一个业务形态 C(如:离线私有化部署 / 新增虚拟货币结算),它需要全新的入参字段。当前接口签名是否必须修改?已有的业务 A 和 B

    实现是否需要同步修改方法签名?”
    * 判定法则:如果新增 C 会导致接口契约及其上游调用方、其他不相关策略类全部被重新改动,说明架构缺乏“开闭原则(OCP)”,必须立即重构。

    4. 算子输入不变性探针 (Operator Input Invariance Probe)

    • 检测机制:当评估两个业务场景或模块是否能复用某个核心算子/能力时,检查该算子的本质最小输入(Minimal Required Input),而非其上游宿

    主所采用的数据容器形态(Container)。
    * 判定法则(破除容器形态障眼法):
    如果业务 A 是线性数组(如 slidingMessages: Message[]),业务 B 是树状分支(如 ChatTree DAG),但下游算子(如 MemoryCompactor 上下文
    压缩器、AuditAgent 质检器、ContextOptimizer)实际消耗的仅仅是“一段按时序排列的轮次列表(Sequence<Message>)”,则二者在计算语义上
    完全等价。
    * 危险信号:
    因为“一个是树、一个是列表”、“一个是单会话、一个是图”等外在容器差异,就草率断言“业务不同无法复用”,转而在两个模块各自手写一套孤立、重复且
    维护不同步的压缩/清洗/调度逻辑(数据结构宿命论)。


    思考技巧二:规整为 Context 的“三层结构模型” (Three-Layer Context)

    发现参数爆炸与接口泄漏后,不能简单地走向另一个极端——将参数打平成弱类型的 ctx: dict 或 ctx: Any(失去类型安全、失去自动补全,沦为“运行时
    盲盒”)。

    必须引导架构收敛为兼具稳定性、类型安全与扩展自由度的三层 Context:

    ┌────────────────────────────────────────────────────────────────────────┐
    │ ExecutionContext (上下文) │
    ├────────────────────────────────────────────────────────────────────────┤
    │ Layer 1: 全局不变量 (Core Invariants) │
    │ - trace_id, user_id, tenant_id, locale, timestamp │
    │ (全生命周期稳定,任何业务策略 A/B/C 必然需要的身份与追踪凭证) │
    ├────────────────────────────────────────────────────────────────────────┤
    │ Layer 2: 业务领域事实 (Domain Payload) │
    │ - order_id, prompt_text, amount │
    │ (通用业务输入,不依赖任何特定实现的业务事实) │
    ├────────────────────────────────────────────────────────────────────────┤
    │ Layer 3: 策略私有扩展载荷 (Variant Extension / Typed Extra) │
    │ - stripe_token, custom_model_params, offline_license_key │
    │ (专属于特定策略实现,由具体策略自行解包与校验,不污染公共接口签名) │
    └────────────────────────────────────────────────────────────────────────┘
    ...```
    #4

发表回复

登录后回复