java优化-代码重,让代码更优美和简洁

news2024/10/5 17:21:26
简言

在项目工作中,经常会有优化,有sql优化,项目架构优化,业务层优化,代码结构优化等,这些优化都是为了系统,易维护,易懂,易扩展。下面是我个人总结的一些经验分享与大家。我觉得每个程序需要成为架构师的必经之路。

以前觉得只需要发费更多时间在业务上,完成功能开发,自测通过,然后测试同学测试完,产品验收没问题就OK。慢慢的发现开始去追求更好,站在更高点去思考问题,慢慢开始成为老鸟了,如何提高代码质量,如何规范下面团队形成某种意识,自发去考虑代码的扩展性,建壮行等等。

1.代码优化是痛苦的

为何这样说呢?

往往代码优化是在以前的业务基础之上去优化别人或者自己代码基础上,提出优化想法,肯定是当前代码的可读性,维护性,设计方向不太友好,需要重新在现有业务上重构代码、或是架构。在优化前需要先去读懂现有代码逻辑,以及以前设计人,或业务发展,结合起来重构代码。

2.如何重构

  • 小型重构
    是对代码的细节进行重构,主要是针对类、函数、变量等代码级别的重构。比如常见的规范命名(针对词不达意的变量再命名),消除超大函数,消除重复代码等。一般这类重构修改的地方比较集中,相对简单,影响比较小、时间较短。所以难度相对要低一些,我们完全可以在日常的随版开发中进行。

  • 大型重构
    是对代码顶层进行重构,包括对系统结构、模块结构、代码结构、类关系的重构。一般采取的手段是进行服务分层、业务模块化、组件化、代码抽象复用等。这类重构可能需要进行原则再定义、模式再定义甚至业务再定义。涉及到的代码调整和修改多,所以影响比较大、耗时较长、带来的风险比较大(项目叫停风险、代码Bug风险、业务漏洞风险)。这就需要我们具备大型项目重构的经验,否则很容易犯错,最后得不偿失。

其实大多数人都是不喜欢重构工作的,就像没有人愿意给别人“擦屁股”一样,主要可能有以下几个方面的担忧:

  • 不知道怎么重构,缺乏重构的经验和方法论,容易在重构中犯错。
  • 很难看到短期收益,如果这些利益是长远的,何必现在就付出这些努力呢?长远看来,说不定当项目收获这些利益时,你已经不负责这块工作了。
  • 重构会破坏现有程序,带来意想不到的Bug,不想去承受这些意料之外的Bug。
  • 重构需要你付出额外的工作,何况可能需要重构的代码并不是你编写的。

3.为何需要重构

程序有两面价值:“今天可以为你做什么” 和 “明天可以为你做什么”。大多数时候,我们都只关注自己今天想要程序做什么。不论是修复错误或是添加特性,都是为了让程序力更强,让它在今天更有价值。但是我为什么还是提倡大家要在合适的时机做代码重构,原因主要有以下几点:

  • 让软件架构始终保持良好的设计。改进我们的软件设计,让软件架构向有利的方向发展,能够始终对外提供稳定的服务、从容的面对各种突发的问题。
  • 增加可维护性,降低维护成本,对团队和个人都是正向的良性循环,让软件更容易理解。无论是后人阅读前人写的代码,还是事后回顾自己的代码,都能够快速了解整个逻辑,明确业务,轻松的对系统进行维护。
  • 提高研发速度、缩短人力成本。大家可能深有体会,一个系统在上线初期,向系统中增加功能时,完成速度非常快,但是如果不注重代码质量,后期向系统中添加一个很小的功能可能就需要花上一周或更长的时间。而代码重构是一种有效的保证代码质量的手段,良好的设计是维护软件开发速度的根本。重构可以帮助你更快速的开发软件,因为它阻止系统腐烂变质,甚至还可以提高设计质量。
    在这里插入图片描述
    在这里插入图片描述

3. 如何重构

小型重构

小型重构大部分都是在日常开发中进行的,一般的参考标准即是我们的开发规范和准则,目的是为了解决代码中的坏味道,我们来看一下常见的坏味道都有哪些?

