1。总结最近写了很多代码,review了很多代码,做了很多重构。简而言之,几周来我一直在研究蹩脚的代码。为了抒发这几周内数次达到临界点的情绪,我决定写一篇关于那些关于糟糕代码的事情的文章。这里是第一篇文章,说说坏代码的成因和现象。2.很容易写出糟糕的代码。刚进入程序员行业的时候,经常听到一个观点:你应该专注于ABCD(需求文档/功能设计/架构设计/理解原则),而写代码只是把想法翻译成编程语言而已,这是一个技术含量不高的问题。当时听到这个观点,会有一种近乎冷漠的不屑:你们是一群不明白代码质量重要性的白痴。但是过了几个月,他们好像也没怎么踩坑。而且随着编程技术的不断发展,越来越多的我原以为是傻X的人加入了程序员这个行业。语言越来越高级,包装越来越完善。各种技术正在帮助程序员提高生产代码的效率。靠着层层封装,程序员真的不需要懂一点点技术细节,只要把需求里的内容慢慢翻译就可以了。很多程序员不知道如何组织代码,如何提高运行效率,不知道底层的原理是什么。他们写的在我看来是烂代码。但是那一大堆代码他妈的在工作。虽然我觉得他们写的代码很笨拙,但从不接触代码的人(比如你老板)的角度来看,代码已经编译,测试,在线运行一个月没有任何问题.你还想要什么?因此,即使你不情愿,你也必须承认,在今天编写代码本身并没有那么困难。3.糟糕的代码就是糟糕的代码,但有几次编写糟糕代码的人离开了,事情似乎又发生了变化。当我想修改功能的时候,发现程序里满是看不懂的逻辑。修改后莫名其妙的bug接连出现。接手项目的人开始漫无目的地加班。我开始喜欢跟别人的祖先打招呼了。我总结了几种老祖宗经常用的烂代码:3.1。意思不明确、能力差的程序员往往写出意思不明确的代码。他们不知道自己在做什么。像这样:publicvoidsave(){for(inti=0;i<100;i++){//防止保存失败,重试100次document.save();}}对于这种程序员,我一般建议改事业。3.2.不会说人类语言不会说人类语言是新手最常遇到的问题。直接表现就是自己写了很简单的代码,别人却看不懂。比如下面这段:publicbooleangetUrl(Longid){UserProfileup=us.getUser(ms.get(id).getMessage().aid);if(up==null){returnfalse;}if(up.type==4||((up.id>>2)&1)==1){returnfalse;}if(Util.getUrl(up.description)){returntrue;}else{returnfalse;}}很多程序员喜欢简单things:简单的函数名,简单的变量名,代码中只用了几个单词;能缩写就缩写,能省略就省略,能合并就合并。这类人写的代码里全是g/s/gos/of/mss之类的世界上没人看得懂的缩写,或者一长串不知道自己在干什么的连续调用。也有很多程序员喜欢复杂,各种宏定义,位运算等炒作,生怕别人一下子看懂了代码,会显得自己水平不够。简单来说,他们的代码是写给机器看的,不是给人看的。3.3.组织不当组织不当是高级的坏代码。写了一些代码之后,程序员有了基本的代码风格,但是对更大的项目没有足够的把握,不知道代码应该怎样。分离、分层和组织。这种反模式的现象是,在项目中经常看到一段代码被抄袭、抄袭;一大堆代码放在一个文件里;一个函数有数百或数千行;或者一个简单的函数,他一圈又一圈地调整了几十个函数,在一个很难找到的小角落默默地调用了一些关键逻辑。这类代码大多比较复杂,难以修改,经常一改就崩溃;另一方面,创建这些代码的人倾向于修改代码并且害怕创建代码。他们宁愿把原来复杂的代码一步步做出来,并且不愿意重新组织代码。当你面对一个几千行的类,问你为什么不提取XX的逻辑时,他们会说:“但是,那还要多一个类。”3.4.假设和缺乏抽象与前面相比例如,假设这个反模式出现的频率更高,花样更多,作案者更难自己意识到问题。例如:publicStringloadString(){Filefile=newFile("c:/config.txt");//readsomething}当文件路径改变时,代码会变成这样:publicStringloadString(Stringname){Filefile=newFile(name);//readsomething}当要加载的内容比较丰富时,又会变成这样:publicStringloadString(Stringname){Filefile=newFile(name);//readsomething}publicIntegerloadInt(Stringname){Filefile=newFile(name);//readsomething}以后可能又变成这样:newFile(name);//readsomething}publicStringloadStringFromNet(Stringurl){HttpClient...}publicIntegerloadIntFromNet(Stringurl){HttpClient...}这类程序员往往是项目组开发效率高的人,但是业务量大开发工作引导他们他们的口头禅是:“我每天必须做XX需求”或“先完成需求,然后再考虑其他事情”。这种反模式的后果往往是代码难以重用。当面临deadline时,程序员急于将需求落实到代码中,这往往是一个循环:写代码的时候没有时间考虑重用,代码很难重用,导致需要继续写将来有很多代码。大量的代码一点一点积累,带来了组织和风格一致性等问题,最终形成了新功能基本靠抄袭的遗留系统。3.5.还有吗?坏代码有很多种,沿着功能-性能-可读-可测试-可扩展的路线,你可以看到很多不可思议的例子。那么什么是坏代码呢?个人认为糟糕的代码包括几个层次:如果只是一个人维护的代码,足以满足功能和性能的要求。如果在团队中工作,它必须易于理解和测试,允许其他人修改自己的代码。同时,代码越靠近系统底层,可扩展性越重要。因此,当团队中底层代码难以阅读,耦合上层逻辑,难以测试,或者对使用场景做太多假设,难以复用,虽然功能已经完成,它仍然是相同的代码。3.6.codeenough反之,如果一个项目的代码很难读懂,能说这是烂代码吗?很难定义,可能不是很好,但它很糟糕吗?如果这个项目从头到尾只有一个人维护,而且那个人维护的很好,那么看起来就是“代码够用”了。一开始,很多项目可能只是一个人负责的小项目。大家关心的重点是代码能否顺利实现功能,按时完成项目。过了一段时间,其他人参与的时候,发现代码有问题,看不懂,也不敢动。需求方又催促上线,怎么办?不得不小心只改逻辑不改结构,然后在注释里写这样的实现很丑,理解了内部逻辑后再重构。过了一段时间,我也有类似的需求,想复用里面的逻辑。才发现原来代码针对各种具体场景都有专门的逻辑,复用很麻烦。为了赶进度,只好抄代码改了。问题解决了,问题翻倍了。几乎所有糟糕的代码都是从“足够的代码”演变而来的。代码没变,只是代码的使用场景变了。如果原来的好代码不符合新的场景,那么就变成了坏代码。4、重构不是万能的程序员喜欢跟程序员说的谎言之一是:现在进度比较紧,X个月后项目进度会松一点再重构。不可否认,重构是在某些(极其有限的)场景下解决问题的手段之一,但写了很多代码后发现,重构往往是程序开发过程中最复杂的工作。花费一个月编写的错误代码将需要更长的时间和更高的风险来重构。经历过几次难以忍受的大规模重构。每次重构前,我都找群里的高手,开了无数次分析会,把群里所有的需求都悬起来了才敢开工。嚎叫无处不在,几乎每天都会出现很多意想不到的问题,上线几乎肯定会出好几个问题。从技术上讲,重构复杂代码时,要做三件事:理解旧代码、分解旧代码、构建新代码。然而,要重构的旧代码往往难以理解;模块之间过度耦合会牵一发而动全身,影响范围难以控制;旧代码不易测试,因此无法保证新代码的正确性。这里还有一个核心问题。重构的复杂性与代码的复杂性不是线性相关的。例如,如果有1000行错误代码,重构需要1小时,那么重构5000行错误代码可能需要2或3天。重构一个失控的项目,往往比重写更有效率。不管具体的重构方式是什么,就收益而言,重构也是一件很麻烦的事情:很难带来直接的收益,也很难量化。这里有一个很有趣的现象。基本上,关于重构的书籍无一例外都会有“如何向老板解释重构的必要性”的独立章节。重构后能提高多少效率?可以降低多少风险?很难回答,糟糕的代码本身并不是可以轻易标准化的东西。比如一个项目的代码可读性差,对开发效率的影响有多大?可以说:以前改一个模块需要3天,重构后需要1天。但是遇到“不就是数据库操作吗?为什么要3天”这样的问题怎么处理呢?糟糕的代码由于不确定性而“糟糕”,开发效率因人而异。想要证明这个东西是“真的”,就会给开发时间加两天,往往会变成“我看了三天才明白这个功能”。干什么”或者“这么简单的修改我要3天”,这种命题只有神经病才会证明。另一方面,很多技术leader也意识到了代码质量和重构的必要性,“thenrefactor”,或者说“如果你看到问题,然后重构”。前面的问题已经解决了,但实际上,重构的成本和收益仍然是一团糟。没有给你分配更多的资源,没有明确的目标,和没有具体的方法,很难想象还有谁会为一个洁癖做这种莫名其妙的工作。所以经常会形成这样的情况:不会写代码的人认为应该重构,而重构很简单,而且新人和老人都有责任做重构,老码友认为自己早晚要重构,重构很难,现在好了,不要把这件事压在我头上,写代码的新手都是谢天谢地没有错误,我不知道如何重构。5.很难写出好的代码。与写出糟糕的代码不同,写出好的代码有很多先决条件:了解要开发的功能需求。了解该程序的工作原理。进行合理的抽象。组织复杂的逻辑。正确估计自己的开发效率。不断练习。写出好的代码有很多方法论,但我认为写出好的代码的核心是听起来很low的“持续练习”。这里就不展开了,留到下一篇吧。很多程序员写了几年代码,并没有太大的进步。代码还是烂的让人不忍直视。主要有两个原因:环境是重要因素之一,在坏代码的影响下很难理解什么是好代码,大部分知道的人都会选择跟风。还有个人性格等主观因素,说不清道不明。写出糟糕代码的程序员是容易相处的人。工作几年的人很难说服他们提高代码质量。你只会反复听到:“那有什么用?”或“以前就是这样做的?”那么招聘的时候要从源头着手,提高代码质量如何呢?前段时间面试的时候加了白板编程,最近又加了计算机编程的题目。我发现一个现象:一个人工作几年,做过很多项目,带过一个团队,发表过一些文章,并不一定代表他写的代码好;相反,一个代码写得好的人,其他方面的能力一般,也不算太差。比如最近喜欢用“写一行代码统计工具”作为面试的计算机编程题目。很多人看到题后的第一反应就是这道题太简单了,不就是写代码吗?从实际效果来看,这道题的识别度还不错。首先,题目很简单,像《面试宝典》一样没有读过书的人也不会吃亏。题目的扩展性非常好。即使事先知道题目,也可以根据不同的情况,改成不同的题目。比如需要根据文件类型统计行数,或者为了提高统计效率,或者在统计的同时输出某个词出现的次数等等。从上看,首先是基本的树遍历算法;其次,有一定的代码量,可以体现程序员组织代码和抽象问题的能力;计算机编码可以很容易地判断申请人是否已经很久没有写过程序了;它还包括了解程序的易用性和性能。最重要的是最终的结果是一个完整的程序。我可以根据日常工作的标准来评价程序员的能力,而不是从一个十几行的函数去执着于这个人在日常工作中会有怎样的表现。.但即便如此,也很难有信心说这个人写的代码质量没问题。毕竟面试只是说明他有能力写出好的代码,而不是说他以后会写出好的代码。6、悲观的结论说了这么多,其实只有两个结论。作为程序员:不要指望别人写出高质量的代码,也不要认为自己写的就是高质量的代码
