烂代码长什么样?
最近看别人写的代码看得头疼,写这篇不仅是总结同时也告诫自己不要写出烂代码祸害别人。看不懂别人的代码是什么感觉?就好像走进一片森林里迷了路,这时候你是不是想把写代码的人抓过...
最近看别人写的代码看得头疼,写这篇不仅是总结同时也告诫自己不要写出烂代码祸害别人。看不懂别人的代码是什么感觉?就好像走进一片森林里迷了路,这时候你是不是想把写代码的人抓过来骂一顿?下面就总结几条最让人受不了的。
标志位以及全局变量太多
标志位看似用起来很方便,是为了表达一种状态,然而一旦起了就要去维护,什么时候清零?什么时候置 1?什么时候初始化?当所表达的这件事情不简单,比如跟另一件事情有牵扯,标志位就不好用了,会有很多地方需要把他清零或置 1,一旦有个地方忘了程序就会出错。标志位一两个还好,多了别人看得头昏,能避免就避免,实在避免不了怎么办?等一下再写,过一会就发现其实不用也可以。
全局变量(这里指的是 int 型或 char 型等基本类型的变量)跟标志位同理,太多只会引起头昏,用之前应该明确这个变量的作用范围,如果作用范围只是在一个函数里面,那么就没必要起在外面,直接在本函数起一个“static”类型的就可以了,也许有时候起的时候并没有发现这个变量可以在函数里写成 static,代码写完后多看看就发现了。同理作用在本文件的那就在本文件里定义成 static。
比单个文件中全局变量更可怕的是一个变量跨越几个文件使用,一不注意看花眼,心累不心累?如果一个变量确实会在几个模块里被读和写怎么办?可以在一个模块定义成 static,然后通过读和写的接口函数来实现读写就好了。
在笔者看来,全局变量这种东西能不用就不用,一般涉及相同业务的变量一起组成一个结构体在结构体里面定义,单独起一个全局的结构体就够了,而不是这里一个那里一个单独的变量散落在文件的各个地方。
比如当某件事情发生时 A 模块会去写某个变量,让 B 模块来读,此时定一个标志位以及变量,当 B 模块发现标志位置 1 了就去读变量,这种做法就不太好。AB 模块完全可以通过消息队列来通信,A 模块只需要把变量值通过发特定消息带给 B 模块就好了,这样就实现了 B 模块在事件发生时得到了这个变量。
逻辑不够简单
逻辑复杂一方面可能是产品的功能本来就设计的复杂;一方面可能是写程序的时候思路不清晰,实现方法不够简洁,代码一团糟自己把自己作死的。如果这两方面都占了,那差不多到了要吐血的边缘了。
如果功能逻辑复杂该怎么办?代码该怎么写就应该好好规划,先想清楚别急着写。
拿我们的产品举个例子,智能家庭网关子设备绑定入网流程就比较复杂,首先手机 App 在局域网内搜索子设备,网关收到搜索消息,去开启 ZigBee 子设备入网流程,入网成功后子设备开始登陆到服务器流程,这个过程中手机持续发搜索消息,网关持续回复搜索消息告知子设备基本信息以及连网处于哪一阶段(比如与网关连接中、登陆服务器中)直到子设备登陆服务器成功,获得了登陆 ID 号,手机向服务器申请绑定该子设备,整个流程结束。
体现到代码上,整个过程中涉及到三个线程,局域网线程、广域网线程、ZigBee 线程。其中,ZigBee 线程需要同时与局域网、广域网线程通信,广域网线程可能需要与局域网线程通信,这关系简直太复杂了。你无法想象原来代码靠一堆的 flag 和变量就把这功能做完了,你需要捋好多遍才搞清楚,那些名字相似的变量们都是些什么作用。
具体怎么做暂且不谈,反正让我做是不会做成这样的,可以利用操作系统的消息队列、回调函数、信号量等等让线程间通信变得简单些,操作系统就是为了让我们更简洁地编码啊!
函数设计不合理
一个函数功能不单一
这是很容易会犯的错误,有时候某个函数被设计成完成一种功能,但随着产品功能迭代升级,发现程序执行到这有了另外一种情况这个函数处理不了了,于是不得不在原来函数里面又补上一段。
这样就造成了这个函数有好几个功能:正常情况时就是原来功能,新的情况时,又是另外一种功能。从函数名看是只有前面这种功能,里面却藏着另一种功能,反正看着有些不爽,如果有时间来改一下,也许可以设计成两个函数,正常情况执行函数 A,新的情况执行函数 B。
功能切分不合理
到底什么功能可以包装成一个函数?会被反复用到的功能,或实现起来代码比较多,放在程序里太长,细节又可以屏蔽的功能。不要几句代码就能实现的功能还要写一个函数,也不要很多不相干的东西全凑在一个函数里,函数又臭又长让人失去了耐心,然后又在某个旮旯里藏着关键性逻辑。
嵌套调用太多层
假如 A 函数调用 B 函数,B 函数里面又调用 C 函数,C 函数里面…….晕不晕?
可读性差
魔鬼数字
比如数组的第 5 个元素减 7,为什么是 5?为什么是 7?让人摸不着头脑,可以把 5 和 7 定义成宏,从宏的名字体现出其意义;
没有注释
这不用多说了吧,关键函数、关键逻辑都应该加上适当注释让后来者好维护;
命名风格不统一
无论是变量、函数还是文件名,都应该能望名知义并保持一样的规则,比如一个模块提供给其他模块的接口函数命名都保持”模块名 _ 功能”这样子,忽然来了个不按这种规则命名的函数,那就比较影响阅读,处女座会受不了的;另外英文的简写尽量用常见的(比如 count 一般缩写成 cnt),而不是冷门的让别人看不懂。
如果你觉得本篇不错,请帮忙转起来吧!
作者简介:绿罗裙,智能家居嵌入式软件工程师,一个程序媛妈妈。
本文为作者投稿,版权归作者所有。
【完】
推荐阅读:
print_r('点个赞吧');
var_dump('点个赞吧');
NSLog(@"点个赞吧!");
System.out.println("点个赞吧!");
console.log("点个赞吧!");
print("点个赞吧!");
printf("点个赞吧!\n");
cout << "点个赞吧!" << endl;
Console.WriteLine("点个赞吧!");
fmt.Println("点个赞吧!");
Response.Write("点个赞吧");
alert(’点个赞吧’)
echo(’点个赞吧’)
点击“阅读原文”,打开 APP 阅读更顺畅!
更多推荐
所有评论(0)