if-else过多

比例代码:

if(){
	if(){
		if(){
			} else if(){
			}
	} else if(){
	}
} else if(){
}

if else建议不超过三层

for循环层次多,同上 if else 列子
重复代码

项目中有多个地方有计算除余结果值,我们可以考虑通过函数封装起来,统一调用方法,或者相似代码片段可以统一抽取方法调用。

函数过长

一个好的函数必须满足单一职责原则,短小精悍,只做一件事。过长的函数体和身兼数职的方法都不利于阅读,也不利于进行代码复用。

命名规范

一个好的命名需要能做到“名副其实、见名知意”,直接了当,不存在歧义。

不合理的注释

注释是一把双刃剑,好的注释能够给我们好的指导,不好的注释只会将人误导。针对注释,我们需要做到在整合代码时,也把注释一并进行修改,否则就会出现注释和逻辑不一致。另外,如果代码已清晰的表达了自己的意图,那么注释反而是多余的。

无用代码

无用代码有两种方式,一种是没有使用场景,如果这类代码不是工具方法或工具类,而是一些无用的业务代码,那么就需要及时的删除清理。另外一种是用注释符包裹的代码块,这些代码在被打上注释符号的时候就应该被删除。

过大的类

一个类做太多事情,维护了太多功能,可读性变差,性能也会下降。举个例子,订单相关的功能你放到一个类A里面,商品库存相关的也放在类A里面,积分相关的还放在类A里面……试想一下,乱七八糟的代码块都往一个类里面塞,还谈啥可读性。应该按单一职责,使用不同的类把代码划分开。

这些都是比较常见的代码“坏味道”,实际开发中当然还会存在其他的一些“坏味道”,比如代码混乱,逻辑不清晰,类关系错综复杂,当闻到这些不同的“坏味道”时,都应该尝试去解决掉,而不是放纵不管不顾。

大型重构

相对小型重构,大型重构需要考虑的事情比较多,需要定好节奏,按部就班的执行,因为在大型重构中,情况多变。

将大象装进冰箱的步骤一般可以分成三步:1)把冰箱门打开(事前);2)把大象推进去(事中);3)把冰箱门关上(事后)。日常所有的事情都可以采用三步法进行解决,重构也不例外。
在这里插入图片描述

事前

事前准备作为重构的第一步,这一部分涉及到的事情比较杂,也是最重要的,如果之前准备不充分,很有可能导致在事中执行或重构上线后产生的结果和预期不一致的现象。

在这个阶段大致可分为三步:

  • 明确重构的内容、目的以及方向、目标
    在这一步里面,最重要的是把方向明确清楚,而且这个方向是经得起大家的质疑,能够至少满足未来三到五年的方向。另外一个就是这次重构的目标,由于技术限制、历史包袱等原因,这个目标可能不是最终的目标,那么需要明确最终目标是怎么样的,从这次重构的这个目标到最终的目标还有哪些事情要做,最好都能够明确下来。

  • 整理数据
    这一步需要对涉及重构部分的现有业务、架构进行梳理,明确重构的内容在系统的哪个服务层级、属于哪个业务模块,依赖方和被依赖方有哪些,有哪些业务场景,每个场景的数据输入输出是怎样的。这个阶段就会有产出物了,一般会沉淀项目部署、业务架构、技术架构、服务上下游依赖、强弱依赖、项目内部服务分层模型、内容功能依赖模型、输入输出数据流等相关的设计图和文档。

  • 项目立项
    项目立项一般是通过会议进行,对所有参与重构的部门或小组进行重构工作的宣讲,周知大概的时间计划表(粗略的大致时间),明确各组主要负责的人。另外还需要周知重构涉及到哪些业务和场景、大概的重构方式、业务影响可能有哪些,难点及可能在哪些步骤出现瓶颈。

事中

事中执行这一步骤的事情和任务相对来说比较繁重一些,时间付出相对比较多。

  • 架构设计与评审
    架构设计评审主要是对标准的业务架构、技术架构、数据架构进行设计与评审。通过评审去发现架构和业务上的问题,这个评审一般是团队内评审,如果在一次评审后,发现架构设计并不能被确定,那就需要再调整,直到团队内对方案架构设计都达成一致,才可以进行下一步,评审结果也需要在评审通过后进行邮件周知参与人。

该阶段产出物:重构后的服务部署、系统架构、业务架构、标准数据流、服务分层模式、功能模块UML图等。

  • 详细落地设计方案与评审
    这个落地的设计方案是事中执行最重要的一个方案,关系到后面的研发编码、自测与联调、依赖方对接、QA测试、线下发布与实施预案、线上发布与实施预案、具体工作量、难度、工作瓶颈等。这个详细落地方案需要深入到整个研发、线下测试、上线过程、灰度场景细节处包括AB灰度程序、AB验证程序。

在方案设计中最重要的一环是AB验证程序和AB验证开关,这是评估和检验我们是否重构完成的标准依据。一般的AB验证程序大致如下:
在这里插入图片描述

在数据入口处,使用相同的数据,分别向新老流程都发起处理请求。处理结束之后,将处理结果分别打印到日志中。最后通过离线程序比较新老流程处理的结果是否一致。遵循的原则就是在相同入参的情况下,响应的结果也应该一致。

在AB程序中,会涉及到两个开关。灰度开关(只有它开启了,请求才会被发送到新的流程中进行代码执行)。执行开关(如果新流程中涉及到写操作,这里需要用开关控制在新流程写还是在老流程中写)。转发之前需要将灰度开关和执行开关(一般配置到配置中心,能随时调整)写入到线程上下文中,以免出现在修改配置中心开关时,多处获取开关结果不一致。

  • 代码的编写、测试、线下实施
    这一步就是按照详细设计的方案,进行编码、单测、联调、功能测试、业务测试、QA测试。通过后,在线下模拟上线流程和线上开关实施过程,校验AB程序,检查是否符合预期,新流程代码覆盖度是否达到上线要求。如果线下数据样本比较少,不能覆盖全部场景,需要通过构造流量覆盖所有的场景,保证所有的场景都能符合预期。当线下覆盖度达到预期,并且AB验证程序没有校验出任何异常时,才能执行上线操作。

事后

这个阶段需要在线上按照线下模拟的实施流程进行线上实施,分为上线、放量、修复、下线老逻辑、复盘这样几个阶段。其中最重要最耗费精力的就是放量流程了。

  • 灰度开关流程
    逐步放量到新的流程中进行观察,可以按照1%、5%、10%、20%、40%、80%、100%的进度进行放量,让新流程逐步的进行代码逻辑覆盖,注意这个阶段不会打开真实执行写操作的开关。当新流程逻辑覆盖度达到要求、并且AB验证的结果都符合预期后,才可以逐步打开执行写操作开关,进行真实业务的执行操作。

  • 业务执行开关流程
    在灰度新流程的过程中符合预期后,可以逐步打开业务执行写操作开关流程,仍然可以按照一定的比例进行逐步放量,打开写操作后,只有新逻辑执行写操作,老逻辑将关闭写操作。这个阶段需要观察线上错误、指标异常、用户反馈等问题,确保新流程没有任何问题。

放量工作结束后,在稳定一定版本后,就可以将老逻辑和AB验证程序进行下线,重构工作结束。如果有条件可以开一个重构复盘会,检查每个参与方是否都达到了重构要求的标准,复盘重构期间遇到的问题、以及解决方案是什么样的,沉淀方法论避免后续的工作出现类似的问题。

总结

代码技巧

  • 写代码的时候遵循一些基本原则,比如单一原则、依赖接口/抽象而不是依赖具体实现。
  • 严格遵循编码规范、特殊注释使用 TODO、FIXME、XXX 进行注释。
  • 单元测试、功能测试、接口测试、集成测试是写代码必不可少的工- 具。
  • 我们是代码的作者,后人是代码的读者。写代码要时刻审视,做前人栽树后人乘凉、不做前人挖坑后人陪葬的事情。
  • 不做破窗效应的第一人,不要觉得现在代码已经很烂了,没有必要再改,直接继续堆代码。如果是这样,总有一天自己会被别人的代码恶心到,“出来混迟早是要还的”。

重构技巧

  • 从上至下,由外到内进行建模分析,理清各种关系,是重构的重中之重。
  • 提炼类,复用函数,下沉核心能力,让模块职责清晰明了。
  • 依赖接口优于依赖抽象,依赖抽象优于依赖实现,类关系能用组合就不要继承。
  • 类、接口、抽象接口设计时考虑范围限定符,哪些可以重写、哪些不能重写,泛型限定是否准确。
  • 大型重构做好各种设计和计划,线下模拟好各种场景,上线一定需要AB验证程序,能够随时进行新老切换。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/136265.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript 函数-函数概念,使用,函数参数,返回值,arguments的使用,函数的申明方式...

JavaScript 函数 目录JavaScript 函数1. 函数的概念2. 函数的使用2.1 声明函数2.2 调用函数2.3 函数的封装3. 函数的参数3.1 形参和实参3.2 函数参数的传递过程3.3 函数形参和实参个数不匹配问题4. 函数的返回值4.1 return 语句4.2 return 终止函数4.3 return 的返回值4.4 函数…

喜讯 | 代谢组学领航企业百趣生物完成数千万元A+轮融资!

2023年1月3日,国内代谢组学研究领航企业上海百趣生物医学科技有限公司(以下简称“百趣生物”)宣布完成数千万元A轮战略融资。本轮融资由金域医学集团及其参股基金科金金域领投,老股东启明创投跟投。 本次融资资金将用于推动公司结…

教育行业课程介绍话术

教育行业,吸引生源是很重要的一项工作,但是机构或企业能吸引到生源的前提一定是学员对于机构所授课程有强烈的兴趣。 前言 教育行业,吸引生源是很重要的一项工作,但是机构或企业能吸引到生源的前提一定是学员对于机构所授课程有强…

MyBatisPlus ---- 插件

MyBatisPlus ---- 插件1. 分页插件a>添加配置类b>测试2. xml自定义分页a>UserMapper中定义接口方法b>UserMapper.xml中编写SQLc>配置文件d>测试3. 乐观锁a>场景b>乐观锁与悲观锁c>模拟修改冲突d>乐观锁实现流程e>MyBatis-Plus实现乐观锁1. 分…

蓝牙耳机什么牌子性价比高?性价比最好的蓝牙耳机排行

近年来,蓝牙耳机越来越成为人们日常生活中常见的数码产品之一,逐渐地,看到更多的音频厂商、手机厂商加入蓝牙耳机市场中来。最近,看到很多人问,蓝牙耳机什么牌子性价比高?下面,我来给大家分享一…

浅谈map和unordered_map的应用场景

map和unordered_map的适用场景 底层结构介绍 map底层是红黑树结构unordered_map底层是哈希结构; Hash适用场景(unordered_map) 内存存角度来说hash因为底层维护了哈希表的存在,内存消耗远大于红黑树,但是因为哈希表增删查改时的直接映射&#xff0c…

OpenFeign服务接口调用

✨ OpenFeign服务接口调用OpenFeign & FeignFeign基本介绍OpenFeign基本介绍二者对比OpenFeign的使用新建Module:cloud-consumer-feign-order80pom依赖application.yml全局配置文件主启动类Service1. 业务逻辑接口FeignClient配置调用provider服务2. 新建Paymen…

第三十九讲:神州无线AC基础管理配置

瘦AP零配置上线,对AP的管理和配置都在AC上进行。AC的基础管理包括AC的无线地址指定及无线功能开启、AP的注册、AP用户数管理、自动信道调整等。 一、配置AC无线IP地址 设置静态的无线IP地址查看AC选取的无线IP地址3.开启无线功能 二、AP注册 1.二层模式…

【网络结构设计】11、E-LAN | 通过梯度传输路径来设计网络结构

文章目录一、背景二、方法2.1 网络设计策略2.2 Partial Residual Networks2.3 Cross Stage Partial Networks2.4 Efficient Layer Aggregation Network三、效果论文:Designing Network Design Strategies Through Gradient Path Analysis 代码:暂无 出…

微服务应用视角解读如何选择 K8s 的弹性策略

头:潘俊峰 前言 微服务架构的出现,拆分了庞大的单体应用,让业务之间的开发与协作变得更加灵活。当面临业务流量增加的场景时,往往需要对一些应用组件进行扩容。K8s 在应用层面提供了 HPA,围绕 HPA 开源社区延伸出了 …

SAP-FI模块 处理自动生成会计凭证增强

FICO-模块一. 相关问题概览1. 固定资产业务过渡科目摘要增强功能-F-022. 固定资产业务过渡科目摘要增强功能-MIGO3. 主营业务收入等科目自动反记账功能二. 问题图片描述1. 固定资产业务过渡科目摘要增强功能-F-022. 固定资产业务过渡科目摘要增强功能-MIGO3. 主营业务收入等科目…

JavaScript 作用域-作用域概述,变量作用域,作用域链

JavaScript 作用域-作用域概述,变量作用域,作用域链 目录JavaScript 作用域-作用域概述,变量作用域,作用域链1. 作用域1.1 作用域概述1.2 全局作用域1.3 局部作用域 (函数作用域)1.4 JS 没有块级作用域2. 变量的作用域2.1 变量作用…

校验和之概念、计算原理、检验原理、实例计算、代码编程,力荐力荐力荐

阅读前请看一下:我是一个热衷于记录的人,每次写博客会反复研读,尽量不断提升博客质量。文章设置为仅粉丝可见,是因为写博客确实花了不少精力。不用担心你关注我而我却不关注你,因为我是个诚信互关的人!&…

如何用LightningChart创建Android图表数据可视化应用程序?(下)

LightningChart JS 是一款高性能的 JavaScript 图表工具,专注于性能密集型、实时可视化图表解决方案。 LightningChart .JS | 下载试用(qun:740060302)https://www.evget.com/product/4189/download 在上一篇,我们介…

CDN是什么?用了CDN就一定比不用更快吗?

对于开发同学来说,CDN这个词,既熟悉又陌生。 平时搞开发的时候很少需要碰这个,但却总能听到别人提起。 我们都听说过它能加速,也大概知道个原因,但是往深了问。 用了CDN就一定比不用更快吗? 就感觉有些…

Node.js操作Dom ,轻松hold住简单爬虫

前言 前段时间,我发现一个开源题库,题目非常有意思。我想把它整成一个JSON文件做为数据储备,方便整活。 一共有一百五十多道题目,手动CV我肯定是不想干的。于是写了个脚本,在写脚本的过程中,我发现一个能…

Opencv(C++)笔记--利用分水岭算法实现图像分割

1--分水岭算法的原理详细原理讲解可参考:博客1和视频1;原理简述:分水岭算法的基本思想是把图像视为拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而两个集…

csrf漏洞原理及防御

攻击原理 从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤 1.登录受信任网站A,并在本地生成Cookie 2.在不登出A的情况下,访问危险网站B 防御原理 csrf能防御的本质是,黑客虽然携带了合法的cookie&a…

振弦采集模块的辅助功能寄存器

振弦采集模块辅助功能寄存器 1.频率值模拟量输出 VMXXX(仅 VM501、 VM511) 模块支持将当前实时频率值以模拟量形式从管脚输出,模拟量有电流和电压两种输出形式。为了使用此功能,需要将辅助功能寄存器 AUX.[0]设置为 1&#xff0…

<Linux开发> ubuntu开发工具-EasyConnect使用记录

<Linux开发> ubuntu开发工具-EasyConnect使用记录 1、安装EasyConnect 打开EasyConnect官网EasyConnect 根据当前电脑系统选择对应版本下载 作者这里是ubuntu 22.04版本 右击,选择 “软件安装” 即可安装完成;windows版本类似…