Zz 代码的坏味道——你们的项目有这些问题吗?


{技术}代码的坏味道——你们的项目有这些问题吗?
http://groups.google.com/group/pongba/browse_thread/thread/e00177cd62e13ed0?hl=zh-CN

    
missdeer       
查看个人资料  
     更多选项 9月22日, 上午8时07分
发件人:missdeer <missd…@gmail.com>
日期:Mon, 21 Sep 2009 17:07:44 -0700 (PDT)
当地时间:2009年9月22日(星期二) 上午8时07分
主题:{技术}代码的坏味道——你们的项目有这些问题吗?
回复
回复作者 转发 打印 单个帖子 显示原始文件 举报此帖 查找此作者的帖子
  最近一直在学习Martin Fowler的《重构》,并且对照我参与的一个已经投入至少15人年,历时3年,约20万行,目前仍然在继续开发维护
的项目,让我觉得触目惊心,其中的代码,到处充斥着Martin Fowler所谓的坏味道,而又困惑重重,不知道别的项目代码质量是如何的。
  下面就都只是随便举一下项目中的实际情况为例,项目是用MFC开发,使用了Codejock的Xtreme Toolkit Pro界面扩展库。
  重复代码。有3处计算MD5的实现,分别由3个开发人员完成,大概实在是这种实现的代码在网上太容易找到了。另外有一个特性,可以与另一个服务进行
文件的上传、下载、更新、同步,而文件因为类型不同,做这些操作时某些细节有细小的差别,但实现中却是为每一类文件具体而完整都实现了一遍这些操作。
  过长的函数。有的开发人员就是习惯性地写出长函数。整个项目中,圈复杂度超过100的有4个函数,超过20的不知道是几十还是上百个。
  过大的类。有一个类的cpp文件,是18000行,另外有一个类的cpp文件是10000行。还有CMainFrame类的cpp文件,用
Source Insight打开后,在列出函数列表的窗口中显示“Too complex to parse”。
  过长的函数列表。有一个cpp文件中共9个函数实现,每个函数的参数都超过7个,而且含义晦涩,自从原创人员两年前离职后,没人敢去动那块代码。
  发散式变化。前面提到的一个18000行的cpp文件,是一个视图的实现。如果要给该视图的右键菜单中新增加一个菜单项,并进行响应,需要修改不知
多少个函数,记得曾经有个开发人员,花了一周时间都在为了一个新增的菜单项。添加代码没花多少时间,时间花在添加后,因此引发的问题上。
  霰弹式修改。有两个模块都需要一个高亮显示语法关键字的编辑功能。有一个基本的控件封装类,但要修改一些代码时,总是要很小心地去从头检查一遍另一
模块的实现是否受影响。我的理解是,这个控件封装类的抽象不够通用,或者两个模块的相似度并不高。
  基本型别偏执。这样的代码在项目中不好找,不过有类似的。项目中使用MSXML操作xml数据,在各个模块的实现中,都直接聚合了一堆MSXML的
接口指针,操作xml的方法,和业务逻辑、界面响应完全混合在一起。
  Switch结构。很多处又大又长的switch结构。
  冗余累赘类。有两个(派生)类过于考虑以后的扩展性,而那种扩展性的需求至少在未来2、3年内是遇不上的。
  夸夸其谈未来性。有一个快捷键处理模块,从项目刚开始就已经实现完成,但后来一直没被用过。项目没有开始实际编码前,超过5个人,花了2个月制订了
各个模块需要暴露的COM接口,结果到现在3年了,真正实现的接口也才10个左右。
  中间转手人。CMainFrame类已经成了各个模块用来转发消息的场所。一个重要的原因是界面与业务逻辑耦合,很多业务处理需要
MainFrame转发到相应的界面实现类中进行处理。
  狎昵关系。无论是各个Pane还是MDIClient,都与CMainFrame存在着这种双向依赖关系。
  异曲同工的类。两个有交互的模块,居然各自定义了一组数据结构,用来描述现实世界中的同一种事物,中间又由CMainFrame来完成这两组数组结
构之间的转换。
  纯数据的类。很多时候,为了向线程函数传递一些数据(超过一个DWORD的量),就专门定义一个纯数据的类。
  被拒绝的遗赠。两个平行的模块,一个类是从另一个类继承过来的,而明明有很多那被继承的类的功能,在派生类中是不需要的。呃,被继承的就是那个
18000行的类。另外还有那两个需要编辑功能的模块,曾经居然也是一个类从另一个类直接继承,导致在派生类中变成不需要什么功能,就加些代码,把那部
分功能屏蔽掉。
  过多的注释,有一个开发人员,喜欢在自己编写的函数开头部分写上几十行注释,呃,全是算法描述和伪代码。
  在公司4年,我参与过的略有规模的项目,除了这个外,另外有一个,基本是独自一人完成,代码量最高峰是7万行,后来路过不断的重构,在仍然有新特性
增加的前提下,代码量缩减到4万多,现在回头看来,这个项目中代码的坏味道似乎少一些,但质量却也不行,崩溃经常发生,其他业务逻辑有问题的也不少。
  所以,我就很是困惑啊,别人的项目是怎么样的情况?

    回复    回复作者    转发       
Report spam
Reporting spam
Message reported
    为此帖评分:

    
    

        

        
您需要先登录才能发帖。
要发帖子,您需要先加入此论坛。
请先在订阅设置页上更新您的昵称,然后再进行发帖。
您没有发帖的权限。
    

    
    
sagasw       
查看个人资料  
     更多选项 9月22日, 上午8时18分
发件人:sagasw <sag…@gmail.com>
日期:Tue, 22 Sep 2009 08:18:35 +0800
当地时间:2009年9月22日(星期二) 上午8时18分
主题:Re: [TL] {技术}代码的坏味道——你们的项目有这些问题吗?
回复
回复作者 转发 打印 单个帖子 显示原始文件 举报此帖 查找此作者的帖子

都有类似的问题,哪怕是大师,也不是一下子就成为了大师,而是有个渐进的过程。

最重要的一点建议:

如果你觉得应该做,那么就从现在开始一点点的进行重构,看书学习只是开始,最重要的部分是动手。

另外不知道你们这个项目有没有自动测试和单元测试,这些都是开发人员的好帮手,不花费测试组多少时间又能检验修改质量。

2009/9/22 missdeer <missd…@gmail.com>
sagasw       
查看个人资料  
     更多选项 9月22日, 上午8时30分
发件人:sagasw <sag…@gmail.com>
日期:Tue, 22 Sep 2009 08:30:19 +0800
当地时间:2009年9月22日(星期二) 上午8时30分
主题:Re: [TL] {技术}代码的坏味道——你们的项目有这些问题吗?
回复
回复作者 转发 打印 单个帖子 显示原始文件 举报此帖 查找此作者的帖子

对于这种代码我有一些办法也许你可以试试:

1,长函数分解,这种长函数往往是内部有重复代码或者功能很独立的代码,可以抽取或者合并成为一个新函数,小心一点做不会有什么问题。

2,函数参数合并,不需要修改太多,只要新建一个结构就可以,把那些参数都放进去。开始阶段先不要对函数个数、序列进行增减,只要让代码看着整洁就好,也是小心点做不会有什么问题。

3,新旧逻辑对比,某个比较独立的逻辑块可以把接口(不是interface,而是调用的entry)部分分成两块,先调用旧代码,然后调用你修改的代码,然后确保两块代码的返回值、修改值都是一样的,当然这是在这段代码不考虑性能问题的前提下。这是用旧代码检验新代码的一种方法,没有unit
test的时候可以用它。

4,一直使用version control,保证可以时刻回溯代码修改。然后删掉不必要的函数、变量、参数、注释。

5,最为重要的一点,在修改之前应该征得你的team
leader的同意和支持,否则出力不讨好。如果有比较熟悉代码而且愿意做代码重构的老同事,那就更好了,可以跟他们一起动手。
——————————————-
孙秀楠宝宝博客 http://sunxiunan.com
——————————————-



    
    
Tiny fool       
查看个人资料  
     更多选项 9月22日, 上午8时40分
发件人:Tiny fool <tinyf…@gmail.com>
日期:Tue, 22 Sep 2009 08:40:16 +0800
当地时间:2009年9月22日(星期二) 上午8时40分
主题:Re: [TL] {技术}代码的坏味道——你们的项目有这些问题吗?
回复
回复作者 转发 打印 单个帖子 显示原始文件 举报此帖 查找此作者的帖子

像极了我当年去XXX遇到的那个程序,呵呵
这个故事详见:一个具体项目的重构(一)<http://www.tinydust.net/prog/diary/2004/09/blog-post_27.html>
 ,一个具体项目的重构(二) <http://www.tinydust.net/prog/diary/2005/10/blog-post.html>,
一个具体项目的重构(三) <http://www.tinydust.net/prog/diary/2005/10/blog-post_30.html>。

当然我们的重构是把项目重新设计了一遍,而不是一般意义的代码级的重构。因为我们很多工程问题是由于要给略有不同的同类硬件产品设计PC客户端造成的。以前的实现方式是,一个新硬件产品,就从老的PC客户端代码改起,最后有无数的差异不大的PC客户端代码,里面充斥着各种谁也不知道的宏定义。新的实现方式是,把所有产品共有的界面逻辑和数据模型,放在一个exe里面,为每一款新产品设计一个dll插件,升级和新产品的主要工作就是设计和分发新的dll插件。
2009/9/22 missdeer <missd…@gmail.com>

Powered by Jekyll and Theme by solid

本站总访问量