《驯服烂代码:在编程操练中悟道》一第1章 刻舟求剑的文档

第1章 刻舟求剑的文档

“什么是软件?”20世纪90年代初的一个冬日,在北京东南部的一所大学里,一位年近花甲的老师,给我们这些计算机系的学生讲软件工程这门课时,问了这个问题。对于当时几乎没有机会接触计算机的我来说,软件就是学校计算机房里那些DEC小型机上令人费解的命令,和286个人计算机里那些好玩的“吃豆子”和“赛车”游戏。“软件不仅仅是程序,还包括描述程序的文档。软件就是程序加文档。”老师对软件的定义,深深地刻在我的脑子里,其程度之深,以至于在之后的很长一段时间里,总令我觉得文档对于软件的影响力,似乎要超过程序。
这一点在我大学毕业后20年的软件开发相关工作的实践中,不断地得到印证。各种各样的文档——需求文档、概要设计文档、详细设计文档、测试文档等,在我先后经历的多个软件开发项目中,始终占据着重要的地位。“毕竟,只要文档在,就不怕开发人员的频繁更换。”一位软件开发经理这样对我说。除了要写Word或Excel的文档,程序员们还被要求在源代码中写尽量详尽的注释。在软件开发经理眼中,撰写文档和编写注释的能力,是衡量程序员是否称职的一项重要标准。
“为保证客观性,软件开发完成后,应该由不同的人员来对其进行测试。”老师的这句话也时时萦绕在我的耳边。这句话的影响力是如此巨大,以至于前些年我做程序员时,我和周围的程序员们都一致认为测试就是测试工程师的事情。在10多年中,我经历的每一个项目,都无一例外地有一个独立于开发团队的测试团队,开发团队将代码开发完成后,简单地在自己机器上运行一下,然后就将代码提交给测试团队去测试了。
十几年来,不管是开发新功能还是修复bug,我一直在努力地撰写文档,编写和修改代码及注释,然后交给测试人员去测试,再去修改测试人员提出的bug,这一切看起来都像教科书上描述的那样地完美和正确。但是最后我却难过地发现,用这种方法开发出来的软件,无一例外逐渐沦为烂代码。在烂代码的沼泽里,即使有文档,也读不懂代码;即使bug很小,也不敢修改代码。我甚至怀疑,这种方法或许会助长烂代码的滋生。这些文档就好像“刻舟求剑”故事中那个刻在船身上的记号。让我们先用这种传统的测试后行(test last)的开发方法,做一个编程操练吧,来看看其中会有什么问题。
对于本书中所有的编程操练,我都将邀请您——我的亲爱的读者——来与我一起结对编程。
“啊?和我结对编程?我还从来没试过哩!”读者可能会说。
结对编程其实一点都不神秘,如果把编程比作打网络游戏,结对编程就好比两个人结伴去打魔兽,除了可以相互学习切磋之外,还能相互有个照应。一起来看看本书的第一个编程操练。
这个操练是我于2013年9月为在“北京设计模式学习组”的第9次活动中操练Observer设计模式而编写的。灵感来自于我在酒店下榻时,在大堂里看到的墙壁上悬挂的那些显示世界上各个主要城市的时间的时钟。我在想,如果所有这些时钟都走时不准,酒店大堂服务员一个个地分别调时间太麻烦,而这位服务员的智能手机上肯定用的是该酒店所在地的当地时间,要是能够在调准服务员手机时间的同时,将酒店大堂墙壁上所有城市的时钟根据时差相应地自动调准,那该多方便。
假如在北京一家酒店的大堂里有5个时钟,分别显示北京、伦敦、莫斯科、悉尼和纽约的时间。其中,伦敦与UTC(Coordinated Universal Time,协调世界时)时间一致,北京比UTC时间早8小时,莫斯科比UTC时间早4小时,悉尼比UTC时间早10小时,纽约比UTC时间晚5小时。若所有这些城市的时钟都多少有些走时不准,需要调整时间时,大堂服务员只需调准自己手机上的北京时间,那么墙壁上那5个城市的时间就能相应地自动调整准确。酒店世界时钟和服务员的手机时钟如图1-1所示。

