跳到主要内容

Go 项目刚起步时,包结构宁可少一点也别先分太细

· 阅读需 3 分钟
一介布衣
全栈开发者 / 技术写作者

很多人刚写 Go 项目时,最有安全感的动作就是先把目录搭完整:controllerservicedaomodelutils 先分好,觉得以后扩展会方便。可项目在功能还不稳定的时候,包分得太细,往往比全写在一个地方更容易把自己绕进去。

目录分层很整齐,不等于职责已经清楚

Go 的包边界一旦切出去,后面改动成本就会跟着上来。早期需求还在变的时候,如果你还没搞明白某块逻辑到底属于“用户域”还是“订单域”,只是因为习惯先拆成多层目录,很快就会出现到处互相引用、数据结构来回搬运的问题。

看起来目录很工整,实际上只是把不确定性提前固化了。后面每改一次接口,都要跨多个包调整,最后不仅没更清晰,反而更难读。

先按业务闭环聚合,比先按技术层切分更稳

我更愿意先从一个完整业务路径出发去组织代码。比如先把某个功能的入口、校验、存储、返回值放在一块,让它先形成可读的闭环。等到第二个、第三个功能出现,再观察哪些代码真的稳定复用,再考虑抽包。

这样做的好处是,你看到的是“这个功能需要哪些依赖”,而不是一开始就被迫决定“所有项目都必须长成 controller/service/repository 这套样子”。Go 本身就鼓励简单直接,过早把 Java 式分层套进去,经常得不偿失。

能先用具体类型,就别急着为抽象腾位置

项目刚起步时,很多抽象只是为了“以后可能会换”。但以后会不会换、值不值得换,通常要等业务跑起来才看得清。仓促把接口、通用模型、通用错误包装全抽出来,代码量一下子会膨胀,真正的业务判断却没变少。

如果当前只有一种实现,先用具体类型把流程走通,反而更容易看见哪些边界是真的。等你发现某一块被重复用到、或者测试替换成本确实高,再抽象也来得及。

小项目最需要的是改得动,不是看起来像“大项目”

我现在判断包结构是否合适,看的不是目录有多漂亮,而是改一个需求时要跳多少文件。如果一个很小的功能调整,需要同时改 handler、service、repository、dto、converter 五六层,那包结构多半已经比项目规模更复杂了。

Go 的包设计宁可后补,也别先透支。起步阶段少一点层次,往往能换来更短的修改路径和更清楚的业务边界。等代码真的开始重复,再拆也完全来得及。