7个软件开发原则

转载 2004年09月05日 15:03:00

关于代码重复最著名的单词是Kent Beck的Once And Only Once,也就是说软件操作的任何一个片断--不管是一个算法,一个常量集合,用于阅读的文档或者其他东西--应当只出现一次。
软件重复出现至少会导致以下问题:
· 其中的一个版本会过期
· 代码的责任会四处散开,导致代码难以理解
· 当你修改代码时,需要重复修改很多地方,一不小心就会遗漏
· 你不能很好地进行性能优化

我以前的一位老板曾经跟我夸耀过他手下编程的能力:“他只要把一份模版代码拷过去,稍加修改,就可以完成一个新的模块“。我惊讶这位程序员思路清晰的同时也怀疑这样的程序除了他自己以外还有谁能维护,我想可能连他自己也无法做到。
重复代码的产生由各种各样的原因,上面的例子就是一个,我经常看到程序员把几行或一整段代码从这里复制到这里,然后少加修改,就变成了一份新的代码。这里的原因是程序员可以通过极少的努力就完成代码重用,但是我们可以来看看DavidHooker提出的7个软件开发原则:
1.第一原则:存在的理由(Pattern: TheReason)
一个软件系统存在的理由就是:为它的用户提供价值。你所有的决定都取决于这一点。在指定一个系统需求,在写下一段系统功能,在决定硬件平台和开发过程之前,问你自己一个问题,“这样做会为系统增加价值吗?“,如果答案是”yes”,做。如果是”No”,不做。这个原则是其他原则的原则。
2.第二原则(能简单就简单,愚蠢!)KISS (Pattern: KeepItSimple)
软件设计不是一个轻描淡写的过程。在做任何一个设计时,你必须考虑很多因素。所有设计应当尽可能简单,但是不要再比这简单了。这样产生的系统才是可以理解和容易维护的。这并不是说很多由意义的特性,因为这种简单性也要被抛弃。确实很多更优雅的设计往往更简单,但简单并不意味着“quick and dirty."。事实上,简单是通过许多思考和一次一次的反复修改才达到的。这些努力的汇报就是更容易维护,代码错误更少。 (看看是否违反)
3.第三原则 :保持远见(Pattern: MaintainTheVision)
清晰的远见是一个软件项目成功的基础。. 没有这样的远见,项目开发最后就变成天天为一个不好的设计做补丁。Brooks说过:
概念的完整性是系统设计中最重要的问题。
Stroustrup 也说:
有一个干净的内部结构识构建一个可理解、可辨识、可维护
、可测试系统的基础。
Booch则总结道:
只有当你对系统的体系由一个清晰的感觉,才可能去发现通用的抽象和机制。开发这种通用性最终导致系统更简单,因此更小,更可靠
如果你不断地复制、粘贴、修改代码,最终你将陷入一个大泥潭(the Big Mud),你永远不可能对系统有一个清晰的认识。
4.第四原则:你制造的,别人会消费 (Pattern: WhatYouProduceTheyConsume)
软件系统不是在真空中使用的。其他人会使用、维护、文档你的系统。这依赖于对你系统的理解。所以,你设计、实现的东西应当能够让别人理解。要记住,你写的代码并非只给计算机看,你要时时记住,代码还要给人看。(Kent Beck)
如果到处泛滥似是而非的代码,别人如何能够辨别这些代码的相似和不同,如何去理解这些代码之间具有何种关系。
5.第五原则:对将来开放( Pattern BuildForTodayDesignForTomorrow)
一个成功的软件有很长的生命期。你必须能够使得软件能够适应这样和那样的变化。所以,一开始就不要软件设计到死角上去。请总是问一下自己“如果这样,那么。。?“这个问题,你要考虑到各种各样的可能性,而不光光是图省事。复制,粘贴一下即可。
6.第六原则:为重用做好计划
软件模式是重用计划的一种。不断重复的代码显然不是这样的计划。
(See CommentsOnSix)
7.第七原则:思考!
在采取任何动作之前首先做一个清晰、完整的考虑,这样才能产生更好的结果。如果你考虑了,但还是产生错误的结果,那么这种努力也是值得的。在你学习或研究类似的问题时,更容易理解和掌握。

