1、为什么需求代码标准

任何系统性的项目都需求架构规划,而架构规划的核心出题是操控复杂度

但随着项意图不断迭代,复杂度就会不断上升,研制效率就会不断下降。

代码规范-对抗软件复杂度

而代码标准正是对立软件复杂度的有用手法,经过约定俗成的规矩,降低复杂度,提高研制效能。

从团队视点来说,一致的代码标准有利于削减阅览本钱和了解本钱,并且能提高代码质量,长期来说,项意图安稳且可保护,也能更好更快速的支撑事务开展。

代码规范-对抗软件复杂度

2、代码是怎么变坏的

2.1、重复的代码

同一个功用,在不同的事务域,大家用同一种技能乃至不同技能都去完成了一遍,放下复用性不说,当咱们要去修正底层的逻辑完成时,上层调用有一个漏改都是极大的风险。

2.2、早期有用的决策不再有用

初期,咱们有能力把一段代码写的简练且逻辑明晰,可是当事务不断迭代,逻辑就变得越来越复杂,当其他同学来接手时,是改仍是不改,改了出问题谁来背锅?这是一个灵魂的拷问,然后一边叹息一边新增自己的代码。。。

2.3、过早的优化

过早的优化是万恶之源,为什么这么说,百万和千万等级日活的架构肯定是不相同的,架构是需求演进的,假如一开始百万等级日活就想奔着千万等级的架构去,不只脱离了实践的事务需求,还浪费许多的人力物力财力,反而得不偿失,从实践动身,适合自己的才是最重要的。

2.4、对合理性没有苛求

技能计划往往都不是单一的,当咱们有「能跑就行」的主意时,就会选择最简略粗犷的计划,可是往往这种计划的复用性和扩展性都很差,当历史的浪潮不断向前推进,就会演变成技能负债,后人一边叹息一边又在屎山上拉了一泡。

2.5、过度规划

调用链路就像老奶奶的裹脚布相同,又臭又长,一层又一层,添加了解本钱,降低开发效率。

2.6、没有规划

没有规划也恰当可怕,一个函数动辄上千行,剪不断理还乱,然后后来者又是一边叹息一边。。。

2.7、排期紧

从前看到这么一个问题,为什么大厂屎山也这么多,高赞的前两个回答是这么说的:

  1. 因为只允许有写一遍就成的时间
  2. 因为能用就行,需求都排不过来

进入一个死循环,屎山越堆越高。。

3、怎么让代码变好

3.1、命名

大到项目名、模块名、包名、对外露出的接口,小到类名、函数名、变量名、参数名,只要是做开发,咱们就逃不过「起名字」这一关。命名的好坏,关于代码的可读性来说非常重要,乃至能够说是起决定性作用的。

3.1.1、命名多长最适宜?

有两种状况,一种命名特别短,关于代码的编写者来说,自己对代码的逻辑很清楚,总感觉用什么样的命名都能够达意,实践上,关于不熟悉你代码的同事来讲,或许就不这么认为了。

另一种,命名很长,觉得命名一定要精确达意,哪怕长一点也不要紧,可是,假如函数、变量的命名很长,那由它们组成的句子就会很长。在代码列长度有限制的状况下,就会常常出现一条句子被分割成两行的状况,这其实会影响代码可读性。

准则上,命名是以能精确达意为目标。多换位考虑,以阅览者的视角去考量命名是否够直观。

3.1.2、命名要可读、可查找

什么是命名可读,指的是不要用一些特别冷僻、难发音的英文单词来命名,更不要随意造词。

虽然咱们并不排挤一些共同的命名方法,但最少得让大部分人看一眼就能知道怎么读。而冷僻、难发音的单词会严重影响交流交流。

其次是可查找,咱们在IDE中编写代码的时分,常常会用「关键词联想」的办法来主动补全和查找。比方,键入某个目标「.get」,希望IDE返回这个目标的所有get最初的办法。

3.1.3、职业标准

