`
zhangjunji111
  • 浏览: 46248 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Bill Venners与Martin Fowler的对话(设计原则与代码所有权)

阅读更多

对话马丁·福勒(Martin Fowler)——第二部分:设计原则与代码所有权
简介

在访谈的这部分,福勒讨论了一些设计原则,包括如何避免重复,如何分离业务逻辑和其表示,显式表达代码。除此之外,还阐述了重构如何依赖于代码所有权。

第二部分:设计原则与代码所有权在连载的第二部分,福勒讨论了一些设计原则,包括如何避免重复,如何分离业务逻辑和其表示,显式表达代码。除此之外,还阐述了重构如何依赖于代码所有权。

不要重复自己

比尔:你在《重构》一书中提到:“代码应该实现任何逻辑一次且仅一次,这是良好设计的要素”。为什么你会认为这是良好设计所必不可缺的要素呢?
马丁:我曾经力图找到一种简单而通用的标准来区分设计的好与坏。 我想,避免重复是最有价值的准则之一。“一次且仅一次”是极限编程的座右铭。《程序员修炼之道》(The Pragmatic Programmer)的作者把其概括为“不要重复自己”(don't repeat yourself),也即DRY原则。
说到避免重复的方法,你可以来做这样一个练习。首先,走查程序代码,检查是否存在重复代码。然后,不需要考虑代码到底要完成什么任务,而 只需要坚定地移除这些重复的代码。反复进行这个过程。通过简单的移除重复代码,我最终“偶得”一个美妙而优雅的模式。这样的情况时常发生。所以我认为,好 的设计通常就是在消除重复代码后得到的。
比尔:你说过,你一直在试图将良好设计的一些基本原则罗列出来。除了“一次且仅一次”或称之为DRY原则外,还有其他的原则吗?
马丁:我想,另一个相当重要的原则就是分离逻辑层和表示层,或者说将用户接口(UI)和应用程序完成的实际任务相分离。通过采用这样的原则,我在面对变化时游刃有余。所以,我认为这也是一个可以依赖的良好设计原则。
比尔:你说你在面对变化时游刃有余,是不是说在将来对程序代码做改动会很容易?
马丁:由于表示层和业务逻辑相互独立,在程序维护阶段所需要做出的变化将变得相当容易。分离了表示层和业务逻辑的程序也很容易被测试。这个原则对我非常有用,我认为可以把它看作是一个很好的基本设计原则。

代码清晰化表达

马丁:最近,代码明确表达思想这一设计原则留给我很深刻的印象。这个原则的意思就是让代码很明确的表达出将要实现的思想。
比尔:你的意思是什么?能更“明确”的解释一下吗?
马丁:举个例子来说吧。假设你需要传递一些数据。你是把数据放在字典里,然后将数据从字典里传递出去呢?还是先构造一个类来容纳这些数据,然后将保存了数据的这个类对象传递出去?
或许你认为采用字典的方案比较好。因为不需要实现一个新类。而且使用该方法的话,当要改变将要传送的数据,也不需要改动字典类中任何代 码。另外,对于能把什么样的数据放到字典里,也是相当灵活的。比如说当需要往字典中存入新数据时,不需要改动任何代码,而只需要将数据以新的关键字放入字 典中即可。
但问题是字典很不明确。你根本就无法得知字典里关键字的真实意思。字典不能确定称买东西的人是顾客还是客户?即使是拼写错误也无法检查出 来。更重要的是,即使你看完代码还是不能回答这样的问题:“访问这些数据的接口是什么?通过这些数据我能得到什么?”所以说,字典是很不明确的。而使用类 的话——即使你不得不重写所有成员变量及其访问函数——一切就变得明确起来。这时只需要查看源代码就知道这些数据是什么了。
比尔:我同意明确性能让我们更容易理解代码。
马丁:是的。我大概在去年或前年做 IEEE 软件专栏时,就曾经关注过这些简单的原则。在一篇标题为“要明确化”(To Be Explicit)的文章中还举了几个例子来阐述明确性。

良好设计的目的

比尔:在《重构》中,你还提到,“我强烈的认为良好设计是软件快速开发的一个基本要素。事实上,所有良好设计的目的就是为了允许进行快速开发”。
马丁:是的。
比尔:你好像前面提到过这点,能为我们解释一下为什么吗?听起来似乎你认为良好设计的唯一目的就是提高开发速度。
马丁:是的。我认为从多方面讲都是这样的。明确性能帮助我们阅读代码,还能帮我们快速应对需求变化。此外,代码设计得好的话,就很容易找到漏洞所在,很多漏洞将不再有藏身之所,

公共接口与发布接口

比尔:你在《重构》一书中提到,曾经碰到过一个团队,所有成员都将自己的接口发布给其他成员,结果大家常常是苦不堪言。
马丁:是的。
比尔:我的直觉是,作为一个从头开发大型系统且人数众多的团队的管理者,首要任务是将系统分成几个主要的子系统,然后定义这些子系统的接口。这些接口在某种程度上就是对外发布的接口。
接口并不是不能被改变。相反,最初要经常改变接口,随着时间的推移,需要改动的地方越来越少。原因很简单,接口随着时间的推移而成熟。除 此以外,随着时间的推移,越来越多的代码绑定在这些接口上,并且开发者对接口越来越熟悉。当到达某个点的时候,你就会说,“好吧,这就是接口。我们往下走 吧。”
马丁:哦,你是这样做的吗?我认为你没必要这样做。
比尔:如果你要想发布一个接口的话,那么最终还是要把它定下来。
马丁:那么让我来问你,假如你有一个团队,为什么要在团队内部发布接口呢?我在 IEEE 的另一篇文章中谈到了公共接口和发布接口的区别:发布接口的调用代码不能被更改。对于某个公共方法来说,我可能会觉得它的名称没有很好的描述其完成的任 务,也就是说更换一个名字或许能更清楚的表达它的功能。假如我能找到所有调用该方法的代码,那我就可以也应当改变这个方法的名称,即使它是一个公共方法。 但对于发布的接口来说,我不能这么做。在那篇文章中,我举了一个三人团队的例子。而这个三人团队的问题就在于他们在不需要发布接口的时候发布了接口。
Sun 必须把他们的 API 发布出来。Sun 不可能去认定 List 是不是一个好名字,是否应该用 VariableArray 来取代。这不是他们想做就能做的。外面到处都是采用 List 这个名字的代码,而 Sun 无法改变这些。但是在另一方面,在一个开发团队中——哪怕团队的规模有20到30人——改变一个未作慎重选择的名字不应该是件困难的事情。你应该可以很容 易的改变这些名称,特别是借助于类似 InteriJ 或者Eclipse 这样的重构工具,你只需要轻点鼠标就能改变所有的调用代码。这根本就不是什么难事。

强代码所有权和弱代码所有权

比尔:在《重构》一书中,你同时还提到了另外一件事:“你在公司中看到的这些都属于一种强代码所有权”。代码所有权是什么意思,强代码所有权有什么缺点?
马丁:我把代码所有权分为三类。在极限编程中用到的代码所有权有时称为集体代码所有权,有时也可以说“无代码所有权”。在这种所有权中,团队中任何人都不具有对代码的所有权。也就是说,任何成员可以在任意时间内改动系统中的任何代码。这就是极限编程采取的方式。
和这种所有权相对立的是强代码所有权。在强代码所有权中,严格区分我的代码和你的代码,我不能改动你的代码。当我想改动我的某个方法的名 字时,如果这个方法被你的代码所调用,那么我就必须先通知你,让你先把所有调用代码改过来,然后我才可以改动这个方法的名字。另一种办法就是,我得将这个 方法“过期化”(deprecation),然后完成后面一系列的步骤。实际上,在这种情况下,因为我绝对不能碰你的代码,因而你所用过的我的任何接口都 是发布的。
弱代码所有权则介于两者之间。弱代码所有权中,还是会区分代码的所有者,不同的是它允许开发者改动其他人的代码。开发者对自己的代码质量 仍然负有责任。如果我想要改变我的代码中某个方法的名称,改就好了。不过,假如我想将某个类的功能转赋到另一个类上,而这些代码的所有权属于你,那么至少 在这么做之前我应该让你知道。这一点是和集体代码所有权不同的。
不论是在弱代码所有权下,还是集体代码所有权下,都可以进行代码的重构。但是在强代码所有权下进行重构是个问题,因为你想做的许多重构根本就无法进行,比如,你不能去改动别人的调用代码。这就是强代码所有权下不适合做重构而弱代码所有权下可以做重构的原因。
比尔:所以问题不在于团队成员定义了各自的子系统的接口,而在于他们把这些接口看成是发布的接口。
马丁:就是这个问题——他们在团队内部发布接口。假如他们采用弱代码所有权的话,就不会有任何问题。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics