评价代码质量标准(一)

为什么要学习设计模式?

image
1. 应对面试中的设计模式相关问题
在求职面试中,设计模式问题是被问得频率比较高的一类问题。特别是一些像 BAT、TMD 这样的大公司,比较重视候选人的基本功,经常会拿算法、设计模式之类的问题来考察候选人。
平时重视设计模式相关知识的积累,只需要在每次面试前花很短的时间,重新温习一下,便可以自信满满地去面试,而不是心里老是担心被问到,影响正常的面试发挥。

2. 告别写被人吐槽的烂代码
代码能力是一个程序员最基础的能力,是基本功,是展示一个程序员基础素养的最直接的衡量标准。你写的代码,实际上就是你名片。
烂代码,比如命名不规范、类设计不合理、分层不清晰、没有模块化概念、代码结构混乱、高度耦合等等。这样的代码维护起来非常费劲,添加或者修改一个功能,常常会牵一发而动全身,让你无从下手,恨不得将全部的代码删掉重写!

3. 提高复杂代码的设计和开发能力
大部分工程师比较熟悉的都是编程语言、工具、框架这些东西,每天的工作就是在框架里根据业务需求,填充代码。这样的工作并不需要你具备很强的代码设计能力,只要单纯地能理解业务,翻译成代码就可以了。
开发一个跟业务无关的比较通用的功能模块,面对这样稍微复杂的代码设计和开发,需要写出易扩展、易用、易维护的代码;
如何分层、分模块?应该怎么划分类?每个类应该具有哪些属性、方法?怎么设计类之间的交互?该用继承还是组合?该使用接口还是抽象类?怎样做到解耦、高内聚低耦合?该用单例模式还是静态方法?用工厂模式创建对象还是直接 new 出来?如何避免引入设计模式提高扩展性的同时带来的降低可读性问题?……各种问题,一下子挤到了我面前。
了解和积累设计模式相关的知识(包括设计模式、设计原则、面向对象设计思想等),在日常开发中
刻意锻炼、积累这方面的能力。将写出高质量代码当做习惯,提升面对复杂代码、功能、系统的设计和开发的能力,让自己优秀的代码作为同事学习、临摹的范例。

4. 让读源码、学框架事半功倍
对于一个有追求的程序员来说,对技术的积累,既要有广度,也要有深度。在学习框架、中间件的时候,研究研究原理,读一读源码,希望能在深度上有所积累。
从我的经验和同事的反馈来看,有些人看源码的时候,经常会遇到看不懂、看不下去的问题。不知道你有没有遇到过这种情况?实际上,这个问题的原因很简单,那就是你积累的基本功还不够,你的能力还不足以看懂这些代码。为什么我会这么说呢?
优秀的开源项目、框架、中间件,代码量、类的个数都会比较多,类结构、类之间的关系极其复杂,常常调用来调用去。所以,为了保证代码的扩展性、灵活性、可维护性等,代码中会使用到很多设计模式、设计原则或者设计思想
如果你不懂这些设计模式、原则、思想,在看代码的时候,你可能就会琢磨不透作者的设计思路,对于一些很明显的设计思路,你可能要花费很多时间才能参悟。相反,如果你对设计模式、原则、思想非常了解,一眼就能参透作者的设计思路、设计初衷,很快就可以把脑容量释放出来,重点思考其他问题,代码读起来就会变得轻松了。
实际上,除了看不懂、看不下去的问题,还有一个隐藏的问题,你可能自己都发现不了,那就是你自己觉得看懂了,实际上,里面的精髓你并没有 get 到多少!因为优秀的开源项目、框架、中间件,就像一个集各种高精尖技术在一起的战斗机。如果你想剖析它的原理、学习它的技术,而你没有积累深厚的基本功,就算把这台战斗机摆在你面前,你也不能完全参透它的精髓,只是了解个皮毛,看个热闹而已。因此,学好设计模式相关的知识,不仅能让你更轻松地读懂开源项目,还能更深入地参透里面的技术精髓,做到事半功倍。

5. 为你的职场发展做铺垫
普通的、低级别的开发工程师,只需要把框架、开发工具、编程语言用熟练,再做几个项目练练手,基本上就能应付平时的开发工作了。但是,如果你不想一辈子做一个低级的码农,想成长为技术专家、大牛、技术 leader,希望在职场有更高的成就、更好的发展,那就要重视基本功的训练、基础知识的积累。
你去看大牛写的代码,或者优秀的开源项目,代码写得都非常的优美,质量都很高。如果你只是框架用得很溜,架构聊得头头是道,但写出来的代码很烂,让人一眼就能看出很多不合理的、可以改进的地方,那你永远都成不了别人心目中的“技术大牛”。
再者,在技术这条职场道路上,当成长到一定阶段之后,你势必要承担一些指导培养初级员工、新人,以及 code review 的工作。这个时候,如果你自己都对“什么是好的代码?如何写出好的代码?”不了解,那又该如何指导别人,如何让人家信服呢?
还有,如果你是一个技术 leader,负责一个项目整体的开发工作,你就需要为开发进度、开发效率和项目质量负责。你也不希望团队堆砌垃圾代码,让整个项目无法维护,添加、修改一个功能都要费老大劲,最终拉低整个团队的开发效率吧?
除此之外,代码质量低还会导致线上 bug 频发,排查困难。整个团队都陷在成天修改无意义的低级 bug、在烂代码中添补丁的事情中。而一个设计良好、易维护的系统,可以解放我们的时间,让我们做些更加有意义、更能提高自己和团队能力的事情。
最后,当你成为 leader、或者团队中的资深工程师、技术专家之后,你势必要负责一部分团队的招聘工作。这个时候,如果你要考察候选人的设计能力、代码能力,那设计模式相关的问题便是一个很好的考察点。
不过,我也了解到,很多面试官实际上对设计模式也并不是很了解,只能拿一些简单的单例模式、工厂模式来考察候选人,而且所出的题目往往都脱离实践,比如,如何设计一个餐厅系统、停车场系统、售票系统等。这些题目都是网上万年不变的老题目,几乎考察不出候选人的能力。在我的专栏中,有 200 多个真实项目开发中的设计模式相关问题,你跟着看下来,足以让你成为设计模式方面的大牛,再来面试候选人的时候,就不用因为题目老套、脱离实践而尴尬了!

目标:写出高质量代码,提高复杂代码的设计和开发能力

数据结构和算法是教你如何写出高效代码,那设计模式讲的是如何写出可扩展、可读、可维护的高质量代码,所以,它们跟平时的编码会有直接的关系,也会直接影响到你的开发能力
写出“好用”的代码。
设计模式能更直接地提高开发能力。把写高质量代码培养成一种开发习惯,形成一种代码质量意识,把设计原则和设计模式在项目中锻炼运用。
需要用到设计模式的一般是复杂的业务需求;

  • 优秀的开源项目、框架、中间件,代码量、类的个数都会比较多,类结构、类之间的关系极其复杂,为了保证代码的扩展性、灵活性、可维护性等,代码中会使用到很多设计模式、设计原则或者设计思想。
  • 指导培养初级员工、新人,以及 code review 的工作;如果你是一个技术 leader,负责一个项目整体的开发工作,你就需要为开发进度、开发效率和项目质量负责。你也不希望团队堆砌垃圾代码,让整个项目无法维护;代码质量低还会导致线上 bug 频发,排查困难。;考察候选人的设计能力、代码能力,那设计模式相关的问题便是一个很好的考察点。

步骤:

为什么要有这种设计原则、思想或者模式?它能解决什么编程问题?有哪些应用场景?又该如何权衡、恰当地在项目中应用?

  1. 总结本质的定义,解决了什么问题?
  2. 在具体的需求一步步演进过程中,每次演进分析代码缺陷在哪里,如何通过设计原则、思想、模式来优化?(如何进行需求分析、如何落地编码的具体方法论)