还有一些职业通用的标准:

  1. 接口前缀加「I」,表示一个Interface。比方IUserService,对应的完成类命名为UserService;
  2. 弹窗后缀加「Dialog」,表示一个Dialog。比方AppUpdateDialog;
  3. 东西类后缀加「Utils」,表示一个东西类。比方TrackUtils;
  4. 等等;

3.1.4、示例

bad:

fun getName(){}

good:

fun getUserName(){}

3.2、注释

命名很重要,注释跟命名平等重要。

3.2.1、注释应该写什么?

注释的意图就是让代码更容易看懂。只要符合这个要求的内容,你就能够将它写到注释里。

比方,论述代码的逻辑,你为什么这么做,想要到达什么样的效果等等。

3.2.2、注释是不是越多越好?

注释太多和太少都有问题。

太多,有或许意味着代码写得不行可读,需求写许多注释来补充。除此之外,注释太多也会对代码自身的阅览起到干扰。并且,后期的保护本钱也比较高,有时分代码改了,注释忘了同步修正,就会让代码阅览者更加利诱。

当然,假如代码中一行注释都没有,那只能说明这个程序员很懒,咱们要恰当催促一下,让他注意添加一些必要的注释。

3.2.3、注释类别

代码规范-对抗软件复杂度

3.2.4、示例

bad:

    /**
     * 取消
     */
    protected fun cancelJob(job: Job?) {
        if (job != null && job.isActive && !job.isCompleted && !job.isCancelled) {
            job.cancel()
        }
    }

good:

    /**
     * 取消协程 会抛出CancellationException
     * @param job 协程job
     */
    protected fun cancelJob(job: Job?) {
        if (job != null && job.isActive && !job.isCompleted && !job.isCancelled) {
            job.cancel()
        }
    }

3.3、代码风格

3.3.1、函数、类多大才适宜?

函数的代码行数不要超越一屏幕的大小,比方50行。

3.3.2、一行代码多长最适宜?

最好不要超越IDE的显现宽度。当然,也不能太小,否则会导致许多稍微长点的句子被折成两行,也会影响到代码的整齐,不利于阅览。

3.3.3、善用空行分割单元块

关于比较长的函数,为了让逻辑更加明晰,能够运用空行来分割各个代码块。

除此之外,在类的成员变量与函数之间、静态成员变量与一般成员变量之间、各函数之间、乃至各成员变量之间,咱们都能够经过添加空行的方法,让这些不同模块的代码之间,边界更加明确。写代码就类似写文章,长于使用空行,能够让代码的全体结构看起来更加有明晰、有条理。

3.3.4、格式化

运用一致的格式化规矩,比方空格、换行等,格式化规矩不一致,容易引起不必要的改变,不利于代码评定和历史改变查询。

3.3.5、示例

bad:

AlertDialog.Builder(context).setView(0).setTitle(R.string.dialog_title).setMessage(R.string.dialog_message).setIcon(0) .create()

good:

AlertDialog.Builder(context)
            .setView(0)
            .setTitle(R.string.dialog_title)
            .setMessage(R.string.dialog_message)
            .setIcon(0)
            .create()

3.4、编码技巧

3.4.1、把代码分割成更小的单元块

大部分人阅览代码的习气都是,先看全体再看细节。所以,咱们要有模块化和抽象思维,长于将大块的复杂逻辑提炼成类或许函数,屏蔽掉细节,让阅览代码的人不至于迷失在细节中,这样能极大地提高代码的可读性。不过,只要代码逻辑比较复杂的时分,咱们其实才主张提炼类或许函数。毕竟假如提炼出的函数只包括两三行代码,在阅览代码的时分,还得跳过去看一下,这样反倒添加了阅览本钱。

3.4.2、防止函数参数过多

我个人觉得,函数包括3、4个参数的时分仍是能接受的,大于等于5个的时分,咱们就觉得参数有点过多了,会影响到代码的可读性,运用起来也不方便。

一般有2种处理办法:

  1. 考虑函数是否责任单一,是否能经过拆分红多个函数的方法来削减参数。
  2. 将函数的参数封装成目标。

3.4.3、函数规划要责任单一

