bob大叔在他的著作《敏捷软件开发-原则模式与实践》一书中提到拙劣设计的七种症状:
1、僵化性:指的是设计难以改变;
2、脆弱性:设计易于遭到破坏;
3、顽固性:设计难以重用;
4、粘滞性:难以做正确的事情;
5、不必要的重复性:过分设计;
6、不必要的重复:滥用鼠标进行复制黏贴
7、晦涩性:混乱的表达
设计的“臭味”主要是因为他们违背了一个或多个设计原则,这些原则包括:
1、单一职责原则(the single responsibility principle, SRP);
2、开放-封闭原则(the open-close principle,OCP);
3、liskov替换原则(the liskov substitution principle, LSP);
4、依赖倒置原则(the dependency-inversion principle,DIP );
5、接口隔离原则(the interface segregation principle, ISP)
敏捷联盟的宣言包括:
人和交互 重于过程和工具
可以工作的软件 重于面面俱到的文档
客户合作 重于合同谈判
随时应对变化 重于遵循计划
那么,什么是敏捷设计呢?
敏捷设计是一个过程,不是一个事件。它是一个持续的应用原则、模式以及实践来改进软件的结构和可读性的过程。它致力于保持系统设计在任何时候都尽可能的简单、干净以及富有表达力。
下面用一个仿书中的案例来阐述拙劣设计与敏捷设计的区别:
场景:一个电台app,最初的设计boss只需要放放音乐就好了,这个需求很简单,第一版的设计如下:
<?php
class Radio{
public function broadcast(){
$music = new Music();
$this->play($music);
}
public function play($music){
$music->sing();
}
}
嗯,看上去一切度很不错,你一定会因为这个高超的编程技能升职加薪迎娶白富美走上人生巅峰的!!!
可惜,很不辛,需求变化了,炒鸡想砍死产品经理有木有!!!
现在电台不仅要播音乐,还要播有声小说,怎么办呢?这当然难不倒聪明绝顶的你,毕竟,你可是要走上人生巅峰的人啊!
很快,你就把第二版的设计做出来了:
<?php
class Radio{
public static $READBOOKS = FALSE;
public function broadcast(){
if(self::$READBOOKS){
$book = new Book();
$this->play($book);
}else{
$music = new Music();
$this->play($music);
}
}
public function play($stuffToPlay){
if(self::$READBOOKS){
$stuffToPlay->read();
}else{
$stuffToPlay->sing();
}
}
}
天啊,你一定是天才,这设计地球上除了你这颗大脑之外,一定没有第二颗大脑可以想得到!!!,哎,终于加完班了,回去看会儿片睡一觉吧!
不行,又有新需求了,现在电台还要播脱口秀,你现在再怎么想磨刀霍霍向PM也不行,还是活动下脖子开始苦逼的码代码吧!
很快,第三版代码又出炉了:
<?php
class Radio{
public static $READBOOKS = FALSE;
public static $TALKSHOW = FALSE;
public function broadcast(){
if(self::$READBOOKS){
$book = new Book();
$this->play($book);
}elseif(self::$TALKSHOW){
$talkShow = new TalkShow();
$this->play($talkShow);
}else{
$music = new Music();
$this->play($music);
}
}
public function play($stuffToPlay){
if(self::$READBOOKS){
$stuffToPlay->read();
}elseif(self::$TALKSHOW){
$talkShow->talk();
}else{
$stuffToPlay->sing();
}
}
}
评价:第一版的设计没有什么问题,但是随着需求的不断变化,代码的坏味道就出现了,要播的内容越多,需要设置的标识符就会越来越多,if/else的嵌套也会越来越复杂,如果有一天要增加午夜板块(你懂的),我们还要继续这样设计吗?
敏捷设计的版本:
在这个案例中不断变化的是要播放的内容,我们可以将这部分内容抽象出来,做成一个Interface:
<?php
interface Sound{
public function play();
}
具体实现类:
<?php
class Books implements Sound{
public function play(){
$this->read();
}
}
<?php
class TalkShow implements Sound{
public function play(){
$this->talk();
}
}
<?php
class Music implements Sound{
public function play(){
$this->sing();
}
}
<?php
class Radio{
public function play(Sound $sound){
$sound->play();
}
}
这样的设计,今后需求再有变化,我们只需要新增一个实现类就行了,这也符合设计原则中的开闭原则(对修改关闭,对扩展开放)。
当然,敏捷设计不赞成过度设计,如果没有后期这些需求的变化,第一版的设计就足够了,没有必要为了设计而设计,增加不必要的复杂度。