到底为谁设计?现在还是将来?

为谁设计?现在还是将来?
如何能既避免" Big Up Front Design",又保持好Open-Close Principle (OCP)?应当depends on一个接口/抽象类,还是一个简单的concrete class就够了?存在用Extract Interface的必要么?它的应用条件不是“ Several clients use the same subset of a class's interfaces, or two classes have part of their interfaces in common”吗?注意是多个客户,和多个类,要是目前只有一个实现类已经完成了所需的工作,我需要考虑将来可能出现的其他实现方法么?也就是说,我需要为应用Strategy打下基础吗?如果你说不用,等需求出现再说,我说:我也是这么想的,但是……呵呵,我们都有点儿naive了。

第一,让test drive的时候会自然而然“涌现出”mock object的需要:你想把A的部分工作交给B,然后你TDD B,结果B的test case中需要A,这时候只能Mock A,如何Mock A呢?只能把和B有关的那部分behavior extract成接口。结果又自然而然B depends on a interface which is implemented by A了。TDD说的“鼓励program to interface”果真不是唬人:结果还是一个类完事儿,中间却多了个接口,你可以自信的说:我没upfront design,这是tests lead me here。

第二个就是重构过程中产生的interface / super abstract class了。
纯粹让test来 drive设计可以比较快的通过test cases,其实现在我看高手应该能很快通过——你不用操心任何smell,OCP什么的,怎么脏怎么来,把你脑子里第一个出现的方案写下呗,当然要是这样,逼近good design/pattern的路要稍微长一点儿,这也是高手和新手的差别:Uncle Bob能一眼看出这儿用Command,这儿用Strategy(Agile Sw Dev, chapter 19, payroll project),那逼近的过程就短的多。然后重构,这是关键了。

重构的关键是refactoring to patterns,但首先要练就一双火眼金睛,能够发现code——或者更确切的——design [1] 中众多smell。

识别smell是第一关,还好,牛人已经指好路了,我辈follow先:《Refactoring》的第3章,《Refactoring Workbook》以及《Refactoring to Patterns》,第一个说实话有点儿高屋建瓴,更复杂的操作通通略去了,初学者看着可能没感觉;那第二个就是对第一个的解释和注解了:按照smell分类,smell的特点,产生原因一一道来,该用、能用什么招(重构)也一一列出,如果说《Refactoring》是《大金刚经》,那《Refactoring Workbook》就是《大金刚经速成手册》,结果你发现速成手册里好多是直接copy大金刚经中的,然后又去看经文,如此反复,对经文理解不可阻挡的深刻了。第三本书,致敬先!看老木匠 [2] 怎么打家具,破除Pattern的神秘和小木匠对Pattern的恐惧,试举一二例:
  • 这个活A要是干了A就显得太肥了(violate Single Responsibility Principle, SRP),分出来给AHelper干,然后干的方法又有多种——Strategy了
  • AClient有必要知道ASon1, ASon2么?没必要,就当它们都是其老子A就够了,怎么办?Encapsulate class with Factory。然后你明白了,Factory Method的真谛在“Polymorphism Creation”!要不是为了"Polymorphism Creation",Creation Method [3] 就够了
  • A一会儿是这样,一会儿是那样,干一样的活,用不同的方法,而且干着干着就从这样变成那样了——State,然后小木匠明白了State的精髓在"Transition Logic",也明白了State和Strategy是多么的不同啊!
  • A有时候就是A,有时候应该是A',A'比A多干一点儿但本质上还是A,小木匠拿斧子砍出一堆if...else if...,老木匠一把夺过斧子,用小刀刻出一个花纹——那多干的一点儿,贴在A上——Decorator。小木匠惊呆了,说怎么弄的?曰:Replace conditional with subclass / polymorphism先,Replace inheritance with delegation再。
  • ……
一共有27招。用来对付12种Smell。这下好了,从Smell,到Refactoring,到Pattern都有了。可得消化一阵儿。(消化都得一阵儿,那写经的……)

但是且慢,前面说“识别Smell是第一关”,如何写Test Case是第零关(习惯从0开始),面对
    public void test???
如何继续?这和“请按任意键”一样难,“任意键”在哪儿?

老木匠,这次是Uncle Bob了,说:行为。
从你需要的最明显的行为开始。你干的是保龄积分,就从Frame.getScore()开始 [4];你干的是payroll,就从先添加一个Employee开始,AddSalariedEmployee.execute() [5];你干的是在火星上跑来跑去的火星车,就从Rover.execute(instructions)开始 [6]。之后干完这个活了又干干啥了?小木匠说嗯我知道应该怎么怎么样,老木匠说,你把这些活归归类,排出个优先级,按行话这叫“User Story”。

行为,easy to say啊。从行为开始也就是说:别瞎忙活先定义一堆Class出来,然后猜每个Class中应当有哪些fields——仅有fields的都不是真正的类!充其量只能算个Data Class,而Data Class是一种Smell。从行为开始也就说彻底抛弃Upfront design,但是这不是说这时候就不能画UML,不能用Pattern,Uncle Bob的payroll project上来不就根据行为定下了Command Pattern为系统骨架吗? 他说,一个小时进行quick design session,在白板上草草的画下UML,目的仅仅是为了start the thinking process and give the developers a common mental model to work from,而这些UML,擦了,留着也行。

你说这种上来就说用Command等Pattern算不算Upfront design?我觉得这应该算作实力。其实后面implementation阶段还是TDD,结果也和UML草图不一样,前面的quich design session阶段应当算作“和计”,总的商量一下吧。

从Test Case开始,到重构,到Pattern,练的是勇气和智慧,看着一堆原本杂草一样的类(那也能叫类?)进化成精巧、美妙的结构,简单的就那么容易理解(我第一次看Agile Sw Dev中重构后的求素数的例子时那叫一个惊讶:代码还能这么清楚),又灵活的恰到好处,不是一件容易的事儿,但值得费一番力气。

跑题了,本来想说说TDD中如何把握OCP的(为谁设计?)。下次吧。

  1.  关于code就是design的思想,在agile guy看来肯定不是问题,其实Clemens,谁敢说他不是学院派的?ICSE'03的keynote speaker,也在他的书中(component software, software ecosystem)反复强调,software is a blueprint,not product,详见component sw,chapter1.4 "the nature of software and deployable entities",计算机是免费又迅速的软件“产品”生产工厂:你给它设计,它在deploy时“生产出”可用的产品,而代码是我们亲爱的软件设计的载 体,UML仅仅是辅助设计的工具。让认为UML和文档是设计,code是实现的人见鬼去
  2. Shug和我一起盖时说:sw developer就是工人,小孩说我爸是sw developer就和说我爸是木匠一样。
  3. Refactoring to Patterns, pp59
  4. Agile Software Development, pp46
  5. Agile Software Development, pp207
  6. 本来想把我做Mars Rover的例子拿来说说,但是toughtWorks估计不答应。私下交流吧。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值