程序的困惑

                                          程序的困惑

写在前面的话

问题

我们写的程序难吗?

技术问题

问题源于何处?

对症下药

一个例子

 

写在前面的话

       假设我们已经详细的了解了用户的需求,包括用户想要的是什么,什么东西日后会变动,哪些功能日后有扩展的需求。假设我们的项目小组成员都是合格的程序员,熟悉公司的开发环境,可以熟练编写程序,并且对于自己的工作有着强烈的责任感。

 

问题

       首先我们必需承认问题的存在,否则也就无需进行下面的讨论。

我把遇到的问题简单的分成了两类。

第一类问题是bug,也就是程序中的错误。

比如,正确的输入后却没有正确的输出;录入边值、错误数值后没有正确的提示或者导致了更严重的错误;程序没有按照预期的流程进行;多人操作时系统出现问题。系统运行速度达不到要求;文字错误,等等。

       第二类问题我称为时间问题。

我们拿到需求的时候,美工开始设计页面,项目经理决定使用什么程序架构,设计数据库,进行工作分派。程序员拿到安排的任务开始编写程序。我们的程序中A调用了BB调用了CC也许应该调用D,但是他又知道了D是如何实现那个功能的而改为自己书写。模块之间,模块内部的相互关系变得复杂起来。项目不断进展,系统慢慢的变成了八卦迷宫,只有项目经理和部分程序员知道其中每条道路的走向和各种不为人知的秘密通道。也许有良心的程序员会写一些文档,将他们所知的都记录下来。随着时间的推移,需求发生了一些变动,程序需要更改或者扩展。当作程序维护的程序员修改了A的一个行为的时候,D模块的程序却出现了错误。就好比修车工人给汽车换了一个轮胎可却导致发动机不能点火一样。程序员不得不深究原因,他最终发现了AD之间的一个隐情。随着程序的改动,各种各样的秘密关系都被暴露了出来,就好像是看福尔摩斯的侦探小说一样。最后只有当维护人员可以将这个系统把玩于股掌之上的时候,那个小小的改动才得以进行。并不是每个作维护的程序员都这么幸运,毕竟大多数程序的开发都是有时间限制的。我把这种问题称为时间问题,就是说如果我们拥有足够的时间问题就能得到解决。

 

我们写的程序难吗?

       我写的程序都不难,我很少接触到难的程序。对于要求的功能我们总是有各种各样的解决途径和办法。对于计算机的数据结构和各种算法,你周围的同事很可能就是精于此道的高手。各种行业规则和行业算法你也不必过多的担心,客户肯定比我们了解的更加清楚。就像你比客户更加了解计算机和程序一样。甚至我们中的某些程序员已经把程序书写和数据库的增删查改划上了等号。

 

技术问题

       j2ee,struts,jsf,hibernate,ejb,web2......技术总是让人感到眼花缭乱,我们总是在追逐技术的路上奔跑。当跑在你前面的技术人员向你炫耀新技术的种种特性,讲述他们的优越性能时,你一定会觉得不愤。如果你年轻力胜你可能会通过努力超过他,如果你已步入中年疲惫不堪,你也许只能抱怨感叹了。其实我们大可不必这样,文章合时而著,技术合时而用。我们不应该让自己陷入技术的泥潭中。而且能够迅速的掌握方便的使用也必定是一个好技术的必备特征。掌握技术的多少只能说明你从业时间的长短和勤奋的程度。当然这只是从使用技术的角度出发,如果你在发展或者是创新某种技术那就另当别论了。我的个人偏向是,技术使用完后就该尽快的忘记。存储他们的最好地方应该是硬盘或者网络里的文档。一个良好的系统应当只关心他的行为,而不关心其具体的实现。

 

问题源于何处?

       程序简单,技术又不是问题,那么我们的问题源于何处?仁者见仁,智者见智。每个人都会有自己的见解。不过我可以肯定的说,我们现在至少是在程序的分析和设计上出了问题。或者是还不能够出问题,因为我们的分析和设计工作做的是在是太少了。一个商业软件的利润可能百分之六十到七十来自后期的维护和拓展。如果是这样的话上面提到的“时间问题”就显得很重要了,而解决这种时间问题的有效办法就是多做一些分析和设计。

 

对症下药

       需求是最重要的,但是我们不在这里讨论。有的地方人们已经把需求上升到工程的高度,与软件工程相提并论。如果需求发生变动的话,设计,代码必定要发生变动。

       设计。现在的设计主要是面向对象的设计。在我们的系统中一切都是对象。抽象出系统中的对象,抽象出系统的行为,个个模块的行为,包括模块内部的行为和他对外提供的行为。对于每个模块来说,他只要管好自己该作的事情就可以了,其他模块的事情由其他模块去做。系统是面向行为的而不是面向技术的。比如,一个用户身份认证的模块,我们提交给他的是一个用户的对象实例,他需要告诉我们这个用户是不是一个系统中的合法用户。这个用户的信息可能存储在本地数据库的一个表格中,可能是从一个统一认证的系统中获取,也可能是由更为严密的CA系统中获取。但是无论怎样,这个用户认证模块的行为已经确定。其他模块要信任这个模块,把用户认证的工作交给他来完成,而不是自己主观的认为认证的工作是否简单或者复杂而跳过认证模块自己来完成认证的流程。这样一来,每个模块都把自己的工作做好,那么整个系统也就显得井然有序。天下有道,却走马以粪,天下无道,戎马生于郊。这是我在《java与模式》中看到的一句话。是说当天下有道(太平)的时候,好的跑马却在田间耕作;当天下无道(不太平)的时候,战马在战场上生出小驹。好的程序设计让我们的程序高手不能发挥作用,不好的设计让个个都是程序高手的项目小组不能按期完成他们的任务。

       什么样的程序是好的程序?书写要清晰明了,每个函数的行数最好不要超过30行(个人标准)。每个类也不要写的太大。程序主要是用来读的,而不是用来炫耀,不要把程序写的太晦涩,要有清楚的注释,如果你不能把注释写的简洁,至少你要把他写清楚。当然你要保证程序是可以正确运行的,他的性能也要满足要求。不能把复杂度是O2的程序写成O3的。写单元测试是好的习惯,他保证建房子的每块砖都是有可靠的。一个公司的程序风格要尽量的保持一致。一个人毕竟不能终生对一个模块负责,后来的维护人员在读你的程序时应当象是在读他自己的程序一样。

       文档。看一部机器要看它的图纸。同样看一个程序要看他的文档。我们现在写的程序规模都比较大。如果一个系统没有准确的文档,而需要逐行的看代码来猜测他的功能的时候,这无疑是对公司的犯罪,员工的时间就是公司的金钱。

 

一个例子

       需求:

记录系统中的各种行为,比如用户登陆,用户检索,用户注册等等。以固定的格式写入日志文件。当达到某种要求的时候将文件传送到日志分析系统。

       设计:

              抽象日志对象       

(图片贴不上来)

              抽象行为:

日志记录

(图片贴不上来)

日志发送

(图片贴不上来)

      

抽象类和接口说明:

配置参数读取器:

              Config.class每个系统都有自己的配置文件,对于自己的配置文件都有相应的读取操作类。日志记录上传模块也需要有自己的配置选项,如果再单独书写一套自己的配置文件和配置文件的读取函数,不但不能有效的复用原有程序,而且增加了系统配置文件的数量,不便于程序的实施和维护。Config仅仅规定了配置读取程序的行为,当这个模块应用于不同的系统中时,该系统的程序员只要对实现一个具体的Config类,这个类实现抽象方法,是对原有程序的包装。原有的程序被动态的加入进来,同时也不破坏现有的程序。

 

记录日志接口:

       Record.class具体的记录方法是会变动的,比如现有的记录规则是,日志文件超过配置的大小后,重新记录一个新的文件。日志文件超过一个配置的时间后也会重新记录一个新的文件。具体的逻辑实现在ConcreteRecord.java类中。如果日后需求变动,就要再重新写一个Record的实现,而程序的其他地方不被影响。Record类又被封装在Log类中,当用户记录日志时,只要调用Log类中的record方法就可以了,而不必关心具体的实现。

 

日志文件过滤接口:

       FileFilter.class我们会根据配置得到一个初始的需要上传的文件列表,但是我们可以根据一定打规则将不需要上传的文件过滤掉。现有的程序支持一个已经上传文件的过滤,和在配置文件中声明的不能上传的文件的配置。具体应用在不同系统中的时候可以再作更改。

 

文件发送接口:

LogFileSender.class规定了文件的发送行为。具体的实现有LocalFileSender.java,将文件拷贝到本机的指定目录;FTPSender.java将文件上传到FTP服务器。

这是这些接口的抽象保证了系统的可变性,让程序真正变得灵活,在后来需求提出修改的时候可以有效快速的更改程序。文章后附带了这个模块的源码,欢迎读者一起讨论。

                                                                                                  张旭 2007-3-5

msn : zx4517@eyou.com

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值