把握行业变革关键节点,12 月 19 日 - 20 日,AICon北京站即将重磅启幕! 了解详情
写点什么

如何提高代码质量

  • 2020-09-14
  • 本文字数:4315 字

    阅读完需:约 14 分钟

如何提高代码质量

说起代码质量,脑子里会冒出很多词,命名规范、格式规范、日志规范、单元测试覆盖率…

但我觉得,代码质量总结起来就两个:好看和好用。

好看是指代码可读性好,容易理解、容易维护,别人接手了不骂你;好用则指代码健壮,不容易出错,机器跑着不骂你。即使出错,也容易定位,容易止损和恢复。

为何需要提高代码质量?

以下是我认为的几点:


  • 提升代码的可维护性,降低新人接手的成本

  • 促进交流,促进知识共享,做好 backup

  • 促进风格一致,降低团队间应用流转的难度

  • 建设写好代码、做好设计的团队氛围


但有一点需要说明,我认为写代码本身是一个创造过程,能让人享受其中,如果有太多的条条框框约束,写代码就失去了创造的乐趣,所以,这里为代码质量建设立一个原则:


  • 只提供建议,不强制遵循

  • 鼓励创造性的编码

  • 鼓励艺术性的编码

如何才能拥有高质量的代码

有两种途径:


  • 第一种途径:先有好的设计—>然后用优秀的编码去实现—>再把优秀的编码风格延续下去

  • 第二种途径:从糟糕的代码开始—>不断去重构,向优秀的设计方案和代码风格不断逼近—>再延续下去

代码质量建设怎么开始呢?

首先得知道什么是好的代码, 这就要有标准,那就是我们常常看到的各种各样的规范,但我觉得要有几个简单的原则,太多了,记不住,有几条原则简单的原则,可以时不时拿来判断,当前做得对不对。


然后就是去实践规范,这里需要一些技巧、一些工具,来帮助我们更好地遵循规范。


接着是度量, 看我们对规范实践的效果,这就是我们常说也常做的 Code Review,但 Code Review 也需要遵循一定的规范,应用一定的技巧。


度量之后是改进, CR 结果要及时跟进,这是最重要一环,否则 CR 就没有实际意义。


总结不可少,复盘是一种很有用的工具,CR 也需要复盘,总结 CR 流程、过程等方面好的和不好的地方,更新规范和 checklist。


接下来我们分别聊一聊各个步骤。

规范: 先知道什么是好代码

从上边高质量代码的诞生途径我们可以看出,设计也是很重要的一环,所以我们的规范包括设计规范和编码规范,结合我们的生产实际,这里加上安全生产的规范,所以规范有 3 部分:设计、编码、安全生产。

设计: 先有优秀的方案

设计推荐多用图表达,图比文字有更直观的传达能力:


首先是业务流程图, 它能快速构建起我们对业务的认知,带着对业务的理解再来看代码,事半功倍。


然后是用例图, 清晰地表达出我们系统的职责、边界、服务对象,结合业务流程图,能快速构建起我们对系统职责的认知。


接着是架构图, 从我们日常的设计需求来看,架构图是需要的。好的架构图能快速给人搭建起理解的框架,再来看系统的细节部分,就很好理解。架构图推荐 C4 规范,它是我目前接触的表达最清晰的架构图规范。


接着再用时序图、状态图、ER 图 等把关键和复杂部分的设计表达出来。


但日常我们的需求有大有小,方案也不需要都遵循统一的范本,为了设计而设计,就徒增加工作量了。以按需为第一原则,能把要做啥,怎么做的表达清楚即可。这里按场景推荐各个图的使用场景:


新建应用/对原有应用进行重大修改/复杂项目


  • 业务流程图(交代业务背景)

  • C4 的系统上下文、容器、组件这 3 张图

  • 用例图:有多个外部参与者

  • 类图:关键模型超过 5 个

  • 状态图:对象状态超过 3 个

  • 时序图:关键流程或复杂链路的参与对象超过 3 个

  • ER 图:涉及数据库变更(包含数据表结构文档)


一般项目/重大日常


  • 业务流程图

  • 时序图(复杂功能、关键流程)


日常


  • 按需

编码: 优秀的方案需要优秀的编码

编码最重要的是可读,控制复杂度,做到自解释,能让人像读自然语言一样读自己的代码,这是最高境界,也是神仙境界。然后是可维护性和可变更性,能快速、安全地修改代码是目标。最后是对优雅实现的要求,卓越的代码会让人拍着大腿叫好,这个不稀奇,我们乱糟糟的代码里也偶尔会有闪光的片段。


