关于最近重构代码的一些思考
最近一直在参与重构项目中的代码。
之前写的代码最大的问题在于“想到哪里写到哪里”,没有从功能上先整体地进行分析,然后将类似的业务分类到一些,有条理地书写代码。应该来说本来是可以这么去做的, 因为我们花了不少时间去做详细设计。写代码的同事已经对业务的逻辑有了相对完整的理解。但由于不少同事在写代码方面经验还比较少,因此很难做到这一点。所以就想到哪里写到哪里,也比较少审视前后写的代码一起来看是不是结构合理的,本来可以共通进行处理的部分也没有合并到一块。代码中出现大量的重复。这是最明显的一个问题,也是最初级的一种问题。
第二种问题来自于对状态迁移表的理解的僵化。我们几乎所有的模块(除了共通的API层)都是使用状态迁移表的方式来进行设计的。这有很多的好处(找机会另写一篇文章聊),但是并不是说除了状态迁移表之外其它的设计手法(模式)就不能用了,或者说不知道如何把其它手法融合到状态迁移表中去。因此业务逻辑稍微复杂一些的时候状态迁移表就变得巨大无比,而且特别容易出现其中某些格子处理特别复杂,很多格子中的处理又过于简单甚至不需要处理。使得设计文档变得比较难以理解。
第三个问题是不懂得细分。特别是使用C++的模块,本来可以用类/类体系很好地将各种相似的逻辑放在一起去处理。用C++来走C的路。
具体的例子因为涉及到公司的IP,不能贴出来。以后找机会总结一下,换些Dummy的代码来说明。
再说一个关于语言的问题:
对于一个项目来说,业务的逻辑复杂度是本质性的,需求不变的情况下,复杂度是一定的。我们要做的就是让代码实现能尽量地接近业务复杂度,我重构的目标基本上也是这样:把由于拙劣实现而产生的多余的复杂度去除。由于某些限制,我们的项目中有些模块必须使用C来写,有些模块可以用C++写。可能由于自己写程序长期使用C++的原因。在重构C和C++代码的时候,感觉明显不一样。C++在语言上给出了更多功能,因此,我们有更多的手段去让代码更贴合业务,就容易写出更好维护,更容易懂的代码来。比如OO(以及因此发展出来的相应的模式),泛型(将语言数据类型这种在业务描述中并不太关心的东西的影响去除掉)。用C++写明显要“轻松”很多,可以给出的办法也比较多,代码量也要小不少。而C++11/14的进步,使用C++在写业务层的东西的时候变得更加简单的高效(无论是语言层或者标准库)。C++非常适合在嵌入式的领域。C除了在特别靠近硬近的代码的时候没有明显地劣势之外,写业务逻辑时明显要感觉到要为语言的简陋走些弯路,做些妥协。我觉得这个观点的一个更好的例子就是用函数式编程语言写快速排序。代码极其简洁,贴近算法本身,而用OO和过程式的语言就要带入那些与“算法”本身无关的东西进来,这些都会加大编程和维护的负担。当然,对于C++我也有很多不爽的地方,比如模块的语法我觉得很丑,Lambda表达式也是各种语言中比较笨重的一种,编译器还应该能为程序员做更多的事,就像Scala那样。
在我看来,只要有可能,就应该选用更多“选择”的语言(在我的选择中,嵌入式开发中能用C++就用C++,能用C++11/14就用C++11/14)。目标就是如何能实现得更简单更快更好维护。
PS: 这几天的新闻,ARM的新编译工具链是基于LLVM进行构建的。LLVM在C++语言以及各种C++代码处理/分析工具上的支持都很棒。我相信在嵌式开发中,C++11/C++14会很快地得到非常好的支持。只要工程团队技能跟上,那么是可以提高开发效率的。