在程序员中,熟悉Java语言的人数相对较多。那么咱们能不能用Java语言实现上面这个编程操练呢?
“好吧,需求已经说得很清楚了。咱们先用UML和Use Case来对这个需求进行分析和设计吧。”
首先把功能性需求整理成下面这样的需求列表,并编上号。
1)REQ01:一家北京的酒店大堂里有5个时钟,分别显示北京、伦敦、莫斯科、悉尼和纽约的时间。
2)REQ02:伦敦与UTC时间一致,北京比UTC时间早8小时,莫斯科比UTC时间早4小时,悉尼比UTC时间早10小时,纽约比UTC时间晚5小时。
3)REQ03:将酒店大堂服务员的智能手机时间设置为北京时间。
4)REQ04:若大堂墙壁上所有那些城市的时钟都或多或少有些走时不准,需要调整时间时,只需调准服务员手机的时间,那么墙上5个城市的时钟时间都能够相应地自动调整准确。
把需求编上号,将来实现和测试这些需求时就好跟踪了。
领域模型定义“系统能够做什么”这样的功能需求,重在解决沟通误解的问题。它关注项目中所有概念的“准确性”,需要建立描述问题领域的通用词汇表,来消除误解和增强概念的准确性。这个词汇表会随着项目的进展,不断地完善和更新。
设计领域模型的第一步是找出领域类。从上面那个需求列表里找出一些重要的名词,可以作为初步的领域类。
这个题目重要的名词有:城市时钟、手机时钟和UTC时间,或许还应该有酒店服务员。
先用这些名词,以后再继续调整。下一步可以创建词汇表,来描述这些名词。
词汇表如表1-1所示。

下一步就可以画领域模型类图了。为了让领域模型类图更有条理,可以从城市时钟和手机时钟里抽象出一个“时钟”类。现在可以先在词汇表中添加一行,表示“时钟”。
在词汇表中添加的那一行如表1-2所示。

城市时钟和手机时钟都继承这个时钟类,是泛化关系。而时钟类中又包含一个UTC时间类,是聚合关系。
领域模型类图如图1-2所示。

首先,酒店服务员这个角色与Update the time of the phone clock这个用例打交道,来更新手机时钟的时间。然后这个用例会调用Update the time of all city clocks这个用例,表示自动更新所有城市时钟的时间。
“咱们不妨看看这个操练的场景是否有设计模式可以适用,这样可以借鉴前人的经验,而不用自己闭门造车。”
“可以快速浏览一下‘四巨头’的23个设计模式的意图。看起来Observer观察者模式的意图正好和咱们的编程操练相吻合。‘定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。’这不正好能满足当调整手机时钟的时间,所有城市的时钟都能自动更新时间这个需求吗?咱们可以把上面的领域模型类图照着‘四巨头’画的类图改一改。”
在“四巨头”的《设计模式》一书中,Observer模式的UML类图如图1-4所示。

类图有了,下面可以参考“四巨头”的类图来细化咱们的类图。在每个类上添加暴露给外界的接口,也就是公共方法。
细化后的类图如图1-6所示。

为简化起见,对于时间这里只考虑小时,所以时间都用int类型来表示。
在细化后的类图中,TimeSubject类可以用一个名叫clocks的HashMap来保存所有5个城市的Clock类的对象和手机时钟对象。为了便于向这个HashMap中添加或删除对象,需要有attach()和detach()这两个方法。TimeSubject类的notify()方法是个抽象方法,它在其子类UtcTime中被实现,具体实现的伪代码在图中用一个注解框标出来了,即对于clocks这个HashMap成员变量,用一个for循环来调用其中保存的每一个Clock对象中的setLocalTime()方法,来对所有时钟的当地时间进行自动更新。而这个notify()方法,可以通过UtcTime类的setUtcTime()方法来触发调用。
Clock抽象类有一个私有的成员变量localTime,用于保存这个时钟所表示的当地时间。它还有另一个私有的成员变量UTC_OFFSET,用于保存它的每一个子类的实例相对于UTC时间的时差。Clock类有一个抽象方法setLocalTime(),用来设置该时钟的当地时间。这个方法之所以是抽象的,是因为Clock类的两个子类——表示手机时钟的PhoneClock类和表示城市时钟的CityClock类——用不同的方式实现了这个方法。在CityClock类中,这个方法的实现仅仅是把传入的参数赋值到其成员变量中;而在PhoneClock类中,这个方法的实现除了赋值外,还调用了PhoneClock类中UtcTime类型的成员变量utcTime的setUtcTime()方法,来触发调用utcTime的notify()方法,从而能够实现自动更新所有城市的时间。
UtcTime类扩展了其父类TimeSubject,且有一个utcTime私有成员变量,用来保存UTC时间。
现在设计文档有了。在开始编程之前,咱们先回顾一下这一章所做的工作:
1)使用了设计驱动的开发方法,来进行有关酒店世界时钟的结对编程操练。
2)整理出了需求列表,并编上了号。
3)创建了领域词汇表,从中找出领域类。
4)画出了领域模型类图。
5)画出了Use Case用例图。
6)根据Observer观察者设计模式,更新了领域模型类图,并画出了细化后的类图。

时间: 2024-09-28 20:17:01

《驯服烂代码:在编程操练中悟道》一第1章 刻舟求剑的文档的相关文章

《驯服烂代码:在编程操练中悟道》一导读

前 言 程序员好比运动员,要想在竞技场上获胜,需要在训练场里长期刻苦地练习技艺. 程序员好比士兵,要想在短兵相接的白刃战中取胜,需要在练兵场上长期刻苦地练习格斗. 程序员好比调酒师,要想用炫目的技艺为客人花式调酒,需要在业余时间长期练习抛瓶. 运动员与和平年代的士兵有大量的时间用于训练.但绝大多数程序员所在的软件公司,在一个接着一个的项目进度的压力下,无法提供大量的时间来供程序员练习,而很多程序员又不愿意在下班后再碰代码.如此一来,程序员们就成了一直在竞技场上比赛的运动员,一直在敌人面前搏斗的士

