标签 Unittest 下的文章

代码是怎么腐化的

新三年,旧三年,修修补补又三年。
                                                             — 中国俗语。

上面的这句俗语用来形容很多遗留软件系统(legacy software system)的现状是再合适不过了。

今天下午做了一下午的代码评审,对象是一个运行了7年的遗留系统。会上除了几处明显的代码逻辑错误我发言指了出来外,涉及业务流程以及代码设计的问题,我 大多保持沉默。因为我清楚,即便我明确指出问题,可能也得不到修正。也许参与评审代码的其他同事也都知晓这些问题,只是觉得现在还不能去改…。

为何不能去改?回想当年第一版代码出炉时,它是那么的“出淤泥而不染”,而如今它身材臃肿,满身赘肉,千疮百孔,让人无处下手,看起来都不舒服。虽然它依旧能坚持工作,但终会有一天,它会轰然倒地,酿成大错。为何代码会腐化到如此地步?是怎么腐化的?这里谈几点体会。

* 第一版的设计和实现水准

我们知道:设计再完美的系统也终会有腐化的一天,时间才是最可怕的武器,它是一把无情的刻刀,不仅能使人老去,逻辑抽象世界的程序也不能幸免。但是你的程 序设计和实现的越完美,这个衰老和腐化的周期就会越长。一个糟糕的初始设计和实现,只会让系统更早的发霉、腐败直至被替换。我们的这个legecy系统在 最初的代码设计上就给后人留下了许多“糟糕的参照物”,在后人无以伦比的“复制粘贴”的技能下,这些糟糕的设计和实现就像癌细胞一样扩散到系统机体的每个 角落,让你无法重新建立其免疫系统。

* 没有测试做保障,不敢改

系统从诞生的那天起就使用“人肉测试”的方式,而且是粗粒度的系统功能测试。没有白盒的、可重复使用的、自动执行的单元测试集做保障,以致没有人敢对其轻举妄动,一旦出了问题,后果自负。另外人肉测试,精力和成本双重消耗,测试人员“耗”不起啊。

* 缺少崇尚“美”的文化

记得组织第一版企业文化中“美”这个成分还有立足之地的,但后期改版后,我们就再也看不到“美”了。码农们也是一样,在缺少了“俱美”之风的吹拂下,大家 都变得有些“丑陋”了,大家都开始摒弃“美”,认为代码只要能工作即可,美不美不打紧,于是工作就变成了修修补补,系统变得日益臃肿,臭气熏天。

* 进度之忧高悬

很多人会说:“如果给我充足的时间,我会让系统获得新生。但我没有时间,客户那边催的急,只能下次再重构、完善和优化了吧”。从这里不知大家是否看出了:“改善是没有的,下次却是永恒的”这一“道理”。在进度堪忧的情况下,我们多数时候选择了屈服,而不是自己的原则。

* 成本,老板们不得不面对的

“能用即可,新三年,旧三年,修修补补又三年”。如果你和老板谈重构、谈优化,那么这句话就是老板最好的拖词儿。成本永远是悬在老板头上的一把宝剑,老板们不能视而不见。因此,如果你要和老板谈重写遗留系统,那得需要多么强大的魄力和坚定的意志啊。

* 拷贝粘贴,最好的伙伴 or 最大的敌人

相信发明复制、粘贴以及剪切板的那位仁兄无论如何也没有想到,自己送给世界的礼物,竟然被码农们操练的如此熟练,应用在各种场合,尤其是Coding中。代码中充斥着大量重复代码信息,都是拷贝、复制和粘贴的结果,于是乎代码腐败的最大敌人就此出现了。

牢记:“千里大堤,溃于蝼蚁”。下一步该怎么办?去闻闻,你的代码腐化了没有!

lcut 0.3.0版本发布

lcut单元测试框架在我的项目中应用已经有一段时间了,项目组的同事对lcut的使用也是越来越熟悉,这不今天一位同事还提出了一个新需求,需求大致是这样的。

 
在实际项目中,经常遇到这类情况:
 
