首页 > 代码库 > The Pragmatic Programmer 读书笔记之一 DRY-Don’t Repeat Youself

The Pragmatic Programmer 读书笔记之一 DRY-Don’t Repeat Youself



The Pragmatic Programmer读书笔记之一

DRY-Don’t Repeat Youself

 

虽然自己买了很多软件工程方面的书,但是因为时间的问题,一直没有静下心来充充电。最近因为感觉自己在编程方面迫切需要有进一步的提高,于是打算好好的研读一下Andrew HuntDavid Thomas合著的《The Pragmatic ProgrammerFrom Journeyman toMaster》。本来我是比较偏好原版的,买的书不是原版就是影印版,但是由于该书原版价格有点贵,舍不得花银子,于是买了电子工业出版社出的评注版(周爱民、蔡学镛评注),这样既有读原版的风味,又有高手的评注做参考,照理应该是很不错的。

刚看完前面几章,边看边对照着手上的项目实践,感觉这书写得真是不错,真后悔没早花时间来进行研读。真是应了概述序言的那句话,作者知道怎样做,而且知道怎样说。大多数时候,我是知道该怎样做,但是说不出个所以然来。为了备忘,我把在读书过程中和平时编码的感悟以读书笔记的形式写下来和各位分享,不妥之处,恳请批评指正。

先介绍一下书的整体结构。书分了八个章节,介绍了编码的各个方面,其中以Tip的形式来浓缩作者的编程哲学,并详细解释为什么要这么做,这么做有什么好处,不这么做有什么坏处。全书加起来有70Tip(我已把所有的Tip摘录出来附在文后),可以看做是两位作者合起来40多年编程经验的精华。

在读前几章20多个Tip的过程中,感觉目前给我最大帮助、影响最深的一条Tip是:DRY - Don’t Repeat Youself,简称DRY原则,这条原则被其他很多软件工程方面的书所提及,如Robert C. Martin Clean CodeMartin FowlerRefactoring等。它的直译就是:不要重复你自己。在很多时候,同一个项目中的某些“事物”会多次出现而导致重复,这些“事物”包括需求、数据库结构定义、算法、类定义等等,如在数据库编程中,表的结构定义会在数据库设计说明书中存在,在代码中获取数据表的对象时也可能会有一份相同的“表定义”存在(用属性来一一对应数据表中各个字段),同时在数据库中表的结构定义还得重复一次,一般当表结构定义要修改时,先是修改文档中的,然后是数据库中的,最后是代码中的,需要时刻保持这三者的一致,要不然程序就可能不正确了,代码和文档也不一致了。当表的数量较小时,如十几个、二十几个表,用手工的方式更改还不会觉得是很麻烦的事,但当表的数量增加到上百个时,如果还是用这种手工的方式进行修改,不仅繁琐,而且很容易挂一漏万,只要代码和数据库有一处没有保持一致,程序就可能会报错崩溃,以前我经常是手工修改,改得自己都不胜其烦,特别是在做需求不确定的项目,表结构经常需要修改,真是奇怪自己为什么没有意识到这个问题,并加以解决,看来这就是实务(高手)程序员和普通程序员的差别了,普通程序只知道完成任务,遇到问题机械的解决,而实务程序员会思考是什么导致了这个问题,而进一步想办法予以解决和改进,以便在下次遇到同样的问题时能够套用之前的解决方法。

DRY原则和重复(Duplication)是紧密不可分的,DuplicationRepeat。书中分析了重复发生的几种情形:外界编程环境强加的重复、粗心导致的重复、懒惰(没耐心)导致的重复(Impatient duplication)、大型项目各开发者间的重复。我想我犯得最多的就是粗心和没耐心导致的重复,有时候需要一个功能,这个功能在其他模块已经实现,但是在当前环境下需要一点逻辑上的小变动,于是就复制粘贴过来,修改修改就当做完事了,这样就产生了重复。

真是后悔没有早点读这本书,害得自己以前走了不少弯路。接下来说说我是怎么实践DRY原则的。手头上有一个项目,是一个信息统计查询系统,整个系统大概有100多个表,每个表的字段数目从10个到30个不等,各个表之间基本上都是独立的,没有太复杂的关系,要求能够在线和离线录入数据,并能够对所有数据进行查询和统计。整个系统的用户是一个树形结构,有上下级的关系。要求服务器放在上级单位,下级单位负责搜集录入数据,但是有些下级单位未和上级单位连接网络,无法通过网络直接录入和上报数据。为了满足这种需求,我采用C/S结构来进行设计,整个系统分两大块,服务器端和客户端,服务器端相对比较简单,就是一台实体的服务器,装Windows Server 2003Oracle 10g R2数据库,所有的数据都存在服务器上,客户端分成两种,一种是管理查询端,另外一种是录入端,管理查询端就是对下级上报的数据进行导入、修改、查询,录入端分两种应用方式,网络版和单机版的,网络版的可通过网络直接将数据上传到服务器中,单机版的则采用Access作为后台数据库,用户在本地将数据录入完毕后将数据导出为上报数据包(为一个Zip压缩文件),再送至上级单位由人工导入服务器中。

在框架设计上没有什么难度,但最要命的是客户目前对整个系统需要统计什么数据、对数据需要做哪些查询汇总操作都不是很清楚。在做这个项目之前,客户都是使用Excel表的形式从下级单位搜集数据,仅仅是作为信息存储的一种载体,并没有相应的方法对数据进行查询和汇总分析。在开发过程中,不可避免的,客户需要不断的变更收集数据的项目、对数据进行统计的方式,导致数据表的结构也需要对应的修改和调整。如果放在以前,我可能还是采用老办法:客户提出修改意见,我修改文档、代码、数据库,来回往复的折腾,不出错是不可能的。

