这是一个初创的公司,快速提供许多新版本的压力很大。延期是不可容忍的—
这会带来财务灾难。软件工程师被迫尽其极限,快速交付。所以代码是以一系列疯狂冲刺的方式垒在一起的。不好的公司结构和不健康的开发过程将在糟糕的软件架构中得到反映。
这些后果的影响是很严重的,远远超出了你对不良设计的天真想象 ?
———— 1 不可理解
——正如你已经看到的,“大都市”的架构以及缺乏强制的结构,导致了一个很难理解的软
件系统,实际上几乎不可能修改。新加入项目的团队成员(譬如我)会被复杂性惊呆,不能够搞清楚状况。坏的设计确实会招致在它上面叠加坏的设计(实际上它简直就是迫使你那样做),因为没有
一种明智的方式可以扩展该设计。在所有能解决手上工作的方法之中,阻力最小的总会被采用,没有明显的办法来修复这些结构问题,所以只要能减少麻烦,就会扔进去新的功能。注意:重要的是要保持软件设计的品质。坏的架构设计会招致更坏的架构设计。
———— 2 缺乏内聚
系统的组件完全没有内聚性。每个组件本来都应该有一个定义良好的角色,但是它们却
包含了一堆杂乱的、不一定相关的功能。这使我们很难确定组件存在的原因,也很难弄明白系统中已经实现了哪项具体的功能。很自然,这让缺陷修复成为了一场噩梦,严重地影响了软件的品质和可靠性。
功能和数据都放在了系统中错误的地方。许多你认为是“核心服务”的部分却没有在系
统的核心部分实现,而是由边远的模块来模拟实现(非常痛苦并且代价很大)。
• 高内聚(Strong cohesion)
内聚是一个测量指标,说明相关的功能如何聚集在一起,模块内的各部分作为一个整体工作得如何。内聚性是将模块粘成一个整体的胶水。弱内聚的模块是不良分解的信号。每个模块都必须具有清晰定义的角色,而不只是一堆不相关的功能。• 低耦合(Low coupling)耦合是模块之间独立性的测量指标—它们之间进出“电线”的数量。在最简单的设计中,模块几乎没有什么耦合,所以彼此间的依赖关系较少。显然,模块不能够完全解耦,否则它们将根本不能够一起工作!—— 模块内部谈内聚,模块之间谈耦合
模块之间的联系有多种方式,有的是直接的,有的是间接的。模块可以调
用其他模块中的函数,或被其他模块所调用。它可能使用其他模块提供的Web服务或设施,可能使用其他模块的数据类型,或提供某些数据让其他模块使用(可能是变量或文件)。
好的软件设计会限制通信的线路,只提供那些绝对需要的。这种通信线路
是确定架构的一部分因素
———— 3 不必要的耦合
“大都市”没有清晰的分层。模块之间的依赖关系不是单向的,耦合常常是双向的。组件A会到达组件B的内部,目的是完成它的一项任务。在其他的地方,组件B又通过硬编码调用了组件A。系统没有最底层,也没有控制中心。它是整体式的一大块软件。_ 整个软件系统就一团, 没法分开
这意味着系统的各部分之间耦合非常紧密,你想启动系统骨架就不得不创建所有的组件。
单个组件的任何改变都会波及其他组件,需要修改许多依赖它的组件。孤立地看代码组件没有任何意义。———— 4 代码问题
“大都市”最微妙而又最严重的问题是重复。由于没有清晰的设计,也不清楚功能应该
处于的位置,所以轮子在整个代码集中不断重新发明。一些简单的东西,如通用算法和数据结构,在许多模块中重复出现,每种实现都带有自己的一些未知的缺陷和怪异的行为特征更多的软件历史考察揭示了原因:“大都市”开始是从一系列独立的原型拼起来的,这
些原型本该抛弃。“大都市”实际上是偶然形成的城市群。当代码组件缝合在一起时,组件之间匹配得不好。随着时间的推移,这种随意的缝合开始破裂,所以组件互相拉扯,导致代码集破碎,而不是和谐地协作。
代码以外的问题
“大都市”内部的问题已经超越了代码集,在公司中其他的地方导致了混乱。不仅开发团队中有问题,而且架构的腐烂也影响到了支持和使用该产品的人。—— 所有软件相关人都可能受坏架构引起的麻烦困扰!开发团队项目的新成员(例如我)被复杂性惊呆了,不能够搞清楚状况。这很好地解释了为什么很少有新人能在公司里待下来—员工流失率非常高。
那些留下来的人非常努力地工作,项目的压力非常大。规划新的功能会导致极大的
恐惧。那些留下来的人非常努力地工作,项目的压力非常大。规划新的功能会导致极大的
恐惧。
缓慢的开发周期由于维护“大都市”是一项恐怖的任务,所以即使是最简单的变更或“很小的”缺陷修复都不知道要花多少时间。管理软件开发周期非常难。客户只好等着实现重要的特征,管理层对开发团队不能满足业务目标感到越来越沮丧。支持工程师在支持这个极不寻常的产品时,产品支持工程师度过了可怕的时光,他们要设法弄明白很小的软件版本差异之间错综复杂的行为差异。第三方支持项目开发了一个外部支持协议,支持其他设备远程控制“大都市”。由于它只是软件内部结构上面薄薄的一层,所以它反映了“大都市”的架构,这意味着它也是巴罗克式的、难以理解的、容易偶尔出错的、不可能使用的。第三方工程师的生活也被“大都市”的可怕结构搞得一团糟。公司内部政治开发问题导致了公司内部不同“种族”的分裂。开发团队与营销销售团队之间关系紧张,每次新版本要推出时,制造部门总是要承受巨大的压力。经理们已经绝望了。
__跟我当前所在的网管项目多么相似
—————————— 看来坏的架构的危害是无穷无尽! 上梁不正下梁歪,——
一开始就错了, 后面就很难归正! _ 离这种坏软件越远越好
—— 就像一个国家领导, 坚持一套错误的理论,一些错误的实践,这样导致他的秘书必须围绕他的错误理论不得不做很多一些麻烦的、多余的工作, 他的下级也不得不苦恼的按照他的理论做事,下下级也是,... 直到最底层——“广大的人民群众”,人民群众可以不用按照他的狗p理论是做事了,但是他们可能会时不时的接触相关工程、系统, 最终不得不受他的困扰、苦痛、甚至是叫苦不迭...就像我们的老m
清晰的需求
软件历史考察凸显了“混乱大都市”之所以混乱的一个重要原因:在项目开始之初,团队并不知道要构建的是什么。本来的初创公司知道它要占领哪个市场,但不知道哪种产品能占领这个市场。所以他们两面下注,要求一个可以做许多事情的软件平台。噢,我们昨天就想得到它了。所以程序员们急急忙忙创建了一个毫无希望的总体基础设施,它具有做任何事情的潜力(但做得不好),而不是创建一个把一件事情做好的架构,并能够在将来进行扩展,做更多的事情。
在规划“大都市”的早期阶段,有太多的架构师。面对糊涂的需求,他们都拿着一块拼
不起来的拼图,试图独自工作。他们在工作时没有考虑到整个项目,所以当他们试图将
这些拼图拼在一起时,就拼不起来了。没有时间进一步思考架构,软件设计的各个部分有一些重叠,于是开始了“大都市”的城市规划灾难 ———— 也是没办法的事情
“大都市”的设计几乎完全是无可救药的—相信我,随着时间的推移,我们也尝试过
修复它。修复工作需要返工、重构、修改代码结构中的问题,这些已经成为不可能的任务。重写也不是省事的方案,因为支持老的、巴罗克式的控制协议是需求的一部分。你可以看到,“大都市”的“设计”产生的后果是残酷的,并且会无情地变得更糟。很难
加入新的特性,所以人们只是忙着添加更多不完善的功能、救急补丁和编造的谎言。没有人在面对代码时感到愉快,项目正盘旋着向下栽。缺乏设计导致了不良的代码,从而又导致了不良的团队精神和不断变长的开发周期。这最终导致了公司严重的财务问题。
最后,管理层宣布“混乱大都市”已经不盈利了,它被抛弃了 !!!!!!!!!
对于任何组织机构来说,这都是勇敢的一步,特别是这个公司一直都眼高手低,同时又试图避免沉沦
单元测试打造了设计
关于代码集的一项核心决定就是所有代码都要有单元测试
单元测试的另一个主要好处在于,它们在很大程度上定型了代码设计:它们实际上迫使
我们实现好的结构。每个小的代码组件都被定型成定义良好的实体,可以独立存在,因为它必须能够在单元测试中构造出来,不需要围绕它构造系统的其他部分。编写单元测试确保了每个代码模块的内聚性,也确保了与系统其他部分之间的松耦合。单元测试迫使我们仔细考虑每个单元的接口,确保该单元的API是有意义的,内部是一致的。
设计时间
“设计之城”成功的另一个因素是分配的开发时间段,它既不长也不短
与设计同行
尽管代码集很大,但它是一致而易于理解的。新的程序员可以比较容易地拿起代码并开始工作。不需要去理解不必要的复杂内部关系,也不需要面对奇怪的遗留代码。由于代码中产生的问题比较少,工作起来有乐趣,所以团队人员的流失率很低。这是因为开发者们负责设计,并不断希望改进它。看着开发团队动态地遵守架构设计是一件有趣的事情。“设计之城”的项目原则规定没有人“拥有”哪一部分设计,这意味着任何开发者都可以改动系统的所有地方。每个人都应该写出高品质的代码。“大都市”是许多不协作的、互相争斗的程序创造的一团混乱,而“设计之城”则是由密切合作的同事创建的一组干净、一致、密切合作的软件组件。在很大程度上,Conway法则(注)反过来也生效,团队的组织方式就像软件的组织方式一样。注意:团队的组织方式必然对它产生的代码有影响。随着时间的推移,架构也会影响到团队协作的好坏。当团队瓦解时,代码的交互就很糟糕。当团队协作时,架构就集成得很好。
我要澄清一点:这些代码并不完美。有些地方存在着技术争论,但是它们在整洁的背景
下显得特别突出,会在将来得到解决。没有什么是一成不变的,由于适应性强的架构和灵活的代码结构,这些问题都可以解
这个关于两个软件系统的简单故事当然不是软件架构的全面介绍,但我已展示了架构如
何对软件项目产生深远的影响。架构几乎会影响所有与之相关的人和事,它决定了代码集的健康,也决定了相关领域的健康。就像一个繁荣的城市会为当地带来成功和声望,好的软件架构将帮助项目获得发展,为依赖于它的人带来成功。好的架构是很多因素的结果,包括以下方面(但不限于此):• 确实进行有意为之的前端设计。(许多项目甚至还没开始,就因为这一点而失败了。)• 设计者的素质和经验。(以前犯过一些错误是有帮助的,这能在下一次为你指出正确方向!“大都市”项目肯定教会了我一些东西。)• 在开发过程中,保持清晰的设计观点。• 授权团队负责软件的整体设计,而团队也承担起这一责任。• 不要害怕改变设计:没有什么是一成不变的。• 让合适的人加入到团队中,包括设计者、程序员和经理,确保开发团队的规模合适。确保他们具有健康的工作关系,因为这些关系将不可避免地影响代码的结构。• 在合适的时候做出设计决定,当你知道所有必要信息时再做出决定。延迟那些暂时不能做出的决定。• 好的项目管理,以及合适的最后期限。