3月底的Demo发布后,除了稍微休息了一下之外,就把整个代码清理了一遍,拿下面这张提交记录来讲,画绿框的是功能点提交,其他的都是代码清理相关的。
    refactor.png

    项目至今还是我一人独立开发,而自己的开发纪律性总体也是不错的,但是经过将近3个月的折腾,整个代码也有不少零零碎碎的问题,有些是有意为之,避免premature optimization,但也有许多是开发过程中没有注意,偷个小懒造成的。比如没有加上合理的类型声明,注释;使用了不一致的命名;对于空值处理逻辑不一致诸如此类。

    清理代码库就像打扫房子,每隔一段时间就应该打扫一次,但是即使坚持定期打扫,时间久了,房间还是会越来越乱。可以说大部分有点年份的项目里都有一些惨不忍睹的模块,比如中后台系统基本都会有的流程引擎(workflow engine)就是重灾区之一。因为流程引擎刚好同时具备好几个成为💩的特性:

    • 基础核心组件,应用范围广,只要业务需求里有流程逻辑,就需要用到。
    • MVP版本实现容易,手速快的话,一天内就能写完。
    • 各种实现细节,比如状态机的迁移,如何支持重试,回滚,如何保证具体流程,不同版本间的前后兼容。再加上scale上去以后的各种分布式问题等等。

    当年我在的Google Cloud SQL组就有一个这样的流程引擎,可以说是最让每个组员头疼的代码,一个创建备库的流程有10+的步骤,还同时被几个场景复用,主从,热备,备份恢复,Point-in-Time-Recovery (PITR),然后再乘以支持多个数据库引擎的分支。我偶尔还会惦记着这个模块现在怎么样了,砸在了谁手里。

    而代码腐烂的问题,toB领域往往又要比toC领域严重的多,一是toB领域的产品粘性更久,一旦上线很难被替换,外面去IOTIOE喊的火热,但是如果去看一下银行的最核心系统,绝大多数跑的还是IBM大型机, COBOL语言,DB2这套古老的配方。二是toB领域的业务逻辑要复杂的多,拿下拉框来举个🌰
    download.png
    toC应用里这样的框其实是很常见的,实现也比较简单,就是一个静态列表,最多加上一个联动的逻辑(比如城市的的列表要对应国家的选择)。但是如果放到toB领域里,这个场景就可能会复杂的多,比如放到当今火热的low-code,这个下拉框就要做成一个通用组件:

    1. 需要考虑展示各种不一样的列表,可能既有文字,又有图标。
    2. 而列表的每一项也都可以是动态的,比如根据上下文信息渲染出不一样的文字,这个就牵扯出了表达式(Expression)能力。
    3. 而列表的点击,选中又可以加上hook,这个就牵扯到了触发器(trigger)能力。
    4. 自动化,这个就需要引入脚本(scripting)能力。
    5. 支持第三方扩展,这个就需要插件(plugin)能力。

    而上面这些只是涵盖了使用态时下拉框的一些功能。toB软件不少还有一个单独的设计态,那就还需要另外一套逻辑。所以如果在一开始设计下拉框的时候,没有考虑全面,预留出设计空间,后面再加的时候,就需要靠打补丁的方式来做。

    而说到脚本(Script),忍不住再插一段。不少toB软件到了一定复杂度,就会引入脚本能力,而这其中最著名的当属JavaScript,这个当初Netscape给自家浏览器开发的脚本语言。笔者作为一个刚经历了3个月高强度前端开发,从JavaScript入门到嫌弃,再过渡到TypeScript的开发者,只能说微软发明的TypeScript让我可以忘记关于他的所有负面印象。

    代码变烂的另一个重要原因,是如今软件开发基本变成了一项集体活动,而多人协同研发就会带来不一致性。code review,代码自动化检测工具这些能解决的问题还相当有限,再加上软件尤其是互联网软件的人员流动,一个几年的项目光人员可能就换了好几拨,就好比一部漫画,前后两半是不同的作者,而就连一页上的上下左右4个分镜都是由不同的人画的。

    而到了toB软件里,代码变烂还有另外一个重要的推手,就是合并,toB领域的收购合并还是比较频繁的,几个toB软件的粪坑往往会合并连成一条粪池。

    所以虽然toB行业里,绝大多数领域其实都有很成熟的产品,但是看到新涌现的SaaS产品,还是完全没有反应的能力,有一个很重要的原因也是代码真的是多的烂的改不动了。回到我们的软件产业,虽然许多我们的工业级软件确实很薄弱,而市面上的竞品功能也很强大。但是只要有一个领域专家,加上一个架构师级别的程序员,再加上一个交互设计,一支精英小队从头开始,也是有机会挑战几百上千甚至上万人规模的行业领导者的。

    而我做的bytebase.com虽然市面上还没有找到明确对标的竞品,但也存在有类似功能的产品。之前也有了解这个领域的同学好心地关心对于那些产品怎么看,我倒是一点不紧张,因为那些产品都快存在10年了,研发人员换了一拨又一拨,代码已经腐化得很厉害了。10年前的产品理念,技术栈其实都很难嫁接到当前云计算,DevOps,Web在线协同化这套体系里。当上面的管理层画着一张张大图,想象着旗下的这些产品去攻城略地的时候,下面的程序员疲于奔命的是如何把手上的代码从💩坑里拖出来,有些只能是勉强维持不让这坨💩完全翻出来臭到更多的人。而结果又总是一拨程序员弃坑,换一拨程序员继续拖。而更让我关注的,是业界是否有新的团队也在做这个方向,不过真的出现的话,也很有意思,钟期既遇,奏流水以何惭?

    回到代码变烂的主题,变烂总是不可避免的,但是还是有一些对策可以减缓变烂的程度,几个我能想到的关键点

    1. 选择静态编程语言,并且限制语言的种类,前端选一种,后端选一种。
    2. 尽量少用技术组件,能用一个数据库扛的,就不要引入缓存服务。能用单机扛的,就不要用分布式。比如说如果数据库选择PostgreSQL的话,其实他具备了从OLTP, OLAP,Key-Value,Geo-Spatial,全文索引等一系列功能,单机足够支撑起一个中大型互联网服务。
    3. 尽可能使用云服务,开源服务,虽然对方的服务实现里面可能也有很多💩,但至少有了一层隔离。
    4. 架构上采用插件化设计,模块上多使用控制反转(Inversion of Control)范式。
    5. 采用自动化工具对代码进行自动修正或审查。
    6. 定期做代码清理。
    7. Code review,许多团队未必有条件做到每次提交review,但对于新成员的前面几次提交,核心的接口,数据库表结构设计还是很值得做的。

    软件作品,一半工程,一半艺术。而抵抗代码变烂,工程的部分就是纪律,纪律,纪律。而艺术的部分,则是如何在研发团队中拿捏纪律的尺度,毕竟我们既有deadline,也有技术的追求,同时也要尊重人性。

    Happy shitting
    2011.11.15_building_software.pngFrom Manu Cornet