想想DRY原则,需要其他的办法来解决这个问题。

所有表结构的定义我都写在了数据库设计说明书里了,说明书是一个Word文档,以表格的方式详细列出了数据库中各数据表的字段名称、数据类型、注释,如果能够把Word文档中的表结构解析出来,生成创建表的DDL语句,然后使用代码连接数据库,执行这些DDL语句,那么就能实现自动创建数据库的目的,哪不是很好吗?要把Word文档里的表格内容解析出来,那很容易,可以使用MicrosoftWord Interop,但是我手上有AsposeWord组件,这个组件可以在不安装Microsoft Word的情况下解析和生成Word文档,而且使用比起微软本身的Word Interop方便得多。

我先使用代码把Word中的数据结构定义读取出来,然后拼接成创建表的DDL语句,可以按照需要生成创建AccessOracleSqlServer等各种类型数据库表的创建语句,最后使用代码连接数据库执行这些DDL语句以便在数据库中创建这些表。我只要在Word中改动表的结构定义,在数据库中生成表和在代码中生成数据表的类定义就可以通过代码自动完成了。这样大大提高了编程的效率,减少了出错的几率。

在对数据进行编辑显示时,我又遇到了麻烦。这些表之间的相互关联不是很紧密,基本上都是独立的,采用DataGridView进行数据显示是比较方便的,但是如果采用DataGridView来进行输入的话,有些不方便,因为有些表的字段是其他表的外键字段,在录入表数据时,只能从已录入的数据中进行选择,举个例子,表A中有一个单位名称字段A1,表B中也有一个单位名称字段B1B1的内容和A1的内容是一致的,B1是表B的外键,关联到表A的主键字段A1,这样在使用DataGridView是需要从表A中得到A1字段的内容列表,显示在表BB1字段输入框中供用户进行选择。客户不太想通过这样的方式录入数据,要求将表的内容显示为一个独立的编辑界面供数据录入,而且最好能够导出为Excel表的形式供多人录入,然后再导入到Access数据库中,以提高效率。如果要按照客户的要求做,那么在程序中必须存在一份表的结构定义,包括字段名称、数据类型,以便根据这些信息动态的生成一个数据编辑界面。

在之前,我已经将表定义写在数据库设计说明书里了,从数据库说明书将表结构定义提取出来,生成一个XML文档,让后使用代码解析这个XML文档,则既可以达到自动创建表的目的,也能够供程序对表结构进行解析,从而能自动生成数据录入界面供用户对数据进行编辑(待续)。


附:书中的70Tip

1. CareAbout Your Craft

2. ThinkAbout YourWork

3.Provide Options, Don’t Make Lame Excuses

4. Don’tLive with Broken Windows

5. Be aCatalyst for Change

6.Remember the Big Picture

7. MakeQuality a Requirements Issue

8.Invest Regularly in Your Knowledge Portfolio

9.Critically Analyze What You Read and Hear

10. It’sBoth What You Say and the Way You Say It

11. DRY- Don’t Repeat Yourself

12. MakeIt Easy to Reuse

13.Eliminate Effects Between Unrealated Things

14.There Are No Final Decisions

15. UseTracer Bullets to Find the Target

16.Prototype to Learn

17.Program Close to the Problem Domain

18.Estimate to Avoid Surprises

19.Iterate the Scheudule with the Code

20. KeepKnowledge in Plain Text

21. Usethe Power of Command Shells

22. Usea Single Editor Well

23.Always Use Source Code Control

24. Fixthe Problem, Not the Blame

25. Don’tPanic

26. “Select”Isn’t Broken

27. Don’tAssume It - Prove It

28. Leana Text Manipulation Language

29.Write Code That Writes Code

30. YouCan’t Write Perfect Software

31.Design with Contracts

32.Crash Early

33. Ifit Can’t Happen, Use Assertions to Ensure That It Won’t

34. UseExceptions for Exceptional Problems

35.Finish What You Start

36.Minimize Coupling Between Modules

37.Configure, Don’t Intergate

38. PutAbstraction in Code, Details in Metadata

39.Analyze Workflow to Improve Concurrency

40.Design Using Services

41.Always Design for Concurrency

42.Separate Views from Models

43. UseBlackboards to Coordinate Workflow

44. Don’tProgram by Coincidence

45.Estimate the Order of Your Algorithms

46. TestYour Estimates

47.Refactor Early, Refactor Often

48.Design to Test

49. TestYour Softwate, or Your Users Will

50. Don’tUse Wizard Code You Don’t Understand

51. Don’tGather Requirements-Dig for Them

52. Workwith a User to Think Like a User

53.Abstractions Live Longer than Details

54. Use aProject Glossary

55. Don’tThink Outside the Box -Find the Box

56.Listen to Nagging Doubts - Start When You’re Ready

57. SomeThings Are Better Done than Described

58. Don’tBe a Slave to Formal Methods

59.Expensive Tools Do Not Produce Better Designs

60.Organize Around Functionality, Not Job Functions

61. Don’tUse Manual Procedures

62. TestEarly. Test Offen. Test Automatically.

63.Coding Ain’t Done ‘Til All the Tests Run

64. UseSaboteurs to Test Your Testing

65. TestState Coverage, Not Code Coverage

66. FindBugs Once

67.Treat English as Just Another Programming Language

68.Build Documentation In, Don’t Bolt It On

69.Gently Exceed Your User’s Expenctions

70. SignYour Work