之前公司存在的问题(2)

2022-03-11

最近注意到服务集成这个软件开发的领域,以及在这个方向上有所成就的创业公司,同时看到有人来公司面试,偶然想起一些以前的事情,回想起我在上家公司的经历。之前文中没有具体说的是,部门的市场定位不清晰。当然造成那样的结果,有很多历史原因,公司一开始是有靠山的子公司,作为甲方立场很足,后来转变为乙方的形式,没有活跃在市场上的基因。这里只说结果。

如果部门的定位是拥有技术基础去自研产品,那么问题就很严重。

我在正式接手核心产品的开发后,发现项目的代码在工程上有凌乱不堪,不是代码乱,是没有顶层设计,没有明确的模块划分,没有清晰的目录结构,没有靠谱的软件设计。项目支持四五种数据库,然而数据库的配置方式竟然不统一,分散在不同配置文件的不同位置,哪儿生效哪儿不生效,哪个功能好使哪个功能不好使,要么靠经验,要么靠猜。API 的设计也很糟糕,我在《随想》中提到过关于 URL 参数的问题,另外 URL 的配置和参数的校验是写在单个的配置文件中,意味着如果在智能合约中想新增 URL,就需要改配置文件然后重启节点。至于配置规则的热加载,好像没有人关心。

智能合约的机制也有问题。交易在提交到合约后,交易的检查和执行分为两个步骤,检查函数的入参和出参都是 bitMap,必须要严格保证入参和出参的长度一致,否则节点就会 panic,因为外面是用循环处理的,会 out of index。问题在于,那可是智能合约,怎么会用那么生硬的写法。后来前面的人告诉我,写智能合约的原则就是,“绝对不能出错”,因为说是智能合约,其实是和项目耦合很深的功能模块,美其名曰系统合约,是底层链的开发人员去开发的,而不是交给用户使用。开发合约,就需要对底层链有足够的了解。当时的人似乎还对这种事情有一点自豪感,感觉像是,“我们能写,因为我们比较熟悉”,丝毫不认为那是一种功能的不健全,而认为是有门槛的 feature。听说本来是没有打算支持智能合约的,由于需要的不断扩张,就硬生生加上了。当时的某人还拿 leader 的某篇文章奉为真理,说,其实区块链也不一定需要智能合约,对那种和广义智能合约理念背道而驰的设计大加赞赏。

多写几个合约后,就会注意到每个合约的检查函数上,都会有一个判断交易是否为空指针的语句。本以为系统内部的函数调用,怎么会凭空出现空交易呢,经过复现和排查,发现在并发情况下,队列偶尔会出现异常,push 一批交易进去,pop 出来就有空交易了,这纯粹是数据结构的问题。然后虽然定位到问题,但没有去解决,因为大不了每次都在合约上写个判断,算是我偷懒。也不知道前面的人,还埋了多少隐性 bug 在里面。

当用合约处理业务的时候,就会发现数据库的读写性能会成为交易性能的瓶颈,比如 MySQL,而且存在一个我一直没想通的问题:合约里的检查函数,怎么判断交易是成功还是失败?因为合约是要针对业务去开发的。合约对交易的检查和执行,都是是在 BFT 共识的 commit 阶段,这个时候已经完成共识了,检查函数并不能去预执行数据库的写操作(如果合约依赖数据库的特性比如事务,区块链就没有意义了),难道要把所有有可能失败的场景全排除一遍?是语义层面的排除,还是执行层面的排除?即使能够枚举出异常,又会损耗多少性能?那可能会产生疑问,为什么不在共识前检查?共识前的检查也是有的,但不管在共识前还是共识后,对数据库的操作总量不会变,对性能的损耗不会变。(延伸思考:为什么公有链不存在这样的问题,联盟链存在。)

版本管理的混乱也是在工程方面的问题之一,甚至都没有人能说清楚,当前的版本号到底是多少,是 2.0 吗?配置文件里可还写的是 1.4,是 2.0.1 吗?仓库里可还有 2.0.3,但不知道是谁改的,有哪些变动。甚至主干代码中会出现用于测试的 case,有些需要异常场景测试的情况,比如在 BFT 共识过程中恶意投票,只能通过改代码的方式观察效果,结果那部分代码就保留在了项目中,可以通过配置启用。其他原因的代码冗余也存在,比如智能合约的公用接口,为了兼容 UTXO,就不得不增加对应的接口,但其他合约完全用不到那些,又不得不实现。

项目在技术方面是存在各种各样问题的,包括我之前解决的由于使用 VRF 导致共识在提案阶段黑名单失效的问题,都说明系统尤其是在比较核心的地方都不够完善,而重构项目的成本又非常高。项目存在的最大价值和意义,就是参加一个行业内知名的测试活动,测试通过后某机构会给企业颁发证书,以证明这个软件是合格的、有资质的、符合标准的。然后企业拿着这个证书就可以宣传、投标、卖钱。至于软件本身好不好,并不重要。我当时光看测试项还感觉没啥,都是一些对区块链的基本要求,能通过测试没什么大不了的。直到亲手操作后发现,测试过程中存在大量的困难,都是人为困难,由于之前开发人员的不专业、团队管理的松散,以及项目本身很多不合理的设计,加上文档和人员的流失,都大大增加了测试过程的准备难度。也许大家没有意识到,什么是有效的困难,才造成了一种项目很好的假象。

如果部门的定位是服务集成,提供解决方案和技术支持,也是不合格的。

除了区块链底层,部门还有 Bass、中间件、SDK、浏览器之类的项目,会涉及到 Kafka、Zoopeeper、Redis、普罗米修斯等组件,但用的很浅,本身技术含量低,整体上做的也不到位,没有产品、没有 UI、没有用户思维、没有 owner 意识,全是在有业务需求的情况下临时改进,结果每次都手忙脚乱,总是以优先应付客户为要务。服务集成的事情,可以简单也可以难,可以做好也容易做不好。然而部门另一方面又不太想做服务集成,比如在用 Hyperledger Fabric 做一些什么事情的时候,leader 就说:客户会问,你们底层用的 Fabric,只是拿来用,也没干什么呀,为什么要收钱?至少能体现出部门的定位有多混乱了。