《驯服烂代码:在编程操练中悟道》一第2章 按图索骥地编写代码

第2章 按图索骥地编写代码 现在,设计文档都齐备了,github也配好了,安装了JDK7和Maven,空项目已经用Maven建好了.还安装好了一个免费使用的IntelliJ IDEA 13.1 Community版,用来编程.现在就可以按照细化后的类图来编写第一个类TimeSubject了. 下面就是TimeSubject类的代码: public abstract class TimeSubject { protected Map<String, Clock> clocks = new Has

textbox操作-VB中,将textbox内容复制给excel文档

问题描述 VB中,将textbox内容复制给excel文档 我希望在VB中放入5个textbox,将5个textbox的内容分别复制给一个叫kiss的excel文档中的A.B.C.D.E列每列第一个非空单元格,完成后保存kiss.xls到原路径(桌面). 各位大侠们帮忙看看,这个第一次用,实在不会搞,折腾了好久了,谢谢啦 解决方案 用VBA http://blog.csdn.net/laotou99/article/details/12967673 不需要什么复制粘贴.另外,你可以利用excel

c#代码-C#编程过程中遇到的难题

问题描述 C#编程过程中遇到的难题 我的界面form_load一打开适合一张数据库里面的退货表联系上了的,但是如果我想要查询 订单表的话,怎么做呢?而且是不换界面的,因为我的界面使用的是数据网格来显示表格,当我点击查询的订单表的时候,总是会弹出ConnectionString尚未初始化这个问题?怎么解决呢?以下是我查询的代码,求指导 SqlCommand sqlCommand = new SqlCommand(); SqlConnection myConnection = new SqlConn

《嵌入式C编程:PIC单片机和C编程技术与应用》一2.5 设计文档

本节书摘来自华章出版社<嵌入式C编程:PIC单片机和C编程技术与应用>一书中的第2章,第2.5节,作者 [美]马克·西格斯蒙德(Mark Siegesmund),更多章节内容可以访问"华章计算机"公众号查看 2.5 设计文档 当程序中用到一些标识符(像MAX_NUMBER_OF_ENTRIES),并且需要一份正式文档时,该文档需要列出所有的常量,并说明它们的含义.在程序中添加注释来描述这些常量将有助于理解代码,并有助于生成文档.有些工具可以从代码中提取出常量的注释,下面给出

用PHP4中的PDF扩展来创建一个PDF文档

综述:PDF文档常被用在电子图书.说明书等方面,可以有效地防止拷贝与盗版,在PHP4中,我们能创建一个PDF格式的文档吗?答案是:运用PHP中的PDF扩展库. 如何配置支持PDF的运行环境? 首先,我们需要安装PDFLib 3.0.1 和 PHP4.0.1pl2 以支持PDF. 软件要求 : PHP 4.02+ ( http://www.php.net ) PDFLib 3.0.1 ( http://www.pdflib.com ) 直接从http://php.net下载PHP的Uwe Stei

Spring Boot中使用Swagger2构建强大的RESTful API文档

由于Spring Boot能够快速开发.便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API.而我们构建RESTful API的目的通常都是由于多终端的原因,这些终端会共用很多底层业务逻辑,因此我们会抽象出这样一层来同时服务于多个移动端或者Web前端. 这样一来,我们的RESTful API就有可能要面对多个开发人员或多个开发团队:IOS开发.Android开发或是Web开发等.为了减少与其他团队平时开发期间的频繁沟通成本,传统做法我们会创建一份RESTf

在Word 2010中邮件合并时如何合并到新文档

在Word 2010文档中进行邮件合并时,为了能够对单个文档进行编辑(例如为 特定收件人的信函添加个性化的文字),同时也是为了避免直接打印可能带来的 纸张浪费,用户可以将信函首先合并到新文档,操作步骤如下所述: 第1步,打开Word 2010文档窗口,切换到"邮件"功能区.在 "完成"分组中单击"完成并合并"按钮,并在打开的菜 单中选择"编辑单个文档"命令,如图2011080701所示. 图 2011080701 选择&quo

Ubuntu系统中怎么使用原生的MS Office编辑文档?

  在 Ubuntu 上是无法使用 MS Office 办公套件的.Ubuntu 自带 LibreOffice,但是存在一些兼容性问题.那么,如何在 Ubuntu 平台上创建原生的 MS Office 文档呢?办法是有的,其中之一就是使用 Office Online. 1.百度 Office Online,选择官网的链接点击打开,登录 Office Online 网站. 2.在 Office Online 的主页面上,列出了可用的在线 App,几乎涵盖了桌面版 Office 的所有组件. 3.点