写点什么

如何提高代码质量

  • 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:067317

评论 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
回复
没有更多了
发现更多内容

东方大唐正式加入openGauss社区

软件测试 | 测试开发 | 接口抓包分析与Mock实战

测吧(北京)科技有限公司

测试

从启动到关闭 | SeaTunnel2.1.1源码解析

Apache SeaTunnel

软件测试 | 测试开发 | 搞清楚这六个能力模型,轻松应对互联网裁员潮

测吧(北京)科技有限公司

测试

Log4j2远程执行代码漏洞如何攻击? 又如何修复

琦彦

log4j2 Log4j2 漏洞 10月月更

实现企业内部知识流通?搭建企业内部Wiki

Baklib

9个 方法预防租赁LED显示屏舞台隐患

Dylan

LED显示屏 户外LED显示屏 led显示屏厂家

软件测试 | 测试开发 | 一步一步学测试平台开发-Vue restful请求

测吧(北京)科技有限公司

测试

软件测试 | 测试开发 | Frida 实现 Hook 功能的强大能力

测吧(北京)科技有限公司

测试

ElasticSearch 不停服升级实践

移动云大数据

elasticsearch

Java 8的新特性

琦彦

java8 10月月更

挑选文档协作工具的技巧

Baklib

Qualcomm Atheros wallys QCA9880 Dual Band 2.4GHz 5GHz 2x2 MIMO 802.11ac Mini PCIE WiFi Module//QCA9882 3x3 FCC/CE/IC

wallys-wifi6

QCA9880 QCA9882

喜报!霍格沃兹第二届火焰杯软件测试高校选拔赛荣获大奖

测吧(北京)科技有限公司

测试

火山引擎在行为分析场景下的ClickHouse JOIN优化

字节跳动数据平台

数据库 数据分析 OLAP Clickhouse 数据研发

图尔兹正式加入openGauss社区

太神了!阿里p7大佬总结的Java面试心得,起始—进阶—突击,一应俱全!

Geek_0c76c3

Java 数据库 开源 程序员 架构

软件测试 | 测试开发 | 测试平台开发-前端开发之数据展示与分析

测吧(北京)科技有限公司

测试

JVM——内存泄漏与内存溢出

琦彦

JVM 内存泄漏 内存溢出 10月月更

微服务的设计模式,你用了几个

琦彦

微服务架构 设计模式 10月月更

openGauss企业级开源数据库获第十届中国电子信息博览会金奖

企业知识分享|如何设计产品手册/产品说明书?

Baklib

易宝正式加入openGauss社区

软件测试 | 测试开发 | 静态扫描体系集成

测吧(北京)科技有限公司

测试

技术分享 | 实战演练

测吧(北京)科技有限公司

测试

毕业后什么都不会,找了个培训班学软件测试学了4个月,拿到offer,坐等入职

测吧(北京)科技有限公司

测试

新零售SaaS架构:中央库存系统架构设计

AI架构师汤师爷

SaaS 架构设计 新零售 库存系统

软件测试 | 测试开发 | Jenkins通过什么方式报警?

测吧(北京)科技有限公司

测试

秋招收到10几个offer 说说我的想法吧

Geek_0c76c3

Java 数据库 开源 程序员 开发

软件测试 | 测试开发 | 做到这几点,你也能成为 BAT 的抢手人!

测吧(北京)科技有限公司

测试

CUDA入门教程;Transformer太火不是好事?;探求GPU极限性能的利器|AI系统前沿动态

OneFlow

人工智能 前沿动态

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