原文标题:3 Key Software Principles You Must Understand
原作者信息:2012年9月7日 Chris Peters
原则1:不要重复(Don’t Repeat Yourself,DRY原则)
原则2:保持简洁(Keep it Simple Stupid,KISS原则)
原则3:适可而止(You Ain’t Gonna Need It,YAGNI原则)
如果你从业于软件开发行业,那么新技术,新语言,新概念将一直伴随着你。我们都会不时的感到疑虑:我可以跟的上这些改变并且保持着足够的竞争力吗?花些时间从我特别喜欢的电影《Casablanca》中总结出一句话来:任时光流逝,基础永存。
What's true for love, is true for code.
基本原理将永存不破。如果你了解软件开发的基本思想,你将快速的适应新技术。在这篇教程中,我们会结合其它原则来讨论这三个基本原则。他们提供了非常强大的方式去管理复杂的软件。我将分享一些我个人的见解和想法,希望在编程或者解决实际问题时能够有用。
原则1.不做重复的事(Don't Repeat Yourself)
降低可管理单元复杂度的一个基本策略就是将他们拆解成更小的单元。
理解这个原则简直太重要了,我不会再讲第二遍。通常将其首字母缩写为DRY,出现在Andy Hunt和Dave Thomas所作的《The Pragmatic Programmer》一书中,但究其概念本身则由来已久。它指的是软件最小的部分。
当你在构建一个大的软件项目时,你将经常被无处不在的复杂事物所困扰。人们并不擅长管理复杂事物;他们更擅长于在特定范围内挖掘极具创造性的解决方案。降低可管理单元复杂度的一条最基本原则就是将系统切分成更为容易的单元。起初,你可能希望将你的系统切分成许多组件,每个组件都能体现它本身的子系统,而这个子系统包含可以实现特定功能的所有东西。
举例来讲,如果你在构建一个内容管理系统(CMS),负责人员管理的模块将会成为一个组件。这个组件可以继续被切分为诸如角色管理单元等等更多的子组件,并且它有可能会与其他的组件进行信息交互,比如安全组件。
就这样不断的将系统切分成组件,再进一步将组件切分为子组件,你终将会切分到一个层次,在这个层次上原本那些复杂单元被精简为一个个单一职责的单元。这些职责可以在一个类里面实现(假设我们在构建面向对象的应用)。类包含方法和属性,方法实现算法,算法及其子部分计算或者囊括了构建业务逻辑的最小模块。
The DRY principle states that these small pieces of knowledge may only occur exactly once in your entire system.
DRY原则指出这些小片段的知识只能在你的整个系统仅仅出现一次
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
每一个小段知识在一个系统中必须拥有一个单一,清晰,权威的呈现。
注意知识与其呈现的区别。如果我们正在CMS中实现数据库连接,那将会有个初始化数据库驱动的代码段,传递认证信息并将连接的引用保存到一个变量里。这个代码段就是知识的一部分,它是讲述某件事是如何完成的。而保存有连接引用的变量则是知识的呈现,并且这是可以被别的模块使用的。如果数据库认证信息改变了,我们将不得不修改代码段,而不是它的呈现。
一个完美的应用,每一个小的业务逻辑将他的知识封装在呈现里,并且声明为一个变量或者一个类属性。
这个变量本身是被封装在一个类里,这个类可以被描述为一个职责的呈现。类又被封装在一个组件里,组件可以被描述为功能的呈现。
除非我们达到软件项目的最顶层,即一堆日益复杂的呈现,否则我们无以继续这样的方案。这种看待软件复杂度的方式被称作模块化架构,而DRY便是它非常重要的一部分。
实现DRY
有很多种方式可以实现DRY,Hunt and Thomas建议代码生成器和数据转换。但从本质上来讲,DRY是一种将逻辑包装到呈现中的哲学。
正如一个应用中的每个部分都可以被看作是呈现,每个部分都公开了基本逻辑的特定片段:用户管理公开了CMS注册用户的访问,用户类代表单一用户并且公开了它的属性(如用户名)。它通过数据库的呈现获取属性。
DRY和模块化架构需要很好的计划。为了取得一个自上而下的表现层次,将你的应用按照逻辑分离的层次结构切分成更小部分,同时让他们可以互相通信。如果你必须管理大型项目,那以组件的方式组织他们并在组件之间使用DRY将是一个不错的选择。请尽量遵守以下规则:
- 做一个应用程序的可视化层次结构,并将主要组件映射进去。复杂项目的每个组件间可能需要一个专用的映射。
- 如果正处于职责关联的层次,你可能需要转换成UML图表(或者相似的)。
- 书写大量代码之前,在你的软件项目中命名它的层次结构。定义它的呈现,并且确保知道它在周遭组件中所担当的角色。
- 确保不同复杂层之间的呈现不会相互依赖(比如一个组件依赖于另一个组件里的一个类)。
上面所列的数据库驱动是一个简单的例子,它不像现实世界涉及到很多层(如一个特定的数据库抽象层),并且在封装逻辑方面——特别是牵涉到设计模式,你要做的事还很多。但即便你只是刚刚开始编程,有一件事也必须牢记于心:
- 当你发现自己正在编写的代码与之前写过的相似甚至是一模一样时,花些时间想想你在做什么,千万不要让自己做重复的事情。
在现实生活中,要想一个应用程序是100%的DRY是极其困难的,但并不是不可能。不管怎样,对于一个DRY程度低到无法接受的应用程序,高难度的维护也很平常。因此,如果你看下那些代码,超过50%的软件项目最终走向失败也不足为奇。
劣质的代码很少是由劣质的程序员造成的。
很多人趋向于认为劣质的代码是由不够优秀的程序员造成的。但在我的经验里,却恰恰相反。通常劣质的代码是由劣质的客户经理以及公司内配置失衡的管理流程导致的。
一个例子
作为一个例子,假设你作为一名技术顾问受雇于一个有很多代码质量问题和维护问题的公司。你翻阅源代码并且发现了好多漏洞和重复代码——代码并不是DRY的!这个是劣质代码的典型特征,这也并不是理由。如果你看过他们的版本控制系统——又称作历史代码,你偶然发现了一些在临近截止日或者里程碑的时刻才产生的漏洞。花些时间查看都发生了哪些变化,这时你很可能会面临一个需求变更。
正如前面提到的,DRY的实现需要很好的计划。
截止时间点上的强制变更会强迫开发人员去实现一些不够精炼的方案。一旦代码因妥协而被修改,DRY原则将被彻底的牺牲在进一步的变化之中。在IT行业有很多成功企业都是由那些对技术有很好理解的人所创建,甚至是程序员自己:Bill Gates, Mark Zuckerberg, Steve Wozniak,Steve Jobs, Larry Page, Sergey Brin 以及 Larry Ellison,这是为什么呢?原因就是他们知道需要在那些方面下功夫才能完成一些事情。相反,很多公司趋向于将工程需求交到客户经理的手中,并且将概念性的部分交给业务顾问——这些人是从来没有实现过任何模块的!
因此,很多技术概念只是在Powerpoint, Photoshop中奏效,而且只在27″宽屏显示器上。如果在静态网站的时代,这样的方法或多或少也可能算作是一个不错的选择,但并不适用于当下——多设备间交互应用盛行的时代。因为程序员是软件生产线的最后一环,从概念上讲,他们是那群必须对错误做出快速修复的人。如果是客户经理,就是那些Hold不住喜欢在最后时刻做出变更的客户的人来做这事,计划被抛在九霄云外,竞实现一些快速的欠考虑的方案。这样一来,代码变得不再DRY。
这个例子有点极端(即便如此,这样的情节我可是亲眼所见的),但它论证了DRY只是理论上的概念,而这个概念正受到现实世界各方的挑战。如果你正在一个要求你以这种方式工作的公司里,或许你该建议在流程上做出一些改变(比如在技术性项目的初期引进一些技术专家)。