
在这普通的一天,敲着普通的键盘,然后聊聊普通代码的质量。
我的日常工作,一部分是与Bug做斗争。在这过程中,总有那么些时刻想一劳永逸地干掉它,虽然知道这几乎是不可能,但还是会做各种尝试去减少Bug。这其中一项就是怎样保证代码的质量。
谈到代码质量,自然需要知道什么是好的代码,什么是需要改进的代码,不然何谈代码质量。
那么什么样的代码才算得上是好的代码呢? 我认为,好的代码应该具备下面一些特征:
01
明确的目标
🔘代码需要明确的做一件事情。
🔘与当前目标不一致的需要避免放在代码中。
🔘当目标不明确时,应该停止写代码,待目标明确后再写代码。
02
合理的规划
🔘在目标明确后,我们应该先规划代码而不是立即写代码。
🔘目标需要拆解,然后将拆解后的任务规划到类、方法。
03
足够的“模块化”
🔘代码是一块一块的,相关的功能才应该放在一起。
🔘方法内可以使用「行」人为的做分割,大一点使用方法做分割,再大一点使用类做分割。
🔘从业务逻辑出发,从页面的就近区域出发,从用户的操作流程出发切割功能点进行代码的模块化。
04
明确的初始化和销毁
🔘需要关注框架生命周期相关的初始化和销毁
🔘需要明确的考虑页面从刚进入的无数据状态->数据获取成功状态/数据获取失败状态的渲染情况。
05
清晰的异常处理
🔘无论是同步的try…catch还是异步的callback,都需要明确的给出错误的解决方案。
06
短流程
🔘对于较长流程,需要做流程切割,清晰的划出子流程边界 。
07
明确的参数和返回值
对于暴露出去的方法,我们需要明确的告知调用方参数的范围和意义,告知返回值的范围和意义。
先从目标说起
往往,在写代码的时候容易迷失在一堆的代码中,然后不知南北。如果对这句话有共鸣的,你大体是拿着就开始写代码了,没有明确到所写代码的目的,也没有在写之前做一些代码规划或者设计。这样出来的代码不出问题已算是运气和人品爆棚。
目标明确的重要性,不言而喻,犹如航海中的灯塔。代码的规划会让你先拿出骨架来,避免迷失在一堆的细枝末节中而胡乱的“拼凑”代码。
减法原则
日常的Bug中,少不了因顾此失彼而导致的Bug,我们后面对这类Bug做了回顾和分析,发现大多是代码的模块划分不合理导致。
举一个简单的例子:在一个对象O中有a, b两个状态属性,只有当a, b两属性同时达到某一状态时才能表现出现象P,然而,这种Bug的出现往往是将a,b两个属性的赋值分开放在多个不同的方法中。
那么,代码的模块应该怎样划分才算合理呢?可能不同的人会给出不同的方法论,比如单一职责,比如根据不同的场景使用一些设计模式。但不同的团队有不同的属性,我们需要将其做普适的落地,所以,就有了减法原则。
减法原则简单来说就是删代码,在代码写完后,能快速地,对原有代码影响最小地进行删除。那么说明代码的模块划分算基本达标。
契约与防御
在多人的协作开发中,开发工作像是一场接力赛。从底层的数据获取一棒一棒的传到用户眼前。在这个过程中,稍有不慎就会出现Bug。但事实也的确有这样的Bug,于是乎搬出了"防御式编程"和“契约式编程”
简单来说,防御式编程就是你再为别人提供方法的时候,别人给你的入参是不可相信的,你需要对每一个入参的合法性做校验。
这样的好处是代码特别的皮实,但随之带来的缺点是代码的臃肿和可维护性变差。
契约式编程,与防御式编程不同,在方法里面无需对入参做校验,以契约的形式告知使用方入参的合法范围,使用方在使用该方法时对其参数做合法性校验。
但,契约式编程对团队的要求是非常的高,目前是没办法达到完全使用契约式编程的,所以,我们将二者做了融合。对外的public方法,我们会做防御,同时也会以注释的形式告知。模块内部的私有方法,我们鼓励使用契约。
清晰的异常处理
对于异常,遵循几个规则:
1. 尽早抛出,延迟捕获——发现了处理不了的情况,及时的抛出异常;在可以不处理的情况下绝不做异常的捕获。
2. 异常的捕获不能泛化——当只需要catch一个IllegalArgumentException的时候,绝不能catch一个Exception。
3. 避免catch后不做任何的代码恢复处理。比如只做一个log的输出,如果的确不需要做任何的代码恢复,建议注释清楚原因。
4. 代码恢复不了的异常需要转换到产品层面输出。我们应该遵循异常的抛出和处理都是明确的。同时,我们应该遵循异常从下层到上层是有迹可循的,而不会在中间被吃掉。建议当前代码处理不了的,请向再上一层抛,避免吃掉而又什么都不做。
长流程切割
长流程切割成短的流程,这又是另外一个话题了,有机会可以下次再聊。
对于代码的质量,相信可聊的内容有很多,涉及到的话题也是很广的。在这我只总结了一些工作中常遇到的和可做普适落地的几个小点。
12
往期精彩



