当前位置:网站首页>How to refactor embedded code?
How to refactor embedded code?
2022-07-25 13:29:00 【Li Xiaoyao】
Focus on 、 Official account of star standard , Straight to the highlights
The article citations :https://www.cnblogs.com/clover-toeic/p/3842758.html
Specific reconstruction methods can be referred to 《 The code of 2》 or 《 restructure : Improve the design of existing code 》, This article no longer teaches others , While focusing on reconstruction, some superficial “ methodology ”, It aims to improve the efficiency of reconfiguration .
The author did not use heavy-duty refactoring tools , Only use Source Insight Of ”Smart Rename” function . Not used either CUnit Wait for unit testing tools , But through online debugging and automated testing to ensure the correctness of the code .
One background
MDU The series of products are taken over from others ,OMCI There are only three or five people related to the module, including the author . In addition to the development of new functions , A lot of time is spent dealing with legacy faults . But the code of this module is complex and poor in readability , As a result, everyone only knows its “ General outline ”, It is difficult to use and maintain with confidence .
Besides , Being busy makes people lose their way . When the main time and energy are spent on troubleshooting , Naturally, there is no time to consider correcting the code , Thus falling into fire fighting everywhere 、 The embarrassing situation of being exhausted .
Two The goal is
The main purpose of refactoring is to improve the design of existing code , Instead of modifying defects 、 New functions .
Refactoring can be modifying variable names 、 Simple physical refactoring like rearranging directories , It can also be a decimation subfunction 、 Simplify the slightly complex logic reconfiguration of redundant design . But it does not change the function of the existing code .
Refactoring can organize spaghetti like messy code into thousand layer cake like neat code . Clean code is more robust , Because it is convenient to establish a perfect test protection network . meanwhile , Novice and old people can safely modify .
Expect after refactoring , Code logic at a glance , It is very convenient to expand and modify , It can quickly locate and repair faults . Where predecessors have fallen, future generations will no longer fall , The achievements of predecessors can be directly borrowed by later generations . All in all , Highly humanized , It greatly liberates human and mental resources .
The initial idea was , By refactoring part of the process and code ( Code first ), Establish a test protection system , Generate phase report , Show code quality ( Instance plus data ) And fault convergence curve . With the help of such reports , It is expected to get the support and publicity of the leadership , It is also conducive to performance appraisal .
3、 ... and practice
In practice , The author did not conduct pure “ restructure ”, Also do defect modification , And add auxiliary functions such as automated testing . In principle, , Focus on refactoring existing code , Pay attention to reuse of new code .
3.1 Code study
OMCI The module code is miscellaneous , Numerous branches , Those difficulties ( It is said that I barely get started in half a year , It takes a year to become proficient ). If you can't master the existing code effectively , It is inevitable to be forced to spend time in the follow-up, healthy and not recognized by the project ( in fact , The remaining faults found in the module are endless ). conversely , If you can fully grasp the existing code , Then it is possible to reverse engineer 、 System / Code recovery and refactoring , Transform the module to be easier to develop and maintain , Finally liberate the coder himself .
To improve the efficiency of code study , The method of division of labor reading and code annotation can be adopted .
“ Division of labor reading ” It refers to dividing the module into several sub functions ( Such as agreement analysis 、 The alarm 、 Statistics 、 On the second floor 、 Voice etc. ), Each person in the group is responsible for one or several pieces , Irregular communication and rotation .
“ code annotation ” It refers to the process of learning code , Comment the code casually ( As big as the process 、 function , As small as lines of code ), function 、 Intention 、 skill 、 defects 、 Questions, etc ( All the places that have been considered can be annotated ). among “ doubt ” You can consult colleagues of the same module of brother products and then convert it to function or intention , It can also be answered by other commentators .
The advantage of this is : Avoid repeated research ; Experience accumulation ; Quantifiable .
The code can take the latest version of the product , Create a server common code directory (SVN Better management ). Do not overwrite others' comments when commenting .
It is suggested that the notes should be in a unified format , Easy to identify and retrieve , Form like ”//>”. An example of a code comment is shown below :
case OMCI_ME_ATTRIBUTE_2: // Operational state
if (attr.attr.ucOperationState != 0 && attr.attr.ucAdminState != 1) //xywang0618> BUG: should be ucOperationState!
{
return OMCI_FUNC_RETURN_OUT_OF_RANGE;
}
break;3.2 Readability
First , Canonical variables 、 Function equinaming . The specific method will not be repeated .
secondly , Notes in place , Especially global variables and general functions . Examples are as follows :
/******************************************************************************
* The name of the function : ByteArray2StrSeq
* Functional specifications : Mask byte array stringing
The array elements are mask bytes , Set all its values to 1 Converts the bit position of to a string in the specified format
* Input parameters : pucByteArray: Mask byte array
ucByteNum : The number of valid bytes to be converted in the mask byte array
ucBaseVal : The value corresponding to the starting byte of the mask string
* Output parameters : pStrSeq : Mask string , With ','、'-' interval
Form like 0xD7(0b'11010111) ---> "0-1,3,5-7"
* return return value : pStr :pStrSeq Pointer backup of , Can be used for strlen Equichained expression
* Usage examples : INT8U aucByteArray[8] = {0xD7, 0x8F, 0xF5, 0x73};
CHAR szSeq[64] = {0};
ByteArray2StrSeq(aucByteArray, 4, 0, szSeq);
----> "0-1,3,5-8,12-19,21,23,25-27,30-31"
memset(szSeq, 0, sizeof(szSeq));
ByteArray2StrSeq(aucByteArray, 4, 1, szSeq);
----> "1-2,4,6-9,13-20,22,24,26-28,31-32"
* matters needing attention : Because this function contains strcat, Therefore, you should initialize on demand before calling pStrSeq
******************************************************************************/
CHAR *ByteArray2StrSeq(INT8U *pucByteArray, INT8U ucByteNum, INT8U ucBaseVal, CHAR *pStrSeq);Last , Rectify obscure code . There are two main means :
1) Rewrite method
With PON Take optical path detection as an example , The unit of optical power provided by the bottom interface is 0.1uW,OMCI agreement Test The unit of optical power reported by the message is 0.002dBuW, and Ani-G The unit of power attribute is 0.002dBmW.
The original code conversion is as follows ( Adapted to highlight the key points ):
INT16S wRxPower = GetRxPowerInDot1uW(); // Received optical power
if(wRxPower < 1){
wRxPower = 1;
}
/*0.1uw to 0.002dbm*/
dblVal = 10 * log10(wRxPower) - 40;
dblVal = dblVal * 500;
wRxPower = (INT16U)dblVal;
wRxPower = (int)wRxPower*100;
/*opt pwr 0.00002db X * 0.00002*/
wRxPower = wRxPower + (30 * 500) * 100;
if(wRxPower < 0){
val = (INT16U)((0 - wRxPower) / 100);
val = (((~val) & 0x7fff) + 1) | 0x8000;
wRxPower = val;
}
else{
wRxPower = wRxPower / 100;
}so , The transformation relationship in the original implementation is very obscure . In fact, with the help of 1dBuW=10*lg(1uW) and 1dBuW-1dBmW=30dB Two formulas , After simple mathematical derivation, we can get a more concise and understandable expression ( Adapted to highlight the key points ):
INT16S wRxPower = GetRxPowerInDot1uW(); // Received optical power
//Test Company 0.002dBuW, Bottom unit 0.1uW, Switch relationships T=(10*lg(B*0.1))/0.002=5000*(lgB-1)
wRxPower = (INT16S)(5000 * (log10((DOUBLE)wRxPower)-1));
//Ani-G Power attribute unit 0.002dBmW,Test Result unit 0.002dBuW
// Switch relationships A(dBmW)*0.002 + 30 = T(dBuW)*0.002, namely A=T-15000
INT16S wAniRxPwr = wRxPower - 15000;Be careful , The original implementation mistakenly believes Ani-G Power properties and Test The unit of the result is the same , The new implementation has fixed this error .
2) Packaging function
Take the mask verification of entity attributes as an example , The original code is as follows :
/* Mask initial verification */
if ((OMCIMETYPE_SET == vpIn->omci_header.ucmsgtype)
|| (OMCIMETYPE_GET == vpIn->omci_header.ucmsgtype))
{
wMask = W(response.omcimsg.auccontent[0],response.omcimsg.auccontent[1]);
usSupportMask = (1 << (OMCI_ATTRIBUTE_NUMBER - map.num))-1;
if( 0 != (wMask & usSupportMask))
{
OmciPrint_warn("[%s] check mask warning: (meclass[%u], meid[%u], msgtype[%u], mask[0x%x], unsupport mask[0x%x])!\n\r",
FUNCTION_NAME, vpIn->omci_header.wmeclass, vpIn->omci_header.wmeid, vpIn->omci_header.ucmsgtype, wMask, usSupportMask);
}
}Yes usSupportMask Assignment and judgment statements ( The first 6~7 That's ok ), Used to verify whether the mask is out of bounds . For more readability , Encapsulate it as the following function :
/******************************************************************************
* The name of the function : OmciIsMaskOutOfLimit
* Functional specifications : Judge whether the entity attribute mask is out of bounds ( The bit 1 The number exceeds the number of attributes )
* Input parameters : INT16U wMeMask : Entity mask
* INT8U ucAttrNum : Number of attributes
* Output parameters : NA
* return return value : BOOL
******************************************************************************/
BOOL OmciIsMaskOutOfLimit(INT16U wMeMask, INT8U ucAttrNum)
{
//wMeMask :mmmm mmmm mmm0 m000
//wInvertMask :0000 0000 000i iiii
INT8U wInvertMask = (1 << (OMCI_ATTR_MAX_NUM-ucAttrNum)) - 1;
return (0 != (wMeMask & wInvertMask));
}The encapsulated function name plays a proper role “ Since the description ” The role of .
3.3 Online commissioning engineering
This product is used as an embedded terminal , Need to be in Linux Compile the packaged version in the system , Then download it to the target board to run . This cross compilation method is suitable for the debugging of a single module , Efficiency is undoubtedly relatively low .
In order to improve the debugging efficiency , stay Linux Server setup online commissioning project . To extract OMCI Module code , After a little transformation, it is compiled and run directly on the server . In this way, you can avoid restarting the board to upgrade the large version every time you modify the code , The debugging efficiency is extremely high .
To make the module run independently , You need to write an analog interface to mask the underlying calls , And cut down unnecessary features ( Such as threads and communication ) etc. .
3.4 Analog database
OMCI The module uses a memory database to manage the entity information that needs to be persisted , However, a large number of platform related interfaces are called in the database code , It is not conducive to the online debugging of the module . therefore , After studying the source code, the author writes a simulated database . The library emulates several original library interfaces and behaviors used by the module , Error information printing is added for internal verification of analog interface , In order to remove obstacles .
Besides , Based on the database interface primitive, the unified interface is encapsulated twice , Eliminate the clutter and duplication of database operation code in the module at one fell swoop .
3.5 automated testing
The reconfiguration of the protection network is not tested , It is no different from surgery without blood source .
First , Public interfaces and functions are provided with corresponding test functions , As examples and use cases . Such as :
//Start of ByteArray2StrSeqTest//
VOID ByteArray2StrSeqTest(VOID)
{
//ByteArray2StrSeq The function algorithm is not very elegant and rigorous , More tests should be carried out to verify , Optimize as much as possible .
INT8U ucTestIndex = 1;
INT8U pucByteArray[] = {0xD7, 0x8F, 0xF5, 0x73, 0xB7, 0xF0, 0x00, 0xE8, 0x2C, 0x3B};
CHAR pStrSeq[50] = {0};
//Time Consumed(x86_gcc3.2.3_glibc2.2.5): 72us
memset(pStrSeq, 0, sizeof(pStrSeq));
ByteArray2StrSeq(pucByteArray, 4, 1, pStrSeq);
printf("[%s]<Test Case %u> Result: %s, pStrSeq = %s!\n", __FUNCTION__, ucTestIndex++,
strcmp(pStrSeq, "1-2,4,6-9,13-20,22,24,26-28,31-32") ? "ERROR" : "OK", pStrSeq);
//Time Consumed(x86_gcc3.2.3_glibc2.2.5): 7us
memset(pStrSeq, 0, sizeof(pStrSeq));
ByteArray2StrSeq(pucByteArray, 4, 0, pStrSeq);
printf("[%s]<Test Case %u> Result: %s, pStrSeq = %s!!!\n", __FUNCTION__, ucTestIndex++,
strcmp(pStrSeq, "0-1,3,5-8,12-19,21,23,25-27,30-31") ? "ERROR" : "OK", pStrSeq);
//Time Consumed(x86_gcc3.2.3_glibc2.2.5): 4us
memset(pStrSeq, 0, sizeof(pStrSeq));
ByteArray2StrSeq(&pucByteArray[4], 2, 1, pStrSeq);
printf("[%s]<Test Case %u> Result: %s, pStrSeq = %s!\n", __FUNCTION__, ucTestIndex++,
strcmp(pStrSeq, "1,3-4,6-12") ? "ERROR" : "OK", pStrSeq);
//Time Consumed(x86_gcc3.2.3_glibc2.2.5): 4us
memset(pStrSeq, 0, sizeof(pStrSeq));
ByteArray2StrSeq(&pucByteArray[6], 2, 1, pStrSeq);
printf("[%s]<Test Case %u> Result: %s, pStrSeq = %s!\n", __FUNCTION__, ucTestIndex++,
strcmp(pStrSeq, "9-11,13") ? "ERROR" : "OK", pStrSeq);
//Time Consumed(x86_gcc3.2.3_glibc2.2.5): 5us
memset(pStrSeq, 0, sizeof(pStrSeq));
ByteArray2StrSeq(&pucByteArray[8], 2, 1, pStrSeq);
printf("[%s]<Test Case %u> Result: %s, pStrSeq = %s!\n", __FUNCTION__, ucTestIndex++,
strcmp(pStrSeq, "3,5-6,11-13,15-16") ? "ERROR" : "OK", pStrSeq);
}
//End of ByteArray2StrSeqTest//Besides , Automatic test function is also added in the module (TestSuite), It can be used to verify the configuration and query operations of batch or single entities . The statistics of batch test results are as follows ( Omit the specific test results of each entity )

In the above test results ,Failed TestCase(s) Most of all , Indicates the number of failed use cases . Besides ,UnCompared TestCase(s) Indicates the number of items not compared , Entities with variable attributes such as acquisition time , Unable to preset appropriate expected results , Therefore, no comparison is made . The printing information during the test can be saved as a log file , Then search in the print log Failure keyword , You can know which configuration failed .
When the current code is heavily modified , With the help of the above automatic test function , You can quickly know the impact of the modified results . When developing new features , You can design test cases and expected results first , And then according to “ Test-driven development ” To encode , Improve coding efficiency and accuracy .
3.6 Go straight to the core
The traditional reconstruction steps are easy first and then difficult , First the periphery, then the core . The author did the opposite , First, refactor the core common code . The advantage of this is :
1) It is convenient to sort out the header file inclusion relationship
At first, only the most public code files are retained in the online debugging project ( Such as log function ), Refactoring and debugging pass, and then gradually add other single function object code . This process will split and / Or combined files , Reduce header file nesting and cross references .
2) Avoid repetitive work or even rework
After public code is refactored and encapsulated , It will be easier to eliminate redundancy when refactoring the application code on the periphery . If you refactor the peripheral code first , It is likely to find that some logic can be unified into common code , This leads to a large area of rework ; And if you start refactoring public code first , By studying the use of peripheral code , It's easy to identify these redundancies early .
3) Iterative verification
When the peripheral code is gradually superimposed on the reconstructed public code , We are also repeatedly testing the correctness and ease of use of public code .
4) Build confidence
Core first, then periphery 、 The process of step-by-step superposition verification is controllable , It can enhance confidence in large-scale reconfiguration , relieve stress . conversely , If you refactor the peripheral code first , When touching the core, pull a hair and move your whole body , There's a lot of pressure .
Four effect
Based on a product code , Conduct OMCI modular DB/LOG/ Entity access / Message processing / Performance statistics and other refactoring . After more than three months of reconstruction , The complexity of module code is greatly reduced ( The average complexity of a core source file is reduced to the original 1/4), The code is significantly streamlined ( According to incomplete statistics, more than 10000 lines have been reduced ), At the same time, it is more readable . In the process of adding code , Write a large number of tool class macros and functions , And increase OMCI automated testing 、 Memory detection and other practical functions .
adopt LineCount and Source Monitor Measure the refactoring effect of a function code , As shown in the following table :