编码最高原则:


可读性


  • 控制复杂度

  • self-document


可维护性


优雅

✎ 分层规范

合理的代码分层,能控制各层的复杂度,以分层的思路去设计,也能提高代码的复用性。对于分层,我认为熟悉的就是好的,能满足工作中的大部分情况就好,这里不谈六边形架构、清晰架构、DODAF 等概念,自己驾驭不了,还不能拿出来吹。我推荐 DDD 最基础的 4 层分层架构,如下:


用户界面/接口层   应用层   领域层 基础设施层
复制代码


这里举个我实际项目中用到的例子:


-- bootstrap    -- BeanConfig-- application    -- pv        -- ChannelPvApplicationService    -- sns-- domain    -- abtest        -- AbtestService    -- address    -- coupon        -- entity            -- Coupon            -- CouponStatus            -- CategoryCouponTemplate    -- category    -- user        -- UserRepository        -- service            -- OneIdService            -- UserService    -- item        -- ItemRepostory    -- live        -- LiveStatus-- infrastructure    -- concurrent        -- ThreadPoolExecutorFactory        -- MonitorableCallerRunsPolicy    -- dal        -- IGraphDal        -- TuringDal        -- DefaultUserRepository    -- dao        -- MybatisItemDao    -- util        -- DateUtil        -- MoneyUtil        -- UriUtil    -- monitor        -- Event        -- Timing        -- TimingAspect        -- TimingEvent        -- Monitors-- view    -- atomicwidget        -- BannerWidget        -- CrazySubsidyWidget        -- FeedItemsWidget        -- NavigateBarWidget        -- LiveWidget    -- page        -- HomeScreenPage        -- CategoryFeedsPage        -- SearchCardPage    -- widget        -- Widget        -- DispatchableWidget        -- Debuggable        -- AbstractWidget        -- AbstractDispatchableWidget        -- WidgetDispatcher        -- WidgetResult        -- WidgetContextIncompatibleException
复制代码


上述项目结构中,因为是导购项目,view 相当于用户界面层,application 是应用层,domain 是领域层,infrastructure 是基础设施层。


再对包的划分说明一下:


  • 领域对象、值对象、DTO、Service 等定义都放在子域的包下,不要有大而全的 entity、service、impl 等包(这里的子域是一个内聚的逻辑概念,对应的是领域设计里的子域,如上例中的 item 在我们的导购里就是商品这个子域)

  • 常量定义尽量跟着相关的类走,作为类的静态字段,不要有大而全的 Constant 类(Switch 相关的除外,但也要按职责尽量拆分开关类)

✎ 代码规范

代码规范就推荐阿里经济体开发规约,很全面,也是阿里同学的基本要求。代码规范就推荐「阿里经济体开发规约」,很全面,也是阿里同学的基本要求,开源版本:阿里巴巴 java 开发手册 https://github.com/alibaba/p3c


结合自己的经验,重点说几点:


命名


  • 命名不用泛称(反例:processData)

  • 尽量用完整的单词描述清楚作用和意图,不要怕字多

  • 对象后缀领域对象不带后缀 DTO:RPC 接口提供的对象以作为 VO:跟前端交互的对象 PO:跟数据库直接交互的对象


日志


  • 所有后台都要有操作日志、数据变更日志

  • 日志要配置异步写盘

  • 线上仅保留 WARN 和 ERROR 级别日志

  • 所有日志都要有 traceId

  • 异常日志要有堆栈、入参、能说清楚是什么错误的信息(可以出统一组件)

  • 打印日志时,禁止直接用 JSON 工具将对象转换成 String


异常


  • 怎么抛:尽量使用非受检异常,提高代码可读性

  • 怎么处理:统一异常用切面处理,或依赖 SpringMvc 的 ControllerAdvice 统一处理

  • 异常 catch 范围尽量小,分清稳定代码和非稳定代码

  • 禁止直接吞掉异常

  • 时刻警惕 NPE,多用 Optional 处理


注释


  • 注释只为了说明为什么这么做,不用来说明是在做什么


面向对象


  • 遵循原则:SRP/OCP/LSP/ISP/DIP

  • 尽量只暴露行为,不暴露数据

  • 慎用继承,优先使用组合方式