咱们在前面讲到单一责任准则的时分,针对的是类、模块这样的使用目标。实践上,关于函数的规划来说,更要满意单一责任准则。相关于类和模块,函数的粒度比较小,代码行数少,所以在使用单一责任准则的时分,没有像使用到类或许模块那样不置可否,能多单一就多单一。

整齐的代码只做好一件事,干脆利落,直接了当,易于阅览,易于保护。

3.4.4、移除过深的嵌套层级

代码嵌套层级过深往往是因为if-else、switch-case、for循环过度嵌套导致的。我个人主张,嵌套最好不超越两层,超越两层之后就要考虑一下是否能够削减嵌套。过深的嵌套自身了解起来就比较费力,除此之外,嵌套过深很容易因为代码多次缩进,导致嵌套内部的句子超越一行的长度而折成两行,影响代码的整齐。

针对层级嵌套过深的代码能够运用多态简化逻辑,移除不必要的if或else,也能够运用策略形式,提前return退出嵌套等。

3.4.5、少便是多

无形装逼最为丧命:

  1. 过度规划:有的同学为了炫技,各种规划形式咔咔往上整,反而添加复杂度;
  2. 隐式耦合:这种是想炫技但功力不行的,规划的不行优雅反而留下后遗症;

建筑师米斯.凡德洛曾说过,less is more,发起简略,对立度装饰的规划理念。简略的东西往往带给人们的是更多的享用。

4、客户端的技能栈

上面介绍了一些通用的标准,但是年代在变化,技能在演进,客户端的技能更新也是日新月异,因而也需求针对不同的技能栈有系统性的规约及代码风格。

比方:

  1. Java的文件名遵从驼峰命名法,而在Flutter中文件名运用下划线离隔;
  2. Java和Kotlin、OC和Swift,不只要类型推导上的区别,还有一些语法糖的特性;
  3. 等等;

下面是端上现有的一些技能栈:

语言 标准文档
Android Java Java开发手册(嵩山版)Google Java Style Guide
Android Kotlin Kotlin Coding conventions
iOS Objective-C Coding Guidelines for Cocoa
iOS Swift Swift Style Guide
跨端 Flutter Effective Dart
跨端 动态化xxx(json -> TypeScript Google TypeScript Style Guide
其他 配置文件(xml、yml,json) Google XML Document Format Style Guide
其他 脚本、插件(Python、Shell、Groovy) Shell Style GuidePython Style Guide

google开源规约:google.github.io/styleguide/

5、管理手法

5.1、检测东西

经过一些类似Lint之类的检测东西,在编写阶段经过警告,把不符合标准的代码摧残在摇篮里。

Alibaba Java Coding Guidelines

5.2、代码评定

代码评定也称code review,俗称cr,cr的意义在于,作为局中人,尽管咱们在编写代码的时分小心翼翼,但也或许会在无意间犯下一个小错误,而此刻cr的人作为旁观者,可有一语点醒梦中人的效果,并且从实践问题动身发生思维的碰撞,相互学习,也有利于提高团队全体的编码水平。

5.3、扫码举动

咱们端上正在做一些代码的管理,删去无用代码,下线老代码,比方原有的灰度校验在全量之后理应下线老的逻辑代码。

5.4、代码重构

咱们也正在做模块化的重构管理,把曾经规划不合理或许不满意现状诉求的地方做改善和优化。

6、一点考虑

管理举动咱们能够一年来一次,但这很明显不是最好的解决办法,代码是人写的,东西是辅佐是底线,怎么国泰民安,仍是要从根源上着手下功夫,这就需求咱们团结一致,从思维上认可,从举动上落实,仔细做好code review,一直对代码坚持敬畏,对自己的代码担任,做一个有崇奉有寻求的程序员。

7、相关书籍

  • 人月神话
  • 代码整齐之道
  • 架构整齐之道
  • 编程珠玑
  • 重构改善既有代码的规划
  • 规划形式之美

8、参考文档

  • 腾讯工程师,万字长文说 Code Review
  • 怎么编写废物代码
  • 规划形式之美
  • 对立软件复杂度的战争

本文正在参加「金石计划 . 瓜分6万现金大奖」