代码品味与架构设计
前情提要
这篇博客的思考来源于两个方面,一个提出了问题,一个解决了问题:
- 我在不久之前尝试 vibe 了一个 AI 游戏,在很好的遵守了我之前摸索出来的大部分经验的情况下,项目依旧理我的理想预期差很远(但是情况比上次好了,说明上次的经验是有用的)。
- 加到了一个在架构设计和代码品味两方面都表现相当好的佬的 QQ ,和他聊了一下相关的问题,收获颇丰,某种程度上知道了如何解决上面的情况。
之前的经验详情请看vibe coding 开发 BFE 后的反思与总结,先看这篇可以获得最佳食用体验,且里面干货同样满满(我自夸中,不符当没看到,谢谢您嘞)。
第一点中遇到的问题,颇有点像我上次推荐的当规则堆积成为智能的坟墓中提到的项目的腐化和不 review 代码导致的智能技术债务的堆积(这个博客的作者也是大佬来的,自己在开发一个 harness 项目)。 k10s 的负责人,最近删掉了目前所有的该项目的代码,也跟这个有关。虽然这篇博客更面向团队,但是由于我经验和能力都不太足,这个债务堆积的特别快。
代码品味
必须承认,我并没有 100% 按照上次的准则去做。我省略掉了最耗时间但是其实也是最重要的一步——开始之前对项目有整体了解的 chat 。我也在思考做了这一步会不会更好,但是缺乏实践,不能给出答案。但是我认为,我没有 chat ,一部分的原因也是不知道该 chat 些什么,前一篇博客在这方面略有不足,这篇博客,某种程度上解决了这个问题。
先说代码品味,一开始我以为佬会和我说,这是个很抽象回答不了的问题,只能靠自己的实践摸索。但是,佬并没有这么说,而是说了设计模式。由于本人接触设计模式是在学校的 Java 课程上,所以一开始并没有很明白,在我看来,我学过的那些设计模式,与 Java 面向对象编程这个特性密不可分,但不是所有语言都是以此为基础设计的,我认为代码品味应该是超脱于具体语言之上的一个东西。我提出了我的疑惑,佬也给了解答。真正要关注的是,这个设计模式为什么被提出,解决什么问题,而不是以什么具体的形式存在。是我没有悟性了,不得不承认确实设计模式对我来说还是抽象, Java 作为一门考察课,我图方便高效(因为我事太多了),理所当然的通过与具体的实现形式绑定来理解了。佬的话确实醍醐灌顶,虽然理解了之后,我反而开始认为,具体语言的代码品味可能并不能完全相通了,毕竟代码品味是要通过具体的实现展现出来的,但是这不妨碍设计模式是一个很好的切入口,无论对任何语言来说。只需要了解一下,一般设计模式要解决的问题,在这个语言里要怎么实现,就能开始逐步积累代码品味。
落实到 vibe coding 上来说,我的想法是,如果你真的奔着把这个项目做好,或者从项目的 vibe 过程中积累代码品味,亦或者项目本身具有一定复杂度的情况下,我都建议每次给 agent 的任务不要太多(比如逐功能添加)。并且每次让 agent 开始工作前,先和他探讨,这个任务最好用什么设计模式,有什么优缺点,有什么替代方案等,然后让他实现之后,跟你讲讲具体是要怎么实现,如果有不懂的可以接着问下去,刚刚 agent 的实践会成为你学习最好的例子和养料。
这个方案不一定好,也不一定对甚至,只是我个人的摸索,而我的定位是小白和萌新。所以对于大佬来说,这个方案无疑是低效的;对于其他小白和萌新,我也积极鼓励你们摸索其他方案,毕竟我这篇还在打上篇的补丁,说不定下篇就直接推翻这篇了。适合自己的才是最好的,保持思考。
但是还有但是,代码品味也确实没这么简单,终究是部分符合我对它的想象。佬还说,并不是使用了设计模式就是有代码品味,真正懂代码品味的人,是能够判断什么时候需要使用的人,甚至不使用也可以是有代码品味的一种体现。我翻译翻译,这有点像庖丁解牛。一开始当然做不到这样,甚至如果没有设计模式作为中间过渡,甚至连怎么变成这样都会毫无头绪。但只要不断地练习实践,就可以从一开始的学会使用设计模式,到判断什么时候该使用,到最后或许能做到对每个遇到的场景都能设计出针对性的模式。第三步当然有点理想,但是做到第二步就能算很有代码品味了。就像庖丁,一开始需要看着牛,到后面可以做到目无全牛,他就是一个很有屠牛品味的人(未成年牛请在成年牛的陪同下阅读本博客)。
架构设计
后面还和佬聊了聊架构设计。这其实要比代码品味具体的多,但还比代码品味还要难培养。因为在小白的小项目上,架构设计不会带来特别明显的不同,自然也会被大部分人忽略,大部分项目只能说有架构,却缺乏有意识地去设计架构。小白又很难有什么大项目,一般只有进公司之后,才能接触到大项目,但是在大项目的构建流程中,大部分人都是在架构设计好之后,负责实现的,很难说能够培养到自己架构设计的能力(说不定连其他整体架构是怎样的都无从得知,只能接触到自己要实现的部分)。还有一种方法是主动去看开源大项目的架构设计,然后通过思考培养这个能力。但是在没有 AI 的时候,大项目的体量是非常恐怖的,架构设计能力的培养并不是看形而上的抽象就够的,要深入到项目源码的细节里去体会,导致看大项目是一个非常费力不讨好的事情。在有了 AI 之后,确实让我们能够更快的了解一个大项目和它的源码细节,但是这利好的是那些非 AI native 者。对于我们这一代来说, AI 的出现让我们随着惰性避开了那些痛苦成长的时候,让我们哪怕有了 AI 读懂代码细节也不是易事。某种程度上也是吃力不讨好的事,所以很少有人主动去做。然而,人总不能一点痛苦不经历就获得成长。以后写代码的能力不再会是护城河,不想吃苦就算了,但架构设计这些以后的安身立命之本,哪怕痛苦也得主动去学去了解。痛苦和成长不会消失,只会转移。
佬推荐多去看看大项目的架构和相关博客,说出名的小初创公司的项目都可以看看。像 tailscale 就非常值得去看(这里还推荐这位佬的两个项目,虽然不大,但是在架构设计方面非常有巧思,分别是 frp-panel 和 Vaala AI Gateway )。多关注各种公司的博客,坚持读下来,总会有所收获。这里还推荐一个读项目的项目,叫做 deepwiki ,想认真读项目的读者可以了解一下。
好了,接下来是 vibe coding 部分!尽管对个人项目来说,架构设计确实可能无关紧要,但是为了培养能力,哪怕再小再简单的项目,我们也可以有意识的去做这一步。在我们提完项目需求之后,可以先问问 agent ,这个项目的架构可以怎么设计,有什么方案,如何抉择。这是一个非常好的学习架构设计,培养自己架构设计思维的过程。我不好说具体能起到多么显著的成效,但是起码能有所收获,坚持多了做到从 0 到 1 入门应该没有问题,很多时候其实我们缺的也只是这一块敲门砖。
有机结合
别看好像并没有往 vibe coding 这个流程中添加很多动作,但已经足以有一套比较不一样的实践思路出来。先提需求,不断通过交流或者其他方式明确需求。然后设计架构。再然后,就是和之前有点不同的地方。先把每个模块和其他模块的接口、协作方式和任务划分定义好,然后给每一个模块(或者耦合度低的几个部分),新开一个 session ,将之前的上下文 + 这个 session 要完成的模块需求输入进去。这么做的原因是,大名鼎鼎的上下文灾难。我之前 vibe 项目时也喜欢一个 session 用到死,觉得这里面包含了所有的上下文,是最懂我这个项目的 session ,重开 session 面临着很大的沉默成本。但事实上,虽然绝大部分 agent 平台都有压缩机制,并且不断完善,上下文灾难依旧无法避免。可能一次 compact 表现还不错,但是多次 compact 之后不出现偏移基本是不可能的。分模块开 session 虽然确实看不到其他模块的上下文,但是通过之前定好的接口和写作方式可以最小化这个的影响,并且由于每个模块的上下文都很干净,对于 agent 实际的提升完全可以覆盖掉前面那个影响。之后在每个模块的 session 内,再来交流使用什么设计模式。
如果你订阅了 GPT plus 这样的套餐,强烈建议你在做什么大项目之前,先在网页端走一遍“前置”流程,单纯只是生成项目需求文档等任务,网页端可以比 agent 做的更好(如果你还用 deep research 的话,那就更是如此)。后面等到真的要开始做了,可以让网页端给你总的和每个模块的 prompt ,这个 prompt 会更完善,项目也会更高质量。诚然会增加输入的 prompt 但我认为比后面反反复复修改增加输出 prompt ,这样显然更划算。
分 session 的模式,貌似非常像派 subagent ,我仔细想了想,确实可以做到,甚至可以做的更好。只要符合以下三点: subagent 是持续存在而不是用完就丢的,否则上下文缺失会很严重; subagent 的职责划分要明确清晰,主 agent 对于他们的调用和分派工作也应该分明;主 agent 和 subagent 之间应该保持最小信息交流,否则就是在同时污染两边的上下文。这三点并没有那么容易做到,当上下文越长时越难做到,人为去划分 session 更适合小白入门,或者直接去用设计成类似这样的产品。
额外内容
一个纠错:之前那篇博客中,我建议大家在项目开始之前写清楚项目级 instructions ,但这有两个问题,一个是遗漏,一个是冗余。没人能说自己在项目开始之前就能想到所有要注意的内容,和所有有价值提供给 agent 的内容。在项目开始之后,哪怕发现了遗漏了什么,也不一定能判断是否值得写入,以及能意识到这个可以写入。还有就是, instructions 某种程度上和 skills 一样,并不是一成不变的,要更新维护,以及检验是否真的有效,不然就是白费 token 。但是项目开始之前,是否有效不好验证,项目开始之后,更新不一定及时,也不一定有人去做。因此, claude code 官方更推荐在项目已经有一定规模之后,执行 /init 命令,让 agent 自动生成 Claude.md 文件(即项目级 instructions )。大部分前面提到的问题,都能通过这种方式缓解或者解决,对于小项目来说已经可以说是没有缺点,大项目则还需要定期维护。
一个补充:个人创作 skills 不只可以积累遇到问题时的解决方式,还可以先彻底跑通一次某个流程,再让 agent 把这个工作流固化成 skills 。

