ai时代开发小技巧(2)—-TDD设计,红测与绿测

这里是沃基 2026-09-20 11:15 1

今天介绍一个在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时代是一个利大于弊的设计,期待给各位佬友带来启发

最新回复 (4)
  • LaiMing 09-20 11:56
    1

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

  • 这里是沃基 楼主 09-20 13:09
    2

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

  • Doubleflower 09-20 17:51
    3

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

  • errorcode 09-20 18:15
    4

    根据实战经验让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:

    ```text
    ┌────────────────────────────────────────────────────────────────────────┐
    │ 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 │
    │ (专属于特定策略实现,由具体策略自行解包与校验,不污染公共接口签名) │
    └────────────────────────────────────────────────────────────────────────┘
    ...
* 帖子来源Linux.do
返回