Besides , Common framework accumulated during refactoring 、 Code and experience , It can be further applied to new projects .
Copyright notice : Source network of this paper , Free delivery of knowledge , The copyright belongs to the original author . If involves the work copyright question , Please contact me to delete .
‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧ END ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧
Pay attention to my WeChat official account , reply “ Add group ” Join the technical exchange group according to the rules . Click on “ Read the original ” See more sharing , Welcome to share 、 Collection 、 give the thumbs-up 、 Looking at .边栏推荐
- Based on Baiwen imx6ull_ Pro development board transplants LCD multi touch driver (gt911)
- Convolutional neural network model -- googlenet network structure and code implementation
- 电脑里一辈子都不想删的神仙软件
- VIM basic operation summary
- mujoco+spinningup进行强化学习训练快速入门
- 错误: 找不到或无法加载主类 xxxx
- IM系统-消息流化一些常见问题
- Friends let me see this code
- 0717RHCSA
- Install mujoco and report an error: distutils.errors DistutilsExecError: command ‘gcc‘ failed with exit status 1
猜你喜欢

Friends let me see this code

Convolutional neural network model -- alexnet network structure and code implementation

基于百问网IMX6ULL_PRO开发板移植LCD多点触摸驱动(GT911)

并发编程 — 内存模型 JMM