代码质量高低也是一个综合各种因素得到的结论。我们并不能通过单一的维度去评价一段代码写的好坏。比如,即使一段代码的可扩展性很好,但可读性很差,那我们也不能说这段代码质量高。
除此之外,不同的评价维度也并不是完全独立的,有些是具有包含关系、重叠关系或者可以互相影响的。比如,代码的可读性好、可扩展性好,就意味着代码的可维护性好

我们真的可以客观地量化一段代码质量的高低吗?
答案是否定的。对一段代码的质量评价,常常有很强的主观性。比如,怎么样的代码才算可读性好,每个人的评判标准都不大一样。
正是因为代码质量评价的主观性,使得这种主观评价的准确度,跟工程师自身经验有极大的关系。越是有经验的工程师,给出的评价也就越准确。需要一个可执行的客观的评价标准作为参考,判断一段代码写得好与坏。

最常用的评价标准有哪几个?

评判代码质量最重要的3个标准:可维护性、可读性、可扩展性;最常用、最重要到几个评判代码质量的标准是:可维护性、可读性、可扩展性、灵活性、简洁性、可复用性、可测试性。

1. 可维护性(maintainability)

落实到编码开发,维护就是修改 bug、修改老的代码、添加新的代码之类的工作。

  • 代码易维护就是在不破坏原有代码设计、不引入新的 bug 的情况下,能够快速地修改或者添加代码
  • 代码不易维护就是修改或者添加代码需要冒着极大的引入新 bug 的风险,并且需要花费很长的时间才能完成。

维护代码的时间远远大于编写代码的时间。
工程师大部分的时间可能都是花在修修 bug、改改老的功能逻辑、添加一些新的功能逻辑之类的工作上。

可维护性也是一个很难量化、偏向对代码整体的评价标准:
代码的可读性好、简洁、可扩展性好,就会使得代码易维护;相反,就会使得代码不易维护。更细化地讲,如果代码分层清晰、模块化好、高内聚低耦合、遵从基于接口而非实现编程的设计原则等等,那就可能意味着代码易维护。
除此之外,代码的易维护性还跟项目代码量的多少、业务的复杂程度、利用到的技术的复杂程度、文档是否全面、团队成员的开发水平等诸多因素有关。
是否易维护本来就是针对维护的人来说的。不同水平的人对于同一份代码的维护能力并不是相同的。对于同样一个系统,熟悉它的资深工程师会觉得代码的可维护性还不错,而一些新人因为不熟悉代码,修改 bug、修改添加代码要花费很长的时间,就有可能会觉得代码的可维护性不那么好。这实际上也印证了我们之前的观点:代码质量的评价有很强的主观性。

比如对接不同电商平台的获取运单、打印、查询物流轨迹等等,通过if else去堆叠代码,代码耦合高,增加一种平台修改整个方法使代码不易维护,我们可以通过策略模式将不同平台的接口封装成不同的策略,再通过工厂模式+单例模式来初始化策略实例和使用具体的策略,可以通过注解+反射来创建实例,这样我们新增一个平台接口只需要增加相应的策略类和加上自定义注解,不需要修改原有的接口,代码的扩展性和维护性就比较好了

2. 可读性(readability)

代码被阅读的次数远远超过被编写和执行的次数,好的程序员能够编写人能够理解的代码。
我们在编写代码的时候,时刻要考虑到代码是否易读、易理解,在修改bug和添加新功能首要的事情就是要读懂代码
代码的可读性在非常大程度上会影响代码的可维护性。毕竟,不管是修改 bug,还是修改添加功能代码,我们首先要做的事情就是读懂代码。代码读不大懂,就很有可能因为考虑不周全,而引入新的 bug。

