本文参考MDU系列某产品OMCI模块现有代码,提取若干实例以说明目前的代码质量,亦可作为甄别不良代码的参考。
本文旨在就事论事,而非否定前人(没有前人的努力也难有后人的进步)。希望以史为鉴,不破不立,最终产出高质量的代码。
一 质量现状
不考虑业务实现,现有的OMCI模块代码质量不甚理想。无论是理解上手、修改扩展和测试排障,可以用举步维艰形容。尤其是二层通道计算相关代码,堪比令史前动物无法自拔的“焦油坑”。
本节将不考虑流程设计,仅就函数粒度列举目前存在的较为突出的代码质量问题。
1.1 巨型函数
通过Source Monitor度量代码复杂度,如下图所示:
可见,相比业界推荐的5以下,OMCI模块代码复杂度非常之高。
复杂度最高(157)的函数位于Omci_me_layer2_data_path.c二层通道计算文件,选取其中一段函数调用链分析:
→OMCI_Me_Layer2_Calculate_TCI_List(复杂度:67,行数:282)
→OMCI_Me_Layer2_Calculate_TCI_According_VlanRuleList(复杂度:28,行数:182)
该函数对扩展Vlan存在递归调用。
→OMCI_Me_Layer2_Compare_TCI(复杂度:6,行数:38)
该函数位于三级while循环各级内,如下(原循环77行,为突出重点已删除次要细节):
更具震撼性的是,OMCI_Me_Layer2_Compare_TCI调用下面三个巨型函数:
→→OMCI_Me_Layer2_Compare_EthType(复杂度:26,行数:90)
→→OMCI_Me_Layer2_Compare_Vid(复杂度:149,行数:450)
→→OMCI_Me_Layer2_Compare_Pri(复杂度:157,行数:468)
以上仅示出调用链上的关键函数,且调用链自身仅隶属于通道计算的一环。评估其全局复杂度,这样的代码实际上是不可维护的。
此外,当Compare处理耗时超过直接Set时,将严重违背设计本意。
事实上,诸如此类的巨型函数在模块内随处可见。单论函数行数,目前发现的最巨型的函数参见Sub_SNGetMeValueFromAdapter(复杂度:59,行数:538行)。
1.2 设计缺陷
代码中存在较多设计欠佳之处,在此举例若干。
1 /********************************************************************** 2 * 函数名称: Omci_List_Pop_Front 3 * 功能描述: 从链表头部弹出一个节点 4 * 输入参数: OMCI_LIST *pList 链表指针 5 * 输出参数: void *pOutData 链表节点的数据 6 * 返 回 值: 7 ***********************************************************************/ 8 INT32U Omci_List_Pop_Front(OMCI_LIST *pList, void *pNodeData) 9 { 10 OMCI_LIST_NODE *pHeadNode = NULL; 11 12 if (pList == NULL || pNodeData == NULL) 13 { 14 return OMCI_FUNC_RETURN_FAILURE; 15 } 16 17 pHeadNode = pList->pHead; 18 if (NULL != pHeadNode) 19 { 20 if (NULL != pHeadNode->pNodeData) 21 { 22 memcpy(pNodeData, pHeadNode->pNodeData, pList->dwNodeDataSize); 23 } 24 else 25 { 26 return OMCI_FUNC_RETURN_FAILURE; 27 } 28 } 29 else 30 { 31 return OMCI_FUNC_RETURN_FAILURE; 32 } 33 34 Omci_List_Remove(pList, pHeadNode); 35 36 return OMCI_FUNC_RETURN_SUCCESS; 37 }