好的提高代码质量的方法有哪些?有什么经验和技巧?

发表于:2021-6-11 09:45

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:阿里巴巴淘系技术    来源:博客园

  为何需要提高代码质量?
  以下是我认为的几点:
  · 提升代码的可维护性,降低新人接手的成本
  · 促进交流,促进知识共享,做好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
  · 风格做好分层,同层用统一的风格(设计/编码)
  安全生产
  安全生产还没有系统总结过,结合自己做稳定性的工作经验提几点,后边跟负责安全生产的同学多学习学习,再来更新:
  防资损
  要有资损评估/监控
  易恢复
  任何新功能上线都要有灰度能力
  监控/报警
  · 兜底设计/监控
  · 性能监控
  · 异常监控
  · 低容忍错误要报警
  · 关键指标要监控(业务/技术)
  · 减少不必要的报警
  降级/限流
  · 识别出弱依赖,保证弱依赖可降级
  · 识别出可限流的依赖方,做好监控和限流配置

      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号