这些原则告诉我们轻松地复制、粘贴和修改代码不可能产生好的,也就是容易理解、维护、重用的代码。但请不要走极端。
我一直认为,一个好的软件系统是各种因素权衡的结果,也就是你如何把握一个度的问题。重复代码产生的另外一个主要原因就是做得太多,XP有一个基本原则叫做You Arent Gonna Need It,它是说“只实现你真正需要的东西,从来不去实现你预期需要的东西“。如果你去实现你现在认为将来需要的东西,不一定就是你以后真正需要的东西。你处于现在的环境中可能无法理解你要实现东西究竟是什么样子的。你会浪费大量的时间去构造这样不知道是否必须的可能性。同时,当你真正实现的时候就可能产生重复代码。

Martin Fowler在它的Refactoring一书中有很多用来处理代码重复,包括:
1. 同一个类的两个方法中有相同的表达式,使用Extract method,然后大家都调用该method;
2. 两个兄弟子类之间有相同的表达式,那么在这两个子类中使用Extract Method,接着使用pull up field,移到共同的超类
3. 如果结构相似而并非完全相同,用Extract method把相同部分和不同部分分开。然后使用form Template method.
4. 如果方法使用不同的算法做相同的事情,那么使用substitute algorithm
5. 如果在两个不相干的类中有重复代码,那么在一个类中使用Extract class,然后在其他类中使用该class对象作为元素。
等等。

重复代码需要refactoring是毫无疑问的,关键在于,你如何找到重复代码,如果所有的重复代码都是死板的重复,那问题是很容易解决的。但是软件开发的复杂因素可能往往使重复代码表现为相似性而并非完全的重复。这些相似性可能并非一眼就能看出来。而是需要经过其它的Refactory步骤和一定的先见之明。
另一个问题就是排除重复代码的粒度,只有大段的重复代码有价值去排除,还是即使是小小的2、3句重复代码就应该去排除。重复代码排除的基本方法是建立自己单独的方法,如果系统中许许多多的方法都很小,方法之间相互调用的开销就会增加,它同时也增加了维护的开销。
但是,这些开销是值得的。方法是覆盖的最小粒度,能够被覆盖的粒度越小,能够重用的范围和成都就愈广。但在这个问题上也不要走极端,只有当一个方法实现一个具体的可以用Intent Revealing Name(揭示意图的名字)命名时,一段代码才值得称为一个方法,而不是考虑其代码的多少。

Martin Fowler在他的refactoring中描述了很多这样的例子,Kent Beck则在Smalltalk Best Practice Pattern中更基础地揭示了隐含在这些refactoing下的意图。
下面是一个实际的例子,来自于Martin Fowler在ACM上的设计专栏:
class Invoice...
String asciiStatement() {

StringBuffer result = new StringBuffer();
result.append(“Bill for “ + customer + “/n”);
Iterator it = items.iterator();
while(it.hasNext()) {
LineItem each = (LineItem) it.next();
result.append(“/t” + each.product() + “/t/t”
+ each.amount() + “/n”);
}
result.append(“total owed:” + total + “/n”);
return result.toString();
}
String htmlStatement() {
StringBuffer result = new StringBuffer();
result.append(“
Bill for ” + customer + “

”);
result.append(“”);
Iterator it = items.iterator();
while(it.hasNext()) {
LineItem each = (LineItem) it.next();
result.append(“ ” + each.product()
+ “ ” + each.amount() + “
”);
}
result.append(“ ”);
result.append(“
total owed:” + total + “

”);
return result.toString();
}
}
asciiStatement和htmlStatement具有类似的基础结构,但是它们的实际步骤却有所不同。他们都完成三件事情:
1. 打印发票头
2. 循环每一个项目,并打印
3. 打印发票尾部
这种结构的相似性和意图马上上我们使用composed method(也就是Martin Fowler的Extract method):

interface Printer {
String header(Invoice iv);
String item(LineItem line);
String footer(Invoice iv);
}
static class AsciiPrinter implements Printer {
public String header(Invoice iv) {
return “Bill for “ + iv.customer + “/n”;
}
public String item(LineItem line) {
return “/t” + line.product()+ “/t/t” + line.amount() +“/n”;
}
public String footer(Invoice iv) {
return “total owed:” + iv.total + “/n”;
}
}
象html则可以实现htmlPrinter.
class Invoice...
public String statement(Printer pr) {
StringBuffer result = new StringBuffer();
result.append(pr.header(this));
Iterator it = items.iterator();
while(it.hasNext()) {
LineItem each = (LineItem) it.next();
result.append(pr.item(each));
}
result.append(pr.footer(this));
return result.toString();
}
class Invoice...
public String asciiStatement2() {
return statement (new AsciiPrinter());
}

现在,statement包含一个通用的结构,重复性已经被排除。更重要的是,你可以实现其它的Printer,XXXPrinter,从而能够轻易地扩展系统。
BTW,Martin Fowler在这里使用了Dispatched Interpretation模式,statement隐瞒了内部的细节,它隐藏内部的数据和表示,当它需要Printer做一件事情时,它负责解码内部的数据结构,然后反过来把消息传给Printer.

参见:Martin Fowler:Refactoring:Improve the design of Existing Code
Kent Beck : Smalltalk Best Pratice Pattern
ACM: Martin Fowler Design column:Reduce repetation
Kent Beck: Extreme Programming Explained

软件工程的七条基本原则

1、 用分阶段的生命周期计划严格管理     在软件开发与维护的漫长的生命周期中,需要完成许多性质各异的工作。这条基本原理意味着,应该把软件生命周期划分成若干个阶段,并相应地制定出切实可行的计划...
  • mydriverc2
  • mydriverc2
  • 2015年07月27日 14:02
  • 2151

7个软件开发原则

关于代码重复最著名的单词是Kent Beck的Once And Only Once,也就是说软件操作的任何一个片断--不管是一个算法,一个常量集合,用于阅读的文档或者其他东西--应当只出现一次。 软...
  • e5Max
  • e5Max
  • 2016年03月24日 13:16
  • 679

《敏捷软件开发:原则、模式与实践》读书笔记

1、敏捷软件开发宣言 个体和交互         胜过 过程和工具 可以工作的软件     胜过 面面俱到的文档 客户合作           胜过 合同谈判 响应变化           胜...
  • backard
  • backard
  • 2013年07月19日 17:20
  • 1043

软件测试七大原则与分类

软件测试七大原则 一、测试显示缺陷的存在 测试可以显示缺陷的存在,但不能证明系统不存在缺陷。测试可以减少软件中存在缺陷的可能性,但即使测试没有发现任何缺陷,也不能证明软件或系统是完全正确的,或者说...
  • xaj_123
  • xaj_123
  • 2015年09月20日 10:30
  • 864

软件设计的开发关闭原则

一、理论知识 Software entities (classes, modules, function, etc.) should be open for extension, but close...
  • hudashi
  • hudashi
  • 2016年06月27日 20:46
  • 523

软件设计6大原则

(1) (2)里氏替换原则()Liskov Substitution Principle LSP
  • u012656834
  • u012656834
  • 2014年07月08日 14:42
  • 1193

模版方法模式与策略模式如何让软件开发符合“开闭原则”

背景描述 在实现一个需求时,通常开发人员都不会准确预测到功能以后会如何改变,如果设计的代码不符合“开闭原则”,那么将来需求稍微变动,往往程序就要进行较大改动,或者代码十分臃肿,不利于维护。我以一...
  • wangwenyang8888
  • wangwenyang8888
  • 2017年05月22日 16:58
  • 231

编程中的正交原则

今天读到了《程序员的修炼之道》关于“正交的好处”一节,突然间想起了一件事情。 关于当年参加飞思比赛的故事。 故事要从一次师弟的反馈说起。话说参加完这个比赛之后,最引以为豪的作品还是由我们队一路摸索建立...
  • longyindiyi
  • longyindiyi
  • 2014年08月10日 18:25
  • 1913

【JAVA】面向对象设计七个原则

程序是为需求服务的,需求无时无刻都有可能变更,最好一开始就依托一套优秀原则来设计程序,以下介绍面向对象设计的七个原则。...
  • u011704894
  • u011704894
  • 2016年01月20日 14:28
  • 1206

软件开发原则

本原则是本人结合项目的实施开发编写代码情况,对多年以来带领项目实施奋战在开发一线经验的提炼与概括。这十条开发指导原则,最基本的思想是“高效,高质量的写出满足业务功能目标的代码。” 1、先开发简单明确...
  • osforge
  • osforge
  • 2015年04月08日 10:40
  • 191
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:7个软件开发原则
举报原因:
原因补充:

(最多只允许输入30个字)