如何评价一段代码的可读性呢?
我们需要看代码是否符合编码规范、命名是否达意、注释是否详尽、函数是否长短合适、模块划分是否清晰、是否符合高内聚低耦合等等。你应该也能感觉到,从正面上,我们很难给出一个覆盖所有评价指标的列表。这也是我们无法量化可读性的原因。
实际上,code review 是一个很好的测验代码可读性的手段。如果你的同事可以轻松地读懂你写的代码,那说明你的代码可读性很好;如果同事在读你的代码时,有很多疑问,那就说明你的代码可读性有待提高了。

3. 可扩展性(extensibility)

可扩展性表示我们的代码应对未来需求变化的能力。跟可读性一样,代码是否易扩展也很大程度上决定代码是否易维护。
代码的可扩展性是指在不修改或少量修改原有代码的情况下,通过扩展的方式添加新的功能代码。说直白点就是,代码预留了一些功能扩展点,你可以把新功能代码,直接插到扩展点上,而不需要因为要添加一个功能改动大量的原始代码。

4. 灵活性(flexibility)

如果一段代码易扩展、易复用或者易用,我们都可以称这段代码写得比较灵活。所以,灵活这个词的含义非常宽泛,很多场景下都可以使用。

  • 当我们添加一个新的功能代码的时候,原有的代码已经预留好了扩展点,我们不需要修改原有的代码,只要在扩展点上添加新的代码即可。这个时候,我们除了可以说代码易扩展,还可以说代码写得好灵活。
  • 当我们要实现一个功能的时候,发现原有代码中,已经抽象出了很多底层可以复用的模块、类等代码,我们可以拿来直接使用。这个时候,我们除了可以说代码易复用之外,还可以说代码写得好灵活。
  • 当我们使用某组接口的时候,如果这组接口可以应对各种使用场景,满足各种不同的需求,我们除了可以说接口易用之外,还可以说这个接口设计得好灵活或者代码写得好灵活。

5. 简洁性(simplicity)

尽量保持代码简单。代码简单、逻辑清晰,也就意味着易读、易维护。我们在编写代码的时候,往往也会把简单、清晰放到首位。
思从深而行从简,真正的高手能云淡风轻地用最简单的方法解决最复杂的问题。
简洁的代码背后往往是业务理解深度的代码逻辑体现

6. 可复用性(reusability)

尽量减少重复代码的编写,复用已有的代码。
比如,当讲到面向对象特性的时候,我们会讲到
继承、多态存在的目的之一,就是为了提高代码的可复用性;
当讲到设计原则的时候,我们会讲到单一职责原则也跟代码的可复用性相关;
当讲到重构技巧的时候,我们会讲到解耦、高内聚、模块化等都能提高代码的可复用性。
可见,可复用性也是一个非常重要的代码评价标准,是很多设计原则、思想、模式等所要达到的最终效果。

7. 可测试性(testability)

代码的可测试性是一个相对较少被提及,但又非常重要的代码质量评价标准。代码可测试性的好坏,能从侧面上非常准确地反应代码质量的好坏。
代码的可测试性差,比较难写单元测试,那基本上就能说明代码设计得有问题。

如何才能写出高质量的代码?

要写出满足这些评价标准的高质量代码,我们需要掌握一些更加细化、更加能落地的编程方法论,包括面向对象设计思想、设计原则、设计模式、编码规范、重构技巧等。而所有这些编程方法论的最终目的都是为了编写出高质量的代码。

  • 面向对象中的继承、多态能让我们写出可复用的代码;
  • 编码规范能让我们写出可读性好的代码;
  • 设计原则中的单一职责、DRY、基于接口而非实现、里式替换原则等,可以让我们写出可复用、灵活、可读性好、易扩展、易维护的代码;
  • 设计模式可以让我们写出易扩展的代码;
  • 持续重构可以时刻保持代码的可维护性;
posted @ 2023-04-05 09:52  Jimmyhus  阅读(231)  评论(0编辑  收藏  举报