做开发这些年我越来越觉得决定代码质量的往往不是某个框架多先进而是从拿到需求到上线的整条链路有没有一套固定的思考方式。我管自己沉淀下来的这套流程叫 t3code不是什么黑科技就是一个带着三个 T 的编码工作流拆任务Task、写测试Test、留痕迹Trace。这套方法不只适合一个人写玩具项目团队协作时尤其能减少反复改动的成本。这篇文章就把这套流程拆开讲透包括我是怎么组织目录、怎么用 AI 辅助写代码、怎么设计日志和排障。适合写过几年代码但总觉得项目越改越乱的人也适合刚带小组想统一规范的同学。1. t3code 的整体设计思路从“能跑”到“能长期维护”很多项目第一版跑起来都很快慢的是后面每次改需求都要连着崩几次。t3code 的第一原则是把“写代码”这件事拆成三段先拆任务再写测试最后做追踪。这三段不是流水线而是互相咬合的标准任务拆清楚了测试才知道测什么测试写得够细追踪才知道该埋什么日志。1.1 先拆需求再写代码到底拆什么我见过太多人拿到需求直接开写写了一半发现“用户可能没有权限”“这个字段可能是空的”“这个接口被调用失败怎么办”……然后被迫停下来补逻辑。t3code 的做法是在动手前花 15 到 30 分钟把需求拆成任务卡每张任务卡都包含三块内容输入条件、业务规则、异常分支。输入条件不只是参数类型还包括状态。比如“用户提交订单”这个需求输入条件要写清楚用户是否登录、购物车是否为空、库存是否充足、支付方式是否有效。业务规则写清楚正常路径下每一步怎么走。异常分支则是让你主动去想库存不够时是拒绝还是锁定支付超时是重试还是标记失败把这些先列出来代码就不是“边写边想”而是“照着清单填坑”。我自己的习惯是任务卡里还要加一个“不做清单”。比如“这次不做取消订单”“这次不做自动退款”。这个清单能挡住需求蔓延也方便后面评估改动范围。很多人以为拆解会拖慢速度实际上省的是调试和返工的时间尤其是接老项目的时候拆解一遍等于把技术债也顺带摸了一遍。1.2 用测试定义“写完”而不是靠“运行通过”“写完”的标准如果是“程序不崩了”那这个标准太低。t3code 里的 Test 不单指单元测试而是验收测试、边界测试和回归测试加起来。我在实践里习惯给每个任务卡配至少三个测试一个测主流程、一个测边界条件、一个测异常分支。三个测试都过了才叫“写完”。边界条件是最容易漏的也是最容易在线上出事的。比如列表接口的 limit传 0 怎么办传负数怎么办不传怎么办给这三个情况各写一条测试代码质量立刻不一样。异常分支也一样第三方接口超时、数据库连接失败、消息队列延迟这些不是“不会发生”的意外是系统运行中的常态。写测试还有一个隐藏价值逼你把代码写得可测试。如果一个函数里全是外部依赖、全局变量、随机时间测试根本没法写。为了让测试能跑你只能把依赖注入、把纯逻辑抽出来、把外部副作用隔离这就是倒逼着改善架构。所以我常说测试不是为了求一个覆盖率数字而是为了让代码长成对的样子。1.3 留痕迹日志、指标和链路缺一不可第三 T 是 Trace。很多人只在报错的时候打印日志平时日志里净是些“进来了”“走了”这种废话。t3code 的追踪设计是三层对外可观测的状态、内部关键节点的日志、以及上下文标识的传递。对外可观测状态说的是健康检查接口、基本指标、核心流程的成功率。内部关键节点日志记录的是每个业务动作的入参、结果、耗时。上下文标识是说同一个用户请求从入口到数据库这一整条链路上都要带着同一个 request_id。这三个做扎实了线上出问题才能“按图索骥”而不是靠肉眼翻日志猜。我一开始也觉得日志晚点补也行但真正踩过坑之后才知道如果发布前没设计好追踪出了问题只能加日志重新发布一次就够让人长记性。所以现在 t3code 里Trace 和 Task、Test 一样重要它不是事后补救而是代码的一部分。2. 工程目录与模块边界让代码住进该住的地方代码烂不烂看目录结构就知道。t3code 在工程组织上不追求花哨的架构只追求三件事按业务切分而不是按技术切分、配置与代码隔离、依赖方向清晰。能做到这三点项目就坏不到哪儿去。2.1 按业务能力切分目录而不是按 controller/service/dao 切分很多项目的目录是 controller、service、dao 这种按技术层来分的结果就是改一个下单功能要在 controller、service、dao 三个目录里各找一遍文件再顺手改几个别的模块的文件最后 merge 全是冲突。t3code 建议按业务能力切分比如 order、user、payment、inventory 各成一个模块每个模块内部再分 controller、service、repository 这类子目录。这样改一个功能不需要跨目录翻所有相关代码都在一个模块里。比如订单模块需要和库存模块通信走的是模块之间的接口而不是直接去拿库存模块的表。模块边界清晰之后代码 review 也好做这个订单模块里的改动到底是不是订单相关的如果不是就说明边界破了。repo/ modules/ order/ controller/ service/ repository/ domain/ user/ controller/ service/ repository/ domain/ payment/ controller/ service/ repository/ domain/ common/ config/ error/ util/ docs/我第一次这么重构的时候最大感受是“找文件”的时间少了三分之一。以前新同学接手项目要问“这个逻辑在哪”现在他自己能顺着模块名找到。更重要的是每次改动的影响范围变得可预估因为模块边界把不该有的跨层依赖挡在了外面。2.2 配置隔离与接口契约把“变量”赶出代码配置隔离这件事听着简单做起来很容易跑偏。最常见的反面例子是把数据库密码直接写在代码里或者把开关逻辑写成if (env prod)。t3code 的做法是所有环境相关的东西一律走配置中心或环境变量代码里只留config.get(db.password)这种抽象。接口契约指的是模块之间、服务之间通信时不要隐式依赖对方的字段。比如订单模块要拿用户模块的手机号就直接调用用户模块提供的接口不要自己去查用户表。接口的返回值要有明确的 schema字段命名统一列表和分页结构统一。这样才能保证一个模块改内部实现时不会炸掉别人的代码。配置隔离的另一个细节是不要把配置变更和发版绑死。比如一个接口的超时时间如果写在代码里调一次就要发一次版如果放到配置中心改动立即生效。t3code 会把“哪些参数允许运行时调整”提前列出来通常是超时时间、重试次数、流量比例、开关标识这几类。2.3 脚手架初始化把规范固化成模板口头规范靠不住人一累就忘。所以 t3code 的第三件事是做脚手架模板把所有目录结构、基础依赖、统一日志格式、错误码包装这些规范直接固化到模板里。新项目只要基于模板生成起步就是在规范之内。脚手架里我最看重两样接口返回结构的标准封装和错误码的规范定义。接口返回我一律用{ code, message, data }包裹不管成功失败结构都一样。错误码不是随便给个数字而要按模块划分段位比如用户模块 1000 段、订单模块 2000 段。这样看错误码就知道是哪里出的问题。模板还要带一个最小闭环示例一个简单的接口、一个单元测试、一个日志输出样例。后来别人用模板时直接照着这个示例改就行不用翻文档猜“最佳实践”。这个模板逼着我把自己的经验沉淀成可复制的东西比写十篇内部文档管用。3. AI 辅助编码的实操要点让工具干活让大脑把关这两年 AI 辅助编码已经成为日常但同样用 AI有人效率翻倍有人改 bug 比手写还慢。t3code 对 AI 的态度很简单把它当成一个特别快的同事而不是一个全知的权威。用它写样例、写模板、写测试但责任始终在自己身上。3.1 提示词的上下文组织把任务卡喂给 AI我试过很多人抱怨 AI 写出来的代码不能用其实问题多半出在提示词太笼统。“帮我写一个下单接口”这种话换作一个刚入职的同事也做不好。AI 需要的不是一个指令而是上下文加约束。t3code 的做法是把任务卡的内容改造成提示词。一个支持字段角色资深后端工程师任务实现订单提交接口输入条件用户已登录、购物车非空、库存可锁定业务规则先锁库存、再创建订单、失败则回滚异常分支库存不足返回 2001重复提交返回 2002约束使用现有框架、遵循统一返回格式、不许引入新依赖测试要求补主流程、边界、异常三个测试这样组织一下AI 生成的代码基本能跑到 70 分。剩下 30 分靠人工审查。我建议少问“怎么写”多问“按这些约束写”因为后者把模糊空间压缩了AI 就少了很多自由发挥的机会。3.2 生成代码的审查清单不能只看“跑不跑得通”AI 生成的代码最坑的地方是表面正确。比如一个查询接口AI 可能给你套了两层循环数据少时跑得通数据一多就炸。t3code 审查清单里我第一眼看性能第二眼看异常处理第三眼看命名和结构。性能方面要看有没有重复查询、有没有 N1、有没有把可以合并的循环分开写。异常处理方面要看数据库操作有没有事务、外部调用有没有超时和重试、边界输入有没有校验。命名和结构方面要看变量名是否表意、函数是否太长、有没有把业务逻辑写在 controller 里。这三个审查项不是吹毛求疵是 AI 最容易犯的毛病。还有一个诀窍让 AI 生成测试再反向验证代码。比如让 AI 写出“输入参数 limit -1 时”的测试如果代码没过说明校验没做对。这个方法特别适合抓 AI 代码里的逻辑漏洞因为 AI 生成的代码通常能过主流程但边界条件它是真的看不见。3.3 测试闭环AI 写测试我造数据AI 写测试也容易跑偏最典型的就是测试里全是 mockmock 来 mock 去最后测了个寂寞。t3code 的做法是AI 负责生成测试框架和断言我负责造真实数据。测试数据尽量贴近生产比如用户 id 用真实长度的字符串订单金额用带小数和精度的情况。真实感数据能测出很多 AI 测试发现不了的问题。我曾经遇到过金额字段在数据库里是 decimal但代码里用 float 计算最后出现 0.30000000000000004 这种结果。这种问题用假数据 mock 永远测不出来。后来我的习惯是每个表都要准备一份真实数据种子测试里优先用种子数据。测试闭环还有一层意思是AI 生成的代码进主干前必须跑一遍全量回归不能只看相关的几个测试。因为 AI 改代码时经常不小心影响别的地方而且它自己意识不到。我现在凡是 AI 参与度高的改动都会多花一倍时间跑回归这个习惯救了我好几次。4. 错误处理、日志与可观测性让线上问题无处可藏代码上线之后调试的难度比开发时高一个数量级。t3code 把错误处理和日志当成和业务代码同等重要的功能来写而不是“顺手加一行 print”。这一部分我想聊聊错误分类、日志字段和监控取舍。4.1 错误分类与统一返回结构别让用户看堆栈我见过很多系统一旦出错就把异常堆栈原样返回给前端用户看到的是一大段英文。这不专业也不安全。t3code 的错误分类很简单就三类参数错误、业务错误、系统错误。参数错误是用户传错值业务错误是规则不满足系统错误是第三方或数据库挂了。这三类错误的处理方式完全不同。参数错误要给清晰的提示比如“价格必须是正数”。业务错误要给出业务语义比如“库存不足当前仅剩 5 件”。系统错误通常只给“系统繁忙请稍后重试”具体原因写进日志不能暴露给外部。统一返回结构用{ code, message, data }前端只认这个结构不用为不同错误格式写兼容代码。异常分类这块我还有一个实践每类错误单独定义异常类并带错误码。业务代码里只抛对应的异常由统一拦截器负责转成返回结构。这样业务层写起来很干净控制器里也不会到处都是 try-catch。表错误码分类参考错误类型错误码范围示例返回给用户的信息参数错误1000 - 19991001请输入合法的邮箱地址业务错误2000 - 29992003当前库存不足系统错误5000 - 59995001系统繁忙请稍后重试4.2 日志字段与上下文串联把散落的线索串起来日志最怕的是“看到错误但不知道是谁的请求、哪个环节挂的、耗时多少”。t3code 的日志设计有一个固定模板我用 JSON 格式保证机器可读也方便接入日志平台。每个请求在入口生成 request_id然后在整个调用链里一直透传。日志字段包不追求多但要全时间戳、服务名、request_id、用户标识、业务类型、方法名、入参摘要、出参摘要、耗时、错误码。特别说一下入参摘要不要把整个大对象塞进去否则日志量会爆炸签名只捞关键字段。我常干的一件事是把日志模板固化到脚手架里这样所有项目日志格式天生一致排查时不用每换一个服务就重新学一遍它的日志格式。链路追踪方面小项目不需要一上来就接分布式链路系统但 request_id 必须在入口生成、在日志里透传。等真出问题的时候用 request_id 把所有日志一搜整个调用链就拼起来了。这个简单做法成本极低收益非常高。我在实践中发现只要做到这一步排查线上问题的速度能提升好几倍。4.3 监控与报警的取舍先盯成功率别先看 CPU监控的坑在于指标太多反而不知道该看哪个。t3code 的监控结构优先级很明确核心业务流程成功率靠前之后再谈 CPU、内存、磁盘这些资源指标。理由很简单资源指标是果业务成功率是因。用户的订单提交成功率掉了比 CPU 涨了 5% 紧急得多。报警规则也要克制。我见过团队配了五十条报警规则结果每天半夜都在响最后所有人把报警群屏蔽了。t3code 的报警只覆盖三种情况错误率超阈值、核心流程耗时突增、服务不可用。阈值一开始可以放宽等到稳定运行一段时间再慢慢收紧。报警的意义不是把所有异常都告诉你而是让你在最需要的时候醒来。可观测性也不只是后端的事。接口的入参、出参、异常都会影响前端排查所以我在接口文档里会把错误码和对应的错误信息一起维护好。前端拿到 2003 就能直接告诉用户“库存不足”而不是“接口报错原因未知”。前后端协作顺畅一半靠的是语义化错误信息。5. 常见问题与排障速查实际踩过的坑和解决思路这一节把我在 t3code 落地过程中遇到的问题整理成速查既有技术问题也有流程问题。每个问题都附上排查思路方便你对照自己的项目看看有没有同样的症状。5.1 三个高频问题边界漏判、日志无效、测试失真第一个高频问题是边界条件漏判。症状是数据量小的时候一切正常数据一多出现各种莫名其妙的错误。排查思路是回到任务卡把所有输入参数列出来逐个问“如果这个是 null、空字符串、负数、超长字符串代码会怎样”把这些问题补上校验和测试基本能挡住八成线上问题。第二个问题是日志无效。需要排查的时候发现日志里全是“开始处理”“处理完成”这种无效信息或者没有 request_id根本串不起来。我现在的经验是日志模板里强制加 request_id、业务关键参数、耗时和结果。凑不出这四个要素的日志不如不打。很多公司日志量看着很多实际上能用的没几条。第三个问题是测试失真。测试全过上线照样炸。原因基本是测试数据和真实情况差太多mock 一切、忽略并发、用假日期、用超短字符串。排查思路是检查测试数据是否贴近生产以及测试是否正确模拟了故障场景比如第三方接口超时和数据库未响应。失真测试比没有测试更危险因为它给你虚假的安全感。5.2 排障自查清单从入口到出口一步步过t3code 排障时我有一套固定流程能覆盖大多数问题。第一步确认请求是否到达应用看入口日志有没有 request_id。第二步确认参数校验是否通过看有没有返回参数错误码。第三步确认业务逻辑走了哪个分支看关键节点的日志输出。第四步确认数据读写是否正常看 SQL 和缓存命中情况。第五步确认外部调用结果看下游接口耗时和状态码。很多问题用这套流程走到第三、四步就已经定位到了。真正难的是每次直接跳到最后一步去猜下游结果发现是自己代码里的校验漏了。我管这套排查流程叫“洋葱排查法”从最外层请求开始一层层往里剥。每一层都有日志排查就有抓手。我还养成了一个习惯凡是线上问题解决之后必定花十分钟写一条复盘记录。内容包括现象、原因、修复、如何避免。这个记录不是为了考核是为了以后遇到同类问题的时候能直接搜到答案。写了半年之后我的排障速度明显变快因为好多问题看着眼熟搜一下记录就知道怎么处理了。5.3 小型项目怎么落地 t3code不用一上来就铺全套如果你的项目只有几个接口不需要把所有规范一次性怼进去。我会先做最轻量的三件事统一返回结构、核心日志带 request_id、给核心流程写边界测试。这三件事就能解决大部分常见问题。等系统长到超过两万行再逐步引入模块化目录、配置中心、监控报警。轻量落地最怕是“为了规范而规范”。比如小项目也要上服务发现、也要搞链路追踪、也要拆十个微服务结果运维成本比开发成本还高。t3code 的精神是让规范为效率服务而不是反过来。我见过一个小项目用极简结构维护得非常好也见过大项目被复杂架构拖垮差别不在用了多牛的技术而在边界有没有守住。如果只让我留一条经验那就是把“想不到的边界”当成 bug 来对待。每次多问一句“如果这里输入不合法会怎样”“如果这里下游挂了会怎样”代码的质量就会稳定很多。t3code 表面上是一套工作流本质上是强迫自己用系统思考代替直觉写码。这个习惯养成了后面的工具、框架、架构都只是加速器而已。
阅读完成 · 觉得有帮助?