Chinaunix首页 | 论坛 | 博客
  • 博客访问: 56417
  • 博文数量: 16
  • 博客积分: 691
  • 博客等级: 上士
  • 技术积分: 130
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-07 14:53
文章分类
文章存档

2010年(16)

我的朋友

分类: C/C++

2010-12-05 14:33:29

    转载按:这是我在InfoQ上看到的一个关于代码书写规范的一系列的讨论,文后的评论,有些比较有意思的,我也一并摘抄下来了,大家有什么看法、想法也可以在这里继续讨论。




不知道为什么,初见它时,我想起了郭芙蓉的排山倒海:

ColdRule *newRule = new ColdRule();
newRule->SetOID(oldRule->GetOID());
newRule->SetRegion(oldRule->GetRegion());
newRule->SetRebateRuleID(oldRule->GetRebateRuleID());
newRule->SetBeginCycle(oldRule->GetBeginCycle() + 1);
newRule->SetEndCycle(oldRule->GetEndCycle());
newRule->SetMainAcctAmount(oldRule->GetMainAcctAmount());
newRule->SetGiftAcctAmount(oldRule->GetGiftAcctAmoun t());
newRule->SetValidDays(0);
newRule->SetGiftAcct(oldRule->GetGiftAcct());
rules->Add(newRule);


就在我以为这一片代码就是完成给一个变量设值的时候,突然,在那个不起眼的角落里,这个变量得到了应用:它被加到了rules里面。什么叫峰回路转,这就是。

既然它给了我们这么有趣的体验,必然先杀后快。下面重构了这个函数:

ColdRule* CreateNewRule(ColdRule& oldRule) {
   ColdRule *newRule = new ColdRule();
   newRule->SetOID(oldRule.GetOID());
   newRule->SetRegion(oldRule.GetRegion());
   newRule->SetRebateRuleID(oldRule.GetRebateRuleID());
   newRule->SetBeginCycle(oldRule.GetBeginCycle() + 1);
   newRule->SetEndCycle(oldRule.GetEndCycle());
   newRule->SetMainAcctAmount(oldRule.GetMainAcctAmount());
   newRule->SetGiftAcctAmount(oldRule.GetGiftAcctAmount());
   newRule->SetValidDays(0);
   newRule->SetGiftAcct(oldRule.GetGiftAcct());
   return newRule;
}

rules->Add(CreateNewRule(*oldRule));


把这一堆设值操作提取了出来,整个函数看上去一下子就清爽了。不是因为代码变少了,而是因为代码按照它职责进行了划分:创建的归创建,加入的归加 入。之前的代码之所以让我不安,多重职责是罪魁祸首。一旦把这个函数提取出来,做完这步操作,我们就不难发现这个函数应该成为CodeRule类的一部 分。篇幅所限,就不再继续了。

谈论干净代码时,我们总会说,函数应该只做一件事。函数做的事越多,就会越冗长,也就越难发现不同函数内存在的相似之处。为了一个问题,要在不同的地方改来改去也就难以避免了。但面对长长的函数,还是有人无动于衷,继续往里塞着“新”代码。

即便大家都认同了函数应该只做一件事,但多大的一件事算是一件事呢!不同的人心里有不同的标准。有人甚至认为一个功能就是一件事。于是,代码会越来 越刺激。想写干净代码,就别怕事小。哪怕一个函数只有一行,只要它能完整的表达一件事。在干净代码的世界里,大心脏是不受喜欢的。

接下来,我需要用历经沧桑的口吻告诉你,这么跌宕起伏的代码也只不过是一个更大函数的一个部分。此刻,浮现在我脑海里的是层峦叠嶂的山峰。



以下是原出处的评论(摘抄):

2010年11月30日 下午9时19分 发表人 高 翌翔

作者在文章中提到,即便大家都认同了函数应该只做一件事,但多大的一件事算是一件事呢!不同的人心里有不同的标准。有人甚至认为一个功能就是一件事。

作者的话过于模糊,接下来俺会一句一句话地解释,并推导出一个可指导实践的结论:

1 “函数应该只做一件事”——表明函数是用来做事的。
具体说,函数名表明“做什么事情”,而函数体记录“如何做事情”。

2 “多大的一件事算是一件事呢”——似乎问题在于如何定义“一”,其实不然,问题关键在于“大”字上!
“大”的计量单位是什么?!

至此,焦点集中在“事情”和“计量单位”上?

接下来,先看几个定义:
事情:人类生活中的一切活动和现象。
活动:有一定目的的行动。
现象:事物在发展、变化中所表现出来的外部形态。
(以上定义引自“百度词典”)

在“事情”的定义中,“人类生活”定义了问题域,活动和现象定义了问题的主体。
回到程序的世界里,问题域不仅限于“人类生活”,而是我们所能感知、并可以用代码表示的所有领域,
而活动被一系列方法所取代,现象被用若干属性来记录。

在谈“大”的计量单位之前,先来说下“大事情”,以“大事情”为关键字在 Google 上搜索就会发现,搜索结果形形色色,
从关系国计民生的政策法规,到茶米油盐酱醋茶的生活琐事,均被冠以“大事情”的标题。
可见所谓“大事情”只是人们从不同角度或出于不同目的,认为值得关注的事情。

由此可知,所谓“大”即值得关注,“大”从来就没有任何计量单位。

前两句话可以重新整理为:函数的函数名表明“做什么事情”,而函数体记录“如何做事情”。值得关注的活动和现象就可定义为一件事情。

3 “不同的人心里有不同的标准”——程序想怎么写就怎么写么?当然不是!那么写程序有统一的标准么?当然没有!
虽然没有标准,但还是有规律可循的,不过规律不在代码中,而在代码外!

前面已经讨论过了,函数是用来做事的,而所做的事情又是我们在生活中关注且经常重复的活动和现象。
因此,与其说编程的规律,不如说是事情本身的规律。

那么“事情本身的规律”又是什么?最基本的规律就是“活动的时序性”,即一件事情可以按时间的先后顺序分解为若干步骤来完成。
例如,军训时大家都有学习踢正步的经历,一个正步动作被分解为摆臂、踢腿等若干容易实现的分解动作。
从“学习踢正步”还会发现一个分解的规律,即每个分解动作只关注一个局部动作。

综上所述,事情的基本特性为“时间和空间的可分解性”。因此,方法的分解也须遵循此规律。

仔细分析就会发现,早期的面向过程程序设计只关注“时间可分解性”,随着问题域复杂度不断增加(参与者越来越多),
后来的面向对象程序设计在此基础上增加了对“空间可分解性”的关注,使得我们的编程模型更贴近事情的基本特性。

--------------------------------------------

2010年12月1日 上午7时2分 发表人 Peng Shawn

事实上CreateNewRule方法是好的,但在某些更面向对象的语言里,这个重构并不理想。
我看到很多使用Java的程序也使用类似的重构,
createNewRule 方法的名字取得太草率了,人们不知道为什么你会创建一个新的Rule对象,当看你的代码时,我会问为什么要创建一个新的对象?这个方法名可以更加有意义一 些,我看方法内部的实现,有可能,我不清楚具体的业务,所以我猜测叫nextRule()会更好,假设你使用Java,你可能会把这个方法move到 ColdRule这个类里去,最终的效果是
rule.nextRule();

just my guess~

阅读(981) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-12-07 10:03:45

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com