其它规范


  • 方法行数保持在一屏之内(30 行以内)

  • 代码提交 commit message 一定要讲清楚做了啥控制每次提交的代码量(一个功能一提交)

  • 参数尽量用不可变对象(不对入参做修改,保持明确的入参和出参)尽量不用隐式入参(ThreadLocal)

  • 数据结构无随机读取时,用 LinkedList 替代 ArrayList

  • 风格做好分层,同层用统一的风格(设计/编码)

安全生产

安全生产还没有系统总结过,结合自己做稳定性的工作经验提几点,后边跟负责安全生产的同学多学习学习,再来更新:


防资损


  • 要有资损评估/监控


易恢复


  • 任何新功能上线都要有灰度能力


监控/报警


  • 兜底设计/监控

  • 性能监控

  • 异常监控

  • 低容忍错误要报警

  • 关键指标要监控(业务/技术)

  • 减少不必要的报警


降级/限流


  • 识别出弱依赖,保证弱依赖可降级

  • 识别出可限流的依赖方,做好监控和限流配置

实践: 如何去实践规范+

给一些原则和技巧建议,帮忙落地规范。

设计

  • 图都不是必须的,只要能讲明白是怎么做的,为什么这么做

编码

  • 使用 Aone-Idea,它已经集成了 PMD/FindBugs/CheckStyle 功能,给开发的同学点个暂,超牛逼。开源版本:Alibaba Java Coding Guidelines alibaba https://plugins.jetbrains.com/plugin/10046-alibaba-java-coding-guidelines

  • 使用 lombok,保持代码的简洁性

  • 不断重构,且遵循以下原则: DRY/YAGNI/Rule Of Three/KISS/POLA 每次需求都是重构契机反问自己,能不能在[可读性/易维护性]做得更好

  • 使代码读起来像自然语言

  • 功能性代码和非功能性代码分离

安全生产

这得跟着公司和部门规范来,学习学习再来补充。

度量: 如何去验证实践效果-CodeReview

Review 时机


  • 项目提测后第一时间:不要在项目上线的前夜 review,来不及改,review 结果容易搁置,浪费参与人的青春


Review 方式


  • 小模块:随时/Aone 代码评审/@backup 同学

  • 项目代码:面对面投屏/Aone 代码评审 + IDE show/项目组+重点关注同学


Review 内容


  • 关注代码的设计是如何落地需求的

  • 总体流程

  • 关键设计

  • 重点功能


Review 前提


  • 代码是编译通过的

  • 开启 Aone-Idea 的实时检测


Checklist


  • 规范性


可读性


可维护性(高内聚低耦合、面向对象原则、实现复杂性等)


可变更性(扩展性等)


  • 安全性/健壮性输入检查异常处理边界检查

  • 性能依赖合理性

改进: 跟踪 CodeReview 结果的执行

  • 有运行时风险的问题必须上线前完成改动

  • 其它问题尽量上线前完成修改,如未修改则要加 todo,指定人和时间来修改

  • 用工具来统计和提示 CR 结果改进情况

总结优化

  • 定期回顾和总结(周会环节)

  • 更新 checklist 和代码规范

  • 发现好的代码和设计,定期展示,给与奖励

后话

以上是摘取的各家之言,加上自己的一些思考。学习是个渐进过程,代码质量的学习我还在进行中,如果有收获,会来更新。如果被人 diss,我还觉得有理,我也会更新进来。


写的这些也是我自己的学习和实践方向,所以,如果发现我的代码没做到这些,吐槽我,然后给我建议,让我做得更好。


本文转载自公众号淘系技术(ID:AlibabaMTT)。


原文链接


如何提高代码质量


2020-09-14 14:068228

评论 3 条评论

发布
用户头像
“打印日志时,禁止直接用 JSON 工具将对象转换成 String” 请问下,这个是基于什么考虑呢?
2020-09-22 10:12
回复
1年半的文章,不知道你是否已经知道了答案,我从自己的角度简单回答下哈。
我们知道JSON转化是要消耗性能的,在高并发的场景下,这会是一个巨大的瓶颈。在日志调用传递参数时,一般这样写logger.debug("error info = {}", JSON.toJsonString(XXX))。此时没有判断相关日志的级别是否开启(比如logger.isDebugEnabled()),那么每次调用该语句都会先执行JSON转化,然后才进入日志处理。而线上是不开启debug日志的,也就是说JSON转化没有意义。如果该语句在大量调用的路径上,你会发现CPU在没有该语句和有该语句的情况下存在巨大差异(请求量足够大时)。
2022-04-24 11:21
回复
用户头像
”第二种途径:从糟糕的代码开始—> 不断去重构,向优秀的设计方案和代码风格不断逼近—> 再延续下去“, 大多数情况是第二种途径
2020-09-15 10:28
回复
没有更多了
发现更多内容

