先说结论
Go 版本暂时搁置了,Shell 版本继续用。
这不是一个轻松的决定,但也是一个不需要太多犹豫的决定。下面聊聊为什么。
当初为什么要做 Go 版本
Shell 脚本做到后期,已经膨胀到了一个很难维护的体量。一门没有类型、没有模块化、没有严格错误处理的语言,写到上万行之后,改一个地方就可能牵连一串意想不到的问题。
所以我们想用 Go 重写一遍——更好的结构、更可靠的执行、更方便扩展。
这个方向本身没有问题。
后来发生了什么
坦率说,Go 版本的开发过程比预想的要坎坷得多。
这个项目从一开始就是 AI 辅助开发的。 用 AI 写代码是整个行业都在探索的方向,它确实能让一个人做出以前需要一个小团队才能完成的事情。但它也带来了一些我们没有预料到的问题。
AI 生成的代码,表面上看起来能跑,逻辑也说得通,但在一些关键的细节上——特别是那些不容易在 demo 中暴露的边界情况——经常埋着隐患。比如底层的命令执行模块,采用了类似流式传输的设计思路,概念上很先进,但实际实现和真正的生产级标准之间有不小的差距。一些基础的接口设计也没有充分考虑实际使用场景,导致上层越写越别扭。
更要命的是成本。我们使用的都是当前最顶级的模型,写一个功能模块算下来就是实打实的算力开销。而这个项目是一个个人维护的开源项目,目前收到的全部赞助加起来也非常有限。为了控制成本,我们尝试了不同的模型组合,但不同模型写出来的代码质量参差不齐,风格也不统一。加上协作者各自使用的工具不同,最终拼在一起的代码,一致性很难保证。
这不是在找借口,而是真实情况。 AI 辅助开发让一个人能做到很多事情,但也让一个人更容易做出一个"看起来不错、实际经不起考验"的东西。我们在这个过程中的判断有失误。
代码本身的问题
抛开原因不谈,Go 版本代码本身的问题也是客观存在的。
写出来的东西能跑,但不够稳。
很多系统操作——比如改网络配置、清理存储、管理邮件服务——本质上是在对宿主机做高危操作。这些操作需要非常谨慎地处理参数、错误和回滚。但实际代码中,不少地方用的是"把参数拼成一条命令字符串直接执行"的方式,而不是更安全的结构化调用。
打个比方:本来应该用精密仪器操作的地方,用了胶带和扳手。平时看着没问题,但遇到边界情况就可能出事。
代码组织越来越乱。
一些核心文件膨胀到了上千行,菜单定义、参数校验、业务逻辑、界面交互全部混在一起。想改一个小功能,需要在一大堆嵌套代码里找上下文。想加一个新功能,只能继续往已经很长的函数里塞。
结果就是:代码能跑,但没人敢轻易动。而且并发模型的实现还有一些棘手的问题,在特定场景下会出现卡死的情况,开发调试起来非常痛苦。
如果继续做下去会怎样
坦率说,以目前的代码状态继续投入,大概率会变成这样:
- 改一个功能,坏两个功能。 代码之间耦合太紧,牵一发而动全身。
- 出了问题很难查。 错误信息不完整,日志串台,排查成本很高。
- 越往后越难改。 债务只会越滚越大,不会自己消失。
- 继续投入的成本和推倒重来差不多。 但推倒重来至少能从一开始就规避已知的坑。
与其在一个地基不稳的房子上继续加盖,不如先停下来想清楚。
所以我们怎么决定的
Go 版本暂时搁置,不再作为主力开发方向。
具体来说:
- 不再往 Go 版本里加新功能
- 不再对 Go 版本做架构层面的调整
- 如果发现严重的安全漏洞,还是会修
- 现有的 Go 版本代码不会删除,还能用
主力精力回到 Shell 版本。
Shell 版本虽然老,但经过这么长时间的打磨,核心功能是稳定的。接下来的迭代会继续基于 Shell 版本进行。
这是不是说 Go 白做了
不是。Go 版本的尝试让我们清楚地认识到了问题所在。这些经验会在未来的技术选型中发挥作用——包括怎么更好地利用 AI 辅助开发,怎么在效率和质量之间找到平衡,怎么在有限的资源下做出靠谱的东西。
只是在当前阶段,把有限的精力投入到一个代码质量过关的版本上,对用户来说是更负责任的选择。
最后
作为这个项目的负责人,我想对所有用户说一句:抱歉。
Go 版本目前的状态没有达到它应该达到的水平,这是我的判断失误。感谢每一位愿意试用、愿意反馈、愿意等待的用户。你们的信任是我最不想辜负的东西。
Shell 版本会继续好好维护下去。等时机成熟了,Go 版本——或者其他更好的方案——会再回来的。
感谢大家的理解和支持。