Excel添加按键运行宏
![[figure attack and Defense] backdoor attacks to graph neural networks (sacmat '21)](/img/d2/6be99fd194c66e4f60af38c6e52c93.png)
[figure attack and Defense] backdoor attacks to graph neural networks (sacmat '21)

Brpc source code analysis (III) -- the mechanism of requesting other servers and writing data to sockets

【AI4Code】《IntelliCode Compose: Code Generation using Transformer》 ESEC/FSE 2020

Connotation and application of industrial Internet

ES6数组去重 new Set()
随机推荐
从输入网址到网页显示
Hcip day 8 notes
Summary of Niuke forum project deployment
Excel add key run macro
Numpy简介和特点(一)
Excel添加按键运行宏
【服务器数据恢复】HP EVA服务器存储RAID信息断电丢失的数据恢复
Gym安装、调用以及注册
Blindly expanding the scale of the meta universe has deviated from the development logic of the meta universe
深度学习的训练、预测过程详解【以LeNet模型和CIFAR10数据集为例】
【CTR】《Towards Universal Sequence Representation Learning for Recommender Systems》 (KDD‘22)
Based on Baiwen imx6ull_ Ap3216 experiment driven by Pro development board
[six articles talk about scalablegnn] around www 2022 best paper PASCA
Leetcode 113. 路径总和 II
6W+字记录实验全过程 | 探索Alluxio经济化数据存储策略
C # basic learning (XXIII)_ Forms and events
【AI4Code】《IntelliCode Compose: Code Generation using Transformer》 ESEC/FSE 2020
【GCN-RS】Towards Representation Alignment and Uniformity in Collaborative Filtering (KDD‘22)
Detailed explanation of the training and prediction process of deep learning [taking lenet model and cifar10 data set as examples]
Design and principle of thread pool