如何在C#或VB.NET程序中为幻灯片添加或删除批注

Geek_249eec

C# PPT VB.NET

如何提升研发效能?我们先从指标谈起

Kyligence

数据分析 指标管理

报名倒计时1天!平头哥、中科院软件所PLCT实验室等技术专家解读最新RISC-V技术

OpenAnolis小助手

报名 risc-v 云栖大会 Workshop 龙蜥峰会

vue3 name 属性的使用技巧

new_cheng

Vue 前端 Vue3 VUE 3.0 源码

36氪|元年科技发布新版数字化PaaS平台,更新多个组件

元年技术洞察

方舟 PaaS 中台战略 企业数字化

要努力,但也别焦虑

源字节1号

程序人生

软件要想做的好,测试必定少不了

华为云开发者联盟

测试 开发 华为云 企业号十月 PK 榜

京东云开发者|京东云RDS数据迁移常见场景攻略

京东科技开发者

MySQL 数据同步 数据迁移 云迁移 数据订阅

从清华大学到苏州经贸,双一流和普通高校都在使用的数据科学教学实训平台

ModelWhale

大数据 人才培养 数据竞赛 实训 教学

软件测试丨接口测试该怎么做?持证上岗的Charles,可以帮你做什么?

测试人

软件测试 接口测试 charles 测试开发

String源码分析(二)

知识浅谈

String类 10月月更

华为数通HCIA小型拓扑综合实验,运用OSPF动态路由协议、ACL访问控制列表,交换机生成树协议,修改交换机根桥、交换机划分vlan、链路聚合等相关数通技术、NAT地址转换以及NAT网络地址转换的配置

Python-派大星

10月月更

推广TrustAI可信分析:通过提升数据质量来增强在ERNIE模型下性能

汀丶人工智能

nlp

27位技术实战派负责人齐聚 深聊降本增效 你一定不想错过!

阿里技术

云计算 云原生 云栖大会 降本增效

2022最新CSS高频面试题指南

CoderBin

CSS 前端 面试题 秋招 10月月更

阿里云云边一体容器架构创新论文被云计算顶会 ACM SoCC 录用

阿里巴巴云原生

阿里云 云原生 容器服务

FlyFish一周年,社区大咖邀你共话开源!

云智慧AIOps社区

低代码 可视化 数据可视化 大屏可视化 无代码

订单中心架构设计与实践

小小怪下士

Java 程序员 系统架构 架构设计

JUC 浅析(三)

Andy

从“汽车制造”生活案例到软件的建造者模式

宇宙之一粟

设计模式 建造者模式 Go 语言 10月月更

AR人体姿态识别,实现无边界的人机交互

HarmonyOS SDK

AR

NAT基础:NAT技术原理,静态NAT、动态NAT、NAPT、Easy IP、NAT Server的原理,以及各NAT的配置方法和转换示例。

Python-派大星

10月月更

教你处理数仓慢SQL常见定位问题

华为云开发者联盟

数据库 后端 华为云 企业号十月 PK 榜

手把手教你从安装CentOS7.4镜像开始,搭建IoT视频监控系统

华为云开发者联盟

后端 开发 华为云 企业号十月 PK 榜

Spark on k8s在阿里云EMR的优化实践

阿里云大数据AI技术

大数据 spark 企业号十月PK榜

数字化时代,企业如何创新自己的客户服务

Baklib

“程”风破浪的开发者|学习中的境界

林冲

学习方法 “程”风破浪的开发者

专访韩向东|元年科技:专业与技术并重,赋能财务数字化转型

元年技术洞察

数字化转型 财务数字化

ACL访问控制列表 基础、创建ACL访问控制列表的两种方式、配置ACL访问控制列表规则、修改ACL规则的默认步长。子网掩码、反掩码、通配符掩码的区别和作用。

Python-派大星

10月月更

对话创始人:团队研发效能应该如何管理和度量?

LigaAI

团队管理 敏捷开发 研发管理 研发效能 企业号十月PK榜

JUC 浅析(四)

Andy

如何提高代码质量_安全_朱天富(海培)_InfoQ精选文章