int bar(…) {
    int ret;
 
    ret = foo(…);
    /* assert ret */
    …
 
    ret = foo(…);
    /* assert ret */
    …
 
    ret = foo(…);
    /* assert ret */
    …
}
 
上述代码中被测函数接口bar的实现中多次调用了某函数foo。这样当我们用mock方式测试bar这个函数时,可能需要多次重复设置foo的返回值以及输出函数的值,就像这样:
 
void tc_test_bar_return_ok(lcut_tc_t *tc, void *data) {
    LCUT_RETV_RETURN(foo, 0);
    LCUT_RETV_RETURN(foo, 0);
    LCUT_RETV_RETURN(foo, 0);
 
    LCUT_ARG_RETURN(foo, 1);
    LCUT_ARG_RETURN(foo, 1);
    LCUT_ARG_RETURN(foo, 1);
 
    LCUT_INT_EQUAL(tc, 0, bar(…));
    …
}
 
我的同事希望lcut能提供一个接口:支持一次调用,设置多次mock obj的返回值或输出参数,使用这样的接口后,上述代码就可以简化为:
 
void tc_test_bar_return_ok(lcut_tc_t *tc, void *data) {
    LCUT_RETV_RETURN_COUNT(foo, 0, 3);
    LCUT_ARG_RETURN_COUNT(foo, 1, 3);
 
    LCUT_INT_EQUAL(tc, 0, bar(…));
}
 
这个需求提的非常好,看起来更像是一种语法糖(syntactic sugar),用于简化代码编写。于是乎下午我就为lcut增加了两个有用的宏:LCUT_RETV_RETURN_COUNT和LCUT_ARG_RETURN_COUNT。
 
正如上面所说,这两个宏可在一次调用中多次设置某个mock obj的返回值和输出参数值,两个宏的原型如下:
 
#define LCUT_RETV_RETURN_COUNT(fcname, value, count) do { \
        lcut_mock_obj_return(#fcname, (void*)value, __FUNCTION__, __LINE__, __FILE__, MOCK_RETV, count); \
    } while(0);
 
#define LCUT_ARG_RETURN_COUNT(fcname, value, count) do { \
        lcut_mock_obj_return(#fcname, (void*)value, __FUNCTION__, __LINE__, __FILE__, MOCK_ARG, count); \
    } while(0);
 
只是比之前提供的LCUT_RETV_RETURN和LCUT_ARG_RETURN多了一个宏参数count。count用于指出对mocked obj进行多少次返回值或输出参数的设置。
 
另外当count传入-1时,其语义为无论mocked object被使用多少次,其返回值或输出参数值都是一样的,即使用LCUT_RETV_RETURN_COUNT或LCUT_ARG_RETURN_COUNT时设置的那个值,直到下一次调用这两个宏进行重新设置时,值才会发生变化。例如上面的例子我们也可以改写为:
 
void tc_test_bar_return_ok(lcut_tc_t *tc, void *data) {
    LCUT_RETV_RETURN_COUNT(foo, 0, -1);
    LCUT_ARG_RETURN_COUNT(foo, 1, -1);
 
    LCUT_INT_EQUAL(tc, 0, bar(…));
}
 
这样无论后续再调用多少次bar函数,foo的返回值总是0,输出参数也总是1。
 
增加了这两个宏后,lcut的版本号也小升了一位,最新版本是lcut-0.3.0-rc1,其中还增加了一个针对lcut mock功能的example – mock_test.c。同时Google Code上的lcut guide也做了更新,对新增的宏的用法进行了简要说明。
 
就这样,lcut 0.3.0版本算是发布了,后续还会经过内部的细致测试,如果没有什么问题,就会去掉rc。
如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 AI原生开发工作流实战 Go语言精进之路1 Go语言精进之路2 Go语言第一课 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats