从零学Java设计模式
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.6 设计模式能够解决哪些问题

请大家仔细想想,我们为什么要写程序?按照一般的说法,我们写程序是想用某种编程语言(例如,本书所用的Java语言),写出让人容易看懂,同时又让计算机能够正确执行的代码,以解决某个特定的问题。但是接下来,我们换一个角度来考虑。

我们能不能把写程序想象成一个目标?之所以有这样一个目标,在大多数情况下,是因为我们想满足某种需要或需求。于是,我们必须界定这个目标能够达成什么样的效果,还要界定有哪些功能不是这个目标所追求的。明确了目标之后,我们就开始采取各种能够实现此目标的措施。我们会反复评估自己是否已经达成目标,如果还没有达成,那就调整我们在实现目标的过程中所使用的各种手法,直至写出一个能够解决问题的程序。我们在这个过程中肯定会遇到各种困难,这一点在前面几节中说过了。

为了应对这些困难,我们可能总是想编写新的代码,而不是去考虑怎么合理地沿用已有的代码。有的时候,这些新的代码看上去好像能让项目继续推进,但实际上,它可能只是把当前遇到的问题给掩盖了起来,而没有将其彻底解决。

现在许多开发团队都遵照SCRUM框架进行开发(参见本章第4个参考资料)。于是,我们想象有这样一个采用该框架来开发应用程序的团队,这个团队的开发工作逐渐偏离了正轨。每天的站会似乎都很顺利,因为每次都有人指出程序中的某个关键错误(bug)。而且这样的bug每次都能在几天之后被修复,于是皆大欢喜。奇怪的是,汇报错误的频率越来越高(或者说,bug越修越多),然而不管有多少bug,这个团队依然一个又一个地将其修复,于是大家还是觉得蛮好。但这真的意味着项目处于正轨吗?这样做出来的应用程序真的能正常运作吗?我们需要好好想一想才行。

除了这些,还有一个更严重的状况:待办事项列表(backlog)越写越长,这里出现了各种有待实现的功能与有待解决的技术问题。当然,技术问题(或者说,技术债务)本身并不一定是坏事。如果能够正确地面对,那么技术债务可以促使我们更为积极地推进项目,这种作用在概念验证阶段尤其明显。但如果我们不能正确地面对,换句话说,我们没能及时发现技术问题,或是我们虽然发现了,但是忽视它,不把它当回事,那么这些技术债务就会阻碍项目的发展。要是我们明明看到了技术问题却不想承认,而是把它说成有待开发的新功能,那问题就尤为严重。

虽说产品待办事项列表本身应该是一个实体,但它实际上由两个不同且不兼容的部分组成,即业务和冲刺待办事项(主要是技术债务)。当然,团队正在处理来自计划会议的冲刺待办事项,但如果技术债务过多,那么会导致团队没有太多时间去实现业务功能。如果这种情况频繁出现,则意味着每次给新的冲刺计划会议做规划时,团队都无法将足够的开发资源投放到实现业务功能上。大家仔细想想,自己的团队是否也出现过因为积压的技术问题过多而无法推进产品的局面。

SCRUM方法的理念可以归结为勇气、专注、决心、尊重与开放。但这些理念并不是SCRUM框架独有的。每一个想要交付优秀产品的团队都应该很乐于接受这套理念。

我们接着说刚才的那个团队。项目走到了很难往前推进的地步,大家都在为怎样清晰界定各自的技术分工而争论。于是,整个团队陷入一种虽然在工作,但是已偏离其目标的状态。我们会发现,每次讨论都特别艰难,因为总有各种各样的理由让我们没办法适当地描述出有待解决的问题。团队成员可能无法再有效地沟通,而是开始相互误解。我们发现软件的熵(entropy,混乱程度)变大了,因为整个软件已经失去条理。到了这种地步,我们就可以说这个项目正在变糟,这意味着我们会浪费许多开发时间去做一些没有意义的事情。

请大家再次停下跟我一起想想看,如何才能避免这样的状况。其实这种状况是有办法观察出来的。通常,每个团队都有一些共性,我指的是虽然团队中各成员的知识水平可能不太一样,但如果投入同样多的精力不再能够产出跟原来一样多的成果(也就是所谓学习曲线开始变缓),那么他们还是能够察觉出这一点的。

我们可以根据项目的推进速度,判断这个项目是否正在变糟。如果团队不能像原来那样朝着目标稳步推进项目,而是总把时间花在修复小的技术问题上,那就要当心了。因为这些小的成功并不符合SCRUM的价值,而且一直陷在这种问题中也无法推进项目。针对这些小问题所提出的解决方案,对于整个项目来说,不能算作一项进展,因为这样的方案只是让这个小问题本身变得比原来好一些,而没有让整个项目有所改观,况且这样的方案或许还与技术规范相违背。在打造这种解决方案的过程中,团队并没有获得一些将来能用到的知识。由于团队无法及时做出需要的功能,或者只能做出其中的一部分功能,因此有可能错失市场机会。

除了推进速度变慢,还有一些症状也能帮助我们意识到项目正在变糟。比方说,如果业务功能变得很难测试,那也要当心。出现这种状况时,项目中各个组件的功能变得很难触发,各部分之间的依赖关系变得较为混乱,这样的代码难于阅读,也难于测试,而且还与程序员所应坚持的开发纪律不符。此时我们会发现,软件设计师的日常工作竟然变成了想办法赶紧修复bug,以结束某个工单,而不是如何设计新的功能。

接下来的各章,我们将介绍许多种设计模式,以解决刚才说的那些常见问题,从而令项目不会变糟。设计模式与OOP的基本理念(包括A、P、I、E)是互相契合的,而且有助于我们更好地坚持SOLID原则。

另外,设计模式还能让我们尽早发现一些错误的走向,提醒我们尽量复用已有的代码,而不要重新去发明现成的代码,这就是所谓DRY原则,即Don't Repeat Yourself(不要重复自己)。