作者从事软件研发 10 多年,曾任职于各种类型 IT 企业,包括咨询、物流、电信、电商、金融……。其中大部分时间是做业务软件开发。众所周知,业务软件需求变更频繁,开发周期短,易腐烂、难维护,故多年来一直致力解决这些问题,研究业务软件架构设计。
在 17 年左右,我觉得已经找到了银弹。之后经过 2 年的实践和总结,确认这只是个部分解——适用于大多数常见的数据处理模式的业务系统。这些方法论的名字“业务系统中间件化”来自于 14 年前后和朋友吹的牛,因为传播的需要,编辑建议我改成“业务中台”(我持保留意见,是的,锅都给小编背,她删了我很多东西)。我认为阿里的中台,华为的让听到炮火的人指挥炮火,以及很久以前的产品工厂,流程工厂,从思想上都是一回事。但是具体做法上和范围内涵上有比较大的差异,虽然这些并非本质区别,但是让技术快速响应业务是路边大妈都懂的。如果要区别的话,手段反而是本质区别。但是他们的方法论,我看不清楚——也许是他们不愿意让我们看清楚,也许是他们自己也没有完全清楚,所以我既不愿意用某一个,也不愿意太去区分这些差异,没有意义,也不会执着于什么名字。而更认可这些做法都是为了快速响应业务,更好的软件设计质量,这一点上是清晰而明确的。
文章第一部分是问题的深层次分析,是第二部分解决方法论的目标和出发点。第二部分是解决业务系统如何快速响应业务,同时提升新系统设计质量的具体做法和依据假设,以及它们的实践经验。
软件研发中的问题
众所周知,软件行业一直受人月定律的困扰,容易陷入到“史前巨兽的焦油坑挣扎”之中。一些发展迅速的软件公司往往数年之内从几个人的小作坊迅速膨胀为几千几万甚至十几万人的大型工厂化组织。越是庞大的动物越是笨重。这些庞大的公司,往往组织效能低下,大公司病严重,甚至最终无法应对任何变化。即使不那么庞大的公司,也会受困于软件焦油坑的各种症状。业务需求频繁,技术却响应不及、质量堪忧;新功能上线,老功能出问题;老功能修复,新功能出问题;系统三天两头宕机。
开发人员抱怨代码复杂到看不懂,不敢动;抱怨产品和市场乱提需求不专业。要产品走需求审核流程;产品找管理层和市场部门来一起施加压力。测试团队抱怨开发代码 bug 频出,按起葫芦起了瓢;bug 分布的逻辑性和随机度难以预测,如果全量测试会导致测试资源不足压力过大,不全量测试这个锅我没法背你们找别人想办法。开发让产品和市场证明:时间紧任务急,来不及设计……,否则以后就让产品提需求写邮件按手印。产品表示这些听起来都是技术问题,技术问题我不懂,反正都是你们技术内部的事,你们自己去决定怎么解决。架构师表示你们产品和技术往往直接对接,不经过我,我无法介入;我给的架构建议也没有看到多少落地。技术经理表示,架构设计的周期过长,大部分需求比较小和零碎,时间周期较短,项目周期上不合适嵌入架构工作。挑出时间进行架构优化呢,最终效果往往不能令人满意。
群众吐槽,架构整天研究些高并发分布式微服务容器化……,对我们并没有什么帮助;我们不是阿里不是腾讯,没这些挑战;我们真正关心的快速响应业务、灵活性的市场运营、测试的安全可靠你们没给多少支持;大数据挺新潮,但是连个日常报表的需求实现不了了;微服务宣传的是挺好,但是你们把系统从几个拆成了几千个,做起事情光找人和协调都累吐血……。技术包装和名词是越来越绚了,但做事情的速度是越来越慢了(当然现实中这一段话不可能公开发生,这是私下的频繁吐槽)。
软件研发陷入了这样的状况,工作越做越多,问题越做越多,考勤时间从 996 慢慢滑向 997 乃至……;团队内部互相抱怨,压力巨大,协作效能下降,工作氛围恶化,离职率提升,工作产出更低,负反馈循环。
不幸的是,这是很普遍的情况。并且愈演愈烈,不可忽视。唯快不破的互联网公司们发现,自己慢慢变成了自己国企那样的笨重。有些公司要结构优化,有些公司内部慢慢有了工程效能部。有些公司开始大张旗鼓的要做中台。
人月定律真的是不可以克服的么?或者说我们已经做到了理论上的极限了么?我们过去的路正确么?正确的话为什么现状是这样的?不正确的话问题在哪?我们现在的路是正确的么?它和过去的路有什么本质差异和不同?我们有信心么?信心来自哪里?
软件的本质
前面谈软件研发中的种种问题可以简化为《人月神话》中说的人月定律。但软件工程为什么会受到人月定律的制约?其深层次的基本原理是什么?
软件受人月定律制约,其原因不可能是因为人月定律是什么,而必定是软件和软件工程是什么。若为不可规避的,随时随处体现的顽疾,则必为软件的本质因素所决定。人月定律的确为软件不可规避的顽疾,却也并非随时随处肆虐的外症。FrederickP.Brooks.Jr.(人月神话作者)用突然变异为人狼的村民来描述它。所以它必定不是软件或者软件工程的本质本身,而只能软件和软件工程的本质有关系,也必定需要一定的条件才能触发。
软件的本质什么?这么重要的问题,搜索一下会发现这个问题少有人探讨,曾经我搜索、比较和思考过很多答案,都不能让我满意。直到有一天我发现《人月神话》中有这么一段作者使用了非常非常大力量的形容词标记,但是少有人关注和引用的话:
“一个相互牵制关联的概念结构,是软件实体必不可少的部分,它包括:数据集合、数据条目之间的关系、算法、功能调用等等。这些要素本身是抽象的,体现在相同的概念构架中,可以存在不同的表现形式。尽管如此,它仍然是内容丰富和高度精确的。 我认为软件开发中困难的部分是规格化、设计和测试这些概念上的结构,而不是对概念进行表达和对实现逼真程度进行验证。当然,我们还是会犯一些语法错误,但是和绝大多数系统中的概念错误相比,它们是微不足道的。
如果这是事实,那么软件开发总是非常困难的。天生就没有银弹。
让我们来考虑现代软件系统中这些无法规避的内在特性:复杂度、一致性、可变性和 不可见性”。
——《人月神话——软件的根本困难》
变化并非是所有软件的本质属性。很多软件功能特性是不变的,这种软件极少有听说研发陷入困境的;变化的越频繁,变化之间的差异性越大,软件研发陷入泥沼的概率越高。尤其是大家常见的需求频繁开发周期紧张的业务类软件。
基于软件的本质:概念和概念对的关系,比较一下物理学中引起核子爆炸的链式反应你会发现:在软件中各种要素同样互相影响,耦合,牵一发而动全身;在发生变化的情况下,互相影响,最复杂的情况是来回震荡反馈,无穷尽也,如同原子链式反应的后果。
软件的本质和不可避免的变化导致了复杂性爆炸——概念、概念之间的依赖和变化是导致人月定律的原因之一。
软件工程的核心任务
软件工程是软件的构造方法和过程。这个解决过程除了问题域(概念和依赖)本身,还涉及到采用什么样的技术,使用什么样的人、组织架构去实现它。
(三域三熵图)
这几个要素并非孤立的,他们是彼此依赖、互相影响的。问题域的变化一定会影响技术域;问题域的变化也一定会影响组织域;技术域的变化也会影响组织域,或者反过来。这进一步导致复杂性的增加。
在《人月神话中》认为软件工程可能是人类有史以来最为复杂的作品。因为相比于传统的工业产品,软件工程即使设计完成,每个开发、测试、部署、运维、运营阶段依然有许多变化,都可能对这个软件有较大影响,甚至颠覆性的变化。而传统的工业在设计阶段结束以后,只需要严格按照设计生产就行了。
这种所有要素都可能变化,并且彼此影响,互相反馈震荡的的结果是难以预料的。这就是软件工程成面临的问题:复杂度爆炸。
软件工程的核心任务是控制复杂性。
控制复杂性有两个策略技术
总量控制
分而治之
总量控制寻求软件研发过程中总体复杂度最低,寻求最接近(三域三熵)图中红线左边部分。
分而治之将一个不可控制的复杂度分解为几个可控制的复杂度。去隔离和限制他们之间彼此影响,控制整个各个复杂单元的风险和进度,达到总体可控性。这种策略有两个比较大的问题:划分本身导致成本提升;不合理的划分会导致成本过高——不论哪一个问题,它都是增加复杂度的。分而治之的策略必须在总量控制策略的制约之下去使用。
以 SOA 为例来说明这个问题。
大多数公司 SOA 的起因是业务复杂性和技术复杂性因素导致单体系统已经难以承受了。但是很多公司最终走向了过于分散,膨胀为几百几千个业务系统。这也同时导致了组织架构急剧膨胀和研发效率的急剧降低。
SOA 的本质不外是分而治之,将一个高度复杂的,难以控制的系统变成 N 个简单的,可以控制的系统。但是这个过程中,划分本身会导致成本提升,比如原有的模块或者对象之间的依赖变成系统之间的依赖,无论通讯还是协作成本都是上升的。所以 SOA 整体上看是坏的,但是一个坏的可控制可落地的东西总比一个好的,不可以控制,不可以落地的东西强。这个过程中一定要控制度,不能坏事做绝,不能以 SOA 或者拆分为目的。
传统的软件工程理论也属于分而治之的策略。即通过将软件划分为几个阶段,每个阶段有清晰的内容和执行者和方法论,以及所有阶段之间定义了完整的协作方法……,传统的软件工程会增加复杂度。举个例子:病人去医院就医,即使是一个感冒,有时候也要经历挂号->验血->拍片->科室诊断->付费->拿药等环节。这流程可能几个小时几天,但医生只看几分钟。人人都清楚是医生而不是流程能看病。企图用软件工程能解决复杂性、解决人月定律是不可能的。企图通过深入、彻底的实践软件工程极致的 SOA 会到导致类似的后果——看起来有点效果,但是越来越重,越来越成为负担。
这也是为什么软件工程理论诞生半个多世纪以来,软件研发依然烂苹果遍地的原因了。即使在软件工程已经诞生的《人月神话》60 年前,它也没在书中占据什么重要地位。
从统计的角度来看,大多数严格遵守软件工程理论的公司没产生多少杰出软件;大多数杰出软件和严格的遵守软件工程没什么关系。统计大多数优秀的软件,你会发现它和某个杰出而天才的设计人员、或者一个小二精干的团队关系更大一点;反过来看某个杰出软件的作者或者团队往往有数个优秀的软件作品。
不同于传统软件工程理论,我认为软件工程的核心任务是控制复杂度。
设计的问题
设计的问题在于它需要业务知识,技术知识,抽象能力,和时间。对于某个业务软件,这四者很难同时拥有。这是业务软件腐化的根源。
现在的软件团队大部分研究的是业务软件,但是技术人员和架构师多数喜欢研究纯技术;在某个业务领域,技术人员敢说精通业务知识的非常罕见。这是技术人员业务知识的匮乏。
业务人员则更难学习技术能力,大多数业务人员不了解为什么要抽象,抽象有什么用处——这根本就是一个技术需要产生的词语,别说培养这样的能力,即使在技术人员身上,要找到具有高度业务抽象、分析能力的也是比较少的,这是业务人员的技术能力和抽象能力的匮乏。
虽然作为个人很难,但作为一个团队,可能比较容易凑齐业务知识、技术知识、抽象能力;但是这意味着交流,讨论,充分,盲区,反复……往往意味着时间消耗巨大,并且很难保证充分了。
这就是为什么设计很难在业务软件中得到真正的应用。即使有架构师这个岗位,也难以对业务团队产生真正的帮助。这是因为现有设计方法本身和业务软件的四个要求是矛盾的。
所以业务软件往往需求快速实现,不经过设计。长此以往,业务系统必将沦为一个垃圾堆。
因为业务软件需求频繁多变、周期紧张的矛盾和设计本身的要求是根本矛盾的。
我更推荐采用事后的,阶段性的,小步快跑的重构的设计方式——这意味着更有效率和更高的设计质量——但很多的银行或者金融公司可能比较介意这一点。
最关键的一点是,在业务架构和业务知识之间,一定要形成一个清晰而明确的架构图,最好是瞬间能反应的。这样,无论在事前或者事后查看业务系统,能够轻易的得到重构方向和方案——因为我们同样碰到过管理上给了重构窗口,但是开发和架构不知道干什么或者乱重构——纯粹技术性的重构,甚至引入更复杂更难以控制的技术框架——导致系统质量更加难以控制。
一个所有人都能接受的最好方式和可行的办法是让技术人员了解业务,尽可能快的了解业务;进行设计,尽可能快的进行设计;这是唯一通用且可行的方式, 如果存在的话。我们下一篇将会介绍这个方法。
作者简介:王林,软件浪人。从事软件研发 10 多年,在各种类型 IT 企业包括咨询、物流、电商、金融……服务过,注重研究实际业务问题。不懂高并发、synchronized 底层原理等,写过单节点 TPS 过 w 的分布式风控系统; 不懂微服务、各种架构设计理论,重构的软件代码行数平均是原代码行数的 1/3~1/6,开发效率、稳定性、扩展性等提升几倍而已;没有做过复杂的业务系统,善于把复杂系统做的非常简单。
评论 1 条评论