春节前和同事在回家的路上看到了建筑工地,不由的感慨建筑业相比软件业来讲实在是成熟太多了! 想想看,建筑师设计好图纸,交给建筑公司(大包工头), 大包工头再报给小包工头, 小包工头随便抓一些农民工就可以干活了! 农民工们可不懂得那么多高深的建筑原理, 对整个建筑也并不了解,可是他们只需要把自己的一砖一瓦做好,整个建筑就能做成了 -- 当然也有豆腐渣工程-- 但毕竟是少数,排除在外。
更重要的是他们根本不用担心项目的后期客户突然想改设计方案,客户不会也不可能要求你把朝北的窗户挪到南边去,也不会要求把10层楼中的第3层和第7层扒掉重盖。
我们这些苦苦挣扎的码农们肯定会想, 什么时候软件业也能这样啊,什么时候我们也能快乐编程,按时上下班,或者以后这些底层的Labor work都让机器人做了, 我们都去做需求,架构,设计, 然后项目按进度,高质量的完成, 大家都很happy...
但是无数的无情现实告诉教育我们:别做梦了,这是绝对不可能的, 至少在可以预见的时间段(比如50年)是不可能的, 原因就在于软件的复杂性,在现有的技术情况下, 软件的固有复杂性无法解决, 只有依靠我们这么码农们去弥补。
为什么软件这么复杂, 为什么我们无法像建筑业盖房子,汽车业装配汽车一样去写软件?
1. 需求的复杂性
布鲁克斯在著名的《人月神话》中提到软件的内在复杂性, 的确,软件系统的复杂性远远超过建筑业和制造业, 软件的需求是在人的脑子中的, 用自然语言都很难完整、准备的表达出来。 一般情况下,人们只有看到一个运行的系统以后才会说: “奥, 我要的其实不是这个... ” 这是传统的瀑布方法失败的重要原因。 需求的不确定性是导致软件复杂的重要原因。
2. 原始的工具
即使需求很复杂,如果我们有强大的, 灵活的工具, 比如以自然语言来写程序, 我们也能处理。
但现实是残酷的, 我们只有计算机语言, 它相当的原始, 从二进制语言,到汇编语言,再到高级语言,其最基本的、最核心的东西依然是顺序,循环,分支, 即使加上面向对象,动态语言,库, 框架,计算机语言的本质仍然没有改变,就像牛顿三定律一出现,整个力学大厦已经建立起来了,后人只是在大厦和某些房间里做装饰而已, 使用计算机语言这种原始的工具,怎么能够表示复杂的需求?
3. 软件组件之间的高耦合性
程序员的出现正是为了填充复杂的需求和原始工具之间巨大鸿沟,程序员需要用自己的大脑,使用极其”原始“的工具, 把无法准确表述的,尚在脑子中的需求映射到可执行的代码上,其难度可想而知!
当然我们程序员也不笨, 在长期的斗争中,我们学会了分而治之,把一个问题划分为一个一个的模块, 让这些模块低耦合,高内聚, 我们还学会了分层,让各个部分的联系达到最小, 可是所有的这些努力只是把复杂性降低了一点, 本质的复杂性依然存在。
普利司通制造的轮胎几乎可以用到所有的汽车, 但是我们程序员无法开发一个登录模块,让它用到所有的软件系统中, 我们程序远远必须要对这些框架,库进行定制,进行二次开发才能适应需求,这样的工作必须通过手工完成。
在某些业务领域例如电力,金融,财务等也许能出现一些重用性很强的“轮胎”, 但很明显不具备更大范围的通用性。
所以在现有的条件下, 不管用什么技术,组成软件的各个组件之间依然是高耦合的(对应传统产业而言), 高耦合会带来巨大的难以想象的复杂度。