好的代码像诗一样(不是朦胧诗手动狗头)。
那么雷总写的代码究竟如何呢?人邮君为大家找到了雷总1994年写的代码片段。
这段用x86汇编写成的代码(以上是代码片段)用于清除内存驻留程序,类似内存加速工具,雷军教科书般规范的注明了代码用意,时间,作者……还细腻的用符号组成了分隔符让代码更加优雅,读起来清晰、舒适,所以雷总称之为诗一般的代码其实也不算过分。
在B站六月份的一个访谈直播活动中,雷总也在给后辈的寄语中不断强调代码要整洁,逻辑要无懈可击。
因为我们编写的代码,除了用于机器执行产生我们预期的效果以外,更多的时候是给人读的,这个读代码的可能是后来的维护人员,更多时候是一段时间后的作者本人。
人邮君发现许多程序员都遇到过这样的情况:过几周或者几个月之后,再看到自己写的代码,感觉一团糟,不禁怀疑人生。
《代码整洁之道》的作者Bob大叔就提出一种观点:代码质量与其整洁度成正比。优秀的系统往往有优秀的结构设计,层次清晰,职责单一,模块化,方便拓展和复用。功能的添加往往只是在现有的框架中添加少量代码。而且Bob大叔在书中给了我们一些行之有效的规则,涵盖从命名到重构的多个方面,只要遵循这些规则,就能编写出干净的、让人舒服的代码。
就拿函数举例吧。
简化代码的一个简单方式就是不断拆分函数,一直拆分,拆分到不能再分出一个函数为止。拆分后的类和函数更加短小,能使代码可读性更高。
例如下面这段代码,又长又复杂,有大量字符串、怪异且不显见的数据类型和API。花3分钟时间,你能读懂多少?
public static String testableHtml( PageData pageData, boolean includeSuiteSetup ) throws Exception { WikiPage wikiPage = pageData.getWikiPage(); StringBuffer buffer = new StringBuffer(); if (pageData.hasAttribute("Test")) { if (includeSuiteSetup) { WikiPage suiteSetup = PageCrawlerImpl.getInheritedPage( SuiteResponder.SUITE_SETUP_NAME, wikiPage ); if (suiteSetup != null) { WikiPagePath pagePath = suiteSetup.getPageCrawler().getFullPath(suiteSetup); String pagePathName = PathParser.render(pagePath); buffer.append("!include -setup .") .append(pagePathName) .append("
"); } } WikiPage setup = PageCrawlerImpl.getInheritedPage("SetUp", wikiPage); if (setup != null) { WikiPagePath setupPath = wikiPage.getPageCrawler().getFullPath(setup); String setupPathName = PathParser.render(setupPath); buffer.append("!include -setup .") .append(setupPathName) .append("
"); } } buffer.append(pageData.getContent()); if (pageData.hasAttribute("Test")) { WikiPage teardown = PageCrawlerImpl.getInheritedPage("TearDown", wikiPage); if (teardown != null) { WikiPagePath tearDownPath = wikiPage.getPageCrawler().getFullPath(teardown); String tearDownPathName = PathParser.render(tearDownPath); buffer.append("
") .append("!include -teardown .") .append(tearDownPathName) .append("
"); } if (includeSuiteSetup) { WikiPage suiteTeardown = PageCrawlerImpl.getInheritedPage( SuiteResponder.SUITE_TEARDOWN_NAME, wikiPage ); if (suiteTeardown != null) { WikiPagePath pagePath = suiteTeardown.getPageCrawler().getFullPath (suiteTeardown); String pagePathName = PathParser.render(pagePath); buffer.append("!include -teardown .") .append(pagePathName) .append("
"); } } } pageData.setContent(buffer.toString()); return pageData.getHtml(); }
这段长代码有太多不同层级的抽象,有奇怪的字符串和函数调用,混以双重嵌套、用标识来控制的 if 语句等,不一而足。
但是,我们只要做几个简单的方法抽离和重命名操作,加上一点点重构,就能在几行代码之内解决问题。
当然,这段代码还可以再次重构。
怎么样,清爽多了有没有?
所以,if 语句、else语句、while语句等,其中的代码应该只占一行,该行大抵应该是一个函数调用语句,这样不但能保持函数短小,而且,因为块内调用的函数拥有较具有说明性的名称,还可以增加代码的可读性和价值。
同一个函数的每条执行语句应该是同一层级的抽象。函数中混杂不同抽象层级,往往会让人迷惑,无法判断某个表达式是基础概念还是细节。
例如,我们经常会写一个函数需要给某个 DTO 赋值,然后再调用接口,接着返回结果。那么这个函数应该包含三步:DTO 赋值,调用接口,处理结果。如果函数中还包含了 DTO 赋值的具体操作,那么说明此函数的执行语句并不是在同一层次的抽象。
我们想要让代码拥有自顶向下的阅读顺序,想要让每个函数后面都跟着位于下一抽象层级的函数,这样一来,在查看函数列表时,就能循抽象层级向下阅读了。这就是向下规则。
《代码整洁之道》的Bob大叔就给我们了一个思路:程序就像是一系列TO起头的段落,每一段都描述当前抽象层级,并引用位于下一抽象层级的后续TO起头段落。
比如:
1.要获取查询结果,先处理查询参数,然后再判断参数合法性,然后再进行查询。(这是最大的思路步骤)
2.要处理查询参数,要先拿到传过来的参数做一些逻辑处理。 ---->getSearchFileds()
3.要判断参数合法性,要进行一系列业务逻辑的判断,最后返回错误信息,统一处理。 ----> checkParam()
4.要进行查询获取结果,要先把引入model,然后处理组装数据,最后返回。把所有组装细节都放在查询获取里面。 ----> _searchWebGameStatis()
参数越多的函数,调用时越麻烦。尽量保持参数数量足够少,最好是没有。
此外,注释与命名,都是非常重要的。针对这些,Bob大叔还为我们整理了很多准则和技巧,如果你也是和雷总一样有追求的程序员,可以读一读Bob大叔的代码整洁之道系列丛书,能让你的代码更加整洁,工作起来更加得心应手。
人邮君也理解有一部分小伙伴目前没有时间读书,如果没有时间系统性地学习代码整洁相关的知识,也一定要开始注意雷总说的代码逻辑问题,保证代码的逻辑性和严谨性,如果不够严谨或者逻辑有问题,那么总有一天这个bug会被触发。
墨菲定律,在软件开发上总是很有效。
========
赠人玫瑰,手留余香,不要忘记点赞、收藏、关注 @人民邮电出版社 哦~
一键三连,感恩有你~