日常开发为什么需要做Code Review
日常开发为什么需要做Code Review
一、背景
最近在开始一个新的项目,在查看项目中代码及具体细节时,发现这个项目真实一堆乱麻,没有规律可循,可总结下这个项目的缺陷
- 没有规律可循,没有结构性设计
- 不做公共封装,哪里方便哪里创建变量
- 一个个文件大于300行,都是超大文件,组件中方法超大逻辑
- class组件部分逻辑可继承封装,但是采取了复制粘贴相同代码的处理
看的我是一堆乱麻,不由得让我开始思考,程序员果真是懒,如果再勤快一些,可能会进行代码的封装和考虑这些公用方法及组件的抽取,同时也存在项目中Code Review 的缺失。
二、为什么需要Code Review 及优点
看这些奇奇怪怪的代码,不由得让我拍脑袋直言,当初多进行进行Code Review ,将这些问题屏蔽掉至少,那Code Review 有哪些优点呢
进行代码审查的原因可以归结为以下几点:
-
提高代码质量: 可以帮助开发者更好地编写代码,减少错误和缺陷,提高代码的质量和可维护性。通过Code Review ,开发者可以识别并修复潜在的问题,从而提高代码的可靠性和稳定性。
-
减少错误率:通过代码审查,开发人员可以发现之前可能没有注意到的错误或缺陷,从而减少错误的发生。
-
促进团队协作: 可以帮助团队成员之间更好地协作,不仅仅是老员工之间的协作,而且更加有效的帮助新员工融入到团队中,确保代码的一致性和可重用性。通过 Code Review ,开发者可以更好地理解其他开发者的代码,并从中学习,从而提高自己的编程水平。
-
提高开发效率: 可以帮助开发者更快地完成任务,减少代码编写的时间。通过 Code Review ,开发者可以更快地发现和解决问题,从而减少调试的时间和工作量。
-
确保代码符合规范: 可以帮助开发者遵循团队的代码规范,确保代码的可读性和可维护性。这对于大型项目的开发非常重要,因为遵循规范可以帮助开发者更好地协作和理解代码。
综上所述,Code Review 对于前端开发的质量和效率都非常重要。通过 Code Review ,开发者可以更好地编写代码,提高代码的质量和可维护性,促进团队协作,提高开发效率和确保代码符合规范。
三、Code Review 都有哪些方式
总体来说可分为常规代码Code Review
和 阻断式Code Review
- 常规代码Code Review
提出修改建议与检查,不阻断代码合并或者影响开发者其他进度的检查
通常这种检查会是团队成员聚集在一起,听其他成员讲述自己最近的开发代码。 - 阻断式Code Review
需要合并进主分支等,需要必须要求复合规定时的检查,必须等待处理完所有建议或者不符合规定的点之后才能合并进主分支
四、Code Review 都会去注意哪些点
既然要做Code Review,那应该去检查哪些细节,我举个我开发中遇到的一些例子,给大家打个样,开发层更多地涉及到React Native中的一些知识点,可以选择性的阅读。
-
代码是否按照lint规范提交,以及其他约定的一些规范提交
至关重要的检查,lint可以省掉很多review内容,可能有时,一些比较着急的开发者会提交代码时使用
-n
命令忽略检查进行提交 -
useSelector使用规则,优化页面性能
使用redux的同学可能会知道,useSelector会导致页面重新渲染,这边也就成为了日常review的一项const kfo = useSelector((state) => state.AtReducer.kfo || {});
不规范原因: useSelector 底层是使用 === 比较 此处|| {}代码逻辑上容易触发render更新;
建议改为以下写法const kfo = useSelector( (state) => state.AtReducer.kfo ) || {}
使用useSelector时也需要关注state的粒度,导出自己需要的变量,不要一下子导出state.userInfo整个变量,同时使用shallowEqual进行比对处理
const { username, age } = useSelector(state => { const { username, age } = state.userInfo;return { username, age }; }), shallowEqual);
-
不要出现大文件,大文件增加分组进行拆分,按照业务模块分组或者extends继承机制处理
超过1000行的文件出现bug,你会去看吗?你会很轻松的找到问题所在吗?答案肯定是不会,因为那么多行代码需要检查,而且也没有信息完全肯定能够修改正常,那肯定得避免出现这种文件,方便自己以及后面有其他同事接手这个项目时,能够不会有那么多的心理负担「🐶」
-
双map或forEach遍历时,可能需要考虑优化
出现这种情况的常见算法一般都是先找出数组中固定的某一个值,然后在用这个值去做业务逻辑,这样可能得和业务人员确定是否存在更加优化的处理方案,比如下面是用了es6中结构赋值的方案去减少了一次检索的过程,这种双循环的,一般都仔细检查下看看是否有优化方案
// 使用解构赋值的模型,减少map循环的使用 (lists || []).map(({ person: name }) => {// 使用name在进行处理其他业务逻辑// name })
-
默认的空赋值[]或者{}
正常来说,比如子组件的userList属性规定类型是数组,在父组件加工数据时提供数据默认值是非常好的习惯,于是我常常在组件内部或者mapStateToProps中看到类似的写法:
const App = (props) => { // 当存在时赋予空数组,保证下层数组类型的正确性 const userList = props.userList || []; return (<Child userList={userList} />) };
当App多次渲染且props.userList为假值时,此时的userList也会被不断的赋予全新的空数组。还记得前文说的吗,当你结构没变化时,我们保证其引用不变不就好了,所以对于空数组都可以在全局赋予一个空数组,比如:
const emptyArr = []; const App = (props) => { // 当存在时赋予空数组,保证下层数组类型的正确性 const userList = props.userList || emptyArr;return (<Child userList={userList} />) };
这样不管App如何渲染,当userList被赋予为空数组时也能让前后引用相同。
-
使用 DeviceEventEmitter.addListener( ‘CHANGE’, function () {})注意依赖的项目可能不为最新值问题
const ref = useRef();const listenerChange = () => {dispatch(FetchConfig({ jwtKey: userInfo?.jwtKey }, (dataList) => {setKols(dataList);}));}ref.current = listenerChange;useEffect((): function => {const listener = DeviceEventEmitter.addListener('CHANGE',function () {ref.current?.();})return () => {listener?.remove?.();};}, []);
如果参数存在于延迟setTimeout,同时依赖于变量,也需要考虑通过以上方案处理,看看下面栗子🌰
const [jwt] = useState('');setTimeout(() => {DeviceEventEmitter.emit('send',{ jwt: jwt }) })
-
addListener事件命名建议采用【模块_特性_名称】,采用全局较为统一的规范
如:LOGIN_STATUS_CHANGE,LOGOUT_STATUS_CHANGE -
使用useFocusEffect注意配合使用useCallback,否则会造成多次渲染
-
默块引入使用路径别名,抽取行内样式
-
Platform.select 和 Platform.OS区分,针对平台比较复杂的逻辑,使用平台判断Platform.select的方案处理
-
react-native元素标签逻辑判断问题
isShow逻辑判断使用!!isShow转义后进行使用,否则会提示文本必须在Text元素中使用的提示信息<View style={styles.fastContainer}>{!!isShow && <View></View>} </View>
-
使用setTimeout、setInterval等伪代码时,需要在组件卸载时或关闭操作时将其清除掉
● setTimeout的销毁函数为clearTimeout
● setInterval的销毁函数为clearInterval
对于多次打开的setTimeout,setInterval需要在再次开启时清空其值clearmyTime: () => void = () => {// eslint-disable-next-lineif (!!this.myTimeout) {clearTimeout(this.myTimeout);this.myTimeout = null;} };onSelected = () => {// 每次开启新的延迟计时器时,都进行清空操作this.clearmyTime();this.myTimeout = setTimeout(() => {// 操作}, 1000) }
-
数组遍历需要考虑使用useMemo处理
map,filter等方法,以及lodash中的遍历方法,都需要使用useMemo进行处理 -
数值类比较操作
receive < 0 ? 0 : receive
,可以考虑使用数学方法const value = receive < 0 ? 0 : receive; // 等同于 const value = Math.max(receive, 0);
-
保证key唯一,不要使用数组遍历产生的index,方便虚拟dom diff,提升性能
相关文章:

日常开发为什么需要做Code Review
日常开发为什么需要做Code Review 一、背景 最近在开始一个新的项目,在查看项目中代码及具体细节时,发现这个项目真实一堆乱麻,没有规律可循,可总结下这个项目的缺陷 没有规律可循,没有结构性设计不做公共封装&#…...

OSPF的优化
O_ASE --- 标志域外路由信息 --- 因为域外的路由信息不可控性较强,所以,信任程度较低,我们将其优先级设置为150。 LSA --- 链路状态通告 --- OSPF协议在不同网络环境下产生的用于携带和传递不同的信息。 LSDB --- 链路状态数据库 SPF --- 最短…...
C++项目中打破循环依赖的锁链:实用方法大全
C项目中打破循环依赖的锁链 一、简介(Introduction)1.1 循环依赖的定义(Definition of Circular Dependencies)1.2 循环依赖带来的问题(Problems Caused by Circular Dependencies)1.3 解决循环依赖的重要性…...
IDEA连接HBase
新建maven工程 打开pom.xml添加hbase需要的依赖 <dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>2.3.5</version> </dependency><dependency><groupId>org.apa…...

Mask2Former来了!用于通用图像分割的 Masked-attention Mask Transformer
原理https://blog.csdn.net/bikahuli/article/details/121991697 源码解析 论文地址:http://arxiv.org/abs/2112.01527 项目地址:https://bowenc0221.github.io/mask2former Mask2Former的整体架构由三个组件组成: 主干特征提取器ÿ…...

【量化课程】01_投资与量化投资
文章目录 1.1 什么是投资1.1.1 经济意义上的投资1.1.2 投资的分类1.1.3 金融投资1.1.4 个人投资者投资品种1.1.5 投资VS投机 1.2 股票投资的基本流程1.3 常见的股票投资分析流派1.3.1 投资者分析流派 1.4 什么是量化投资1.4.1 量化投资基本概念1.4.2 量化投资的优势1.4.3 量化投…...

SpringBoot实现导出Excel功能
1 问题背景 需求要做一个导出excel的功能 2 前言 本篇着重阐述后端怎么实现,前端实现的部分只会粗略阐述。该实现方案是经过生产环境考验的,不是那些拿来练手的小demo。本文阐述的方案可以借鉴用来做毕设或者加到自己玩的项目中去。再次声明,…...

NSSCTF之Misc篇刷题记录⑧
NSSCTF之Misc篇刷题记录 [MMACTF 2015]welcome[广东强网杯 2021 团队组]欢迎参加强网杯[虎符CTF 2022]Plain Text[SWPUCTF 2021 新生赛]原来你也玩原神[SWPUCTF 2021 新生赛]我flag呢?[鹤城杯 2021]New MISC NSSCTF平台:https://www.nssctf.cn/ PS&…...

从零开始学习Linux运维,成为IT领域翘楚(七)
文章目录 🔥Linux下常用软件安装_JDK和Tomcat安装🔥Linux下常用软件安装_MySQL安装🔥Linux下常用软件安装_MySQL卸载 🔥Linux下常用软件安装_JDK和Tomcat安装 Jdk 安装 解压jdk安装包 tar -zxvf jdk-8u201-linux-x64.tar.gz -C/…...
优漫动游设计APP的UI界面需要注意哪些问题?
一、加载 加载时间的长短,很大程度的决定了用户体验是否有所提升,虽然理想中的页面加载出来应该一秒就够了,但是设计师不要忽略网络问题!如果网速不够的话,页面加载三五秒都算是快的了,所以在用户等待的过程中&a…...
面试 004
什么是 Java 内存结构 Java 内存结构就是 JVM 的运行书数据区的内存结构: 里面有堆、虚拟机栈、本地方法栈、程序计数器; 虚拟机栈:里面的数据结构是栈帧,存放了方法名,局部变量等信息 方法区在 1.8 的时候…...
CCF-202206-2-寻宝!大冒险!
目录 题目背景 问题描述 一、思路: 二、实现方法(C) 2.1、方法一(int储存) 思路: C实现如下: 2.2、方法二(结构体储存) 思路: 注意:边界…...

二叉搜索树中的众数
1题目 给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。 如果树中有不止一个众数,可以按 任意顺序 返回。 假定 BST 满足如下定义&…...

认识JSP
什么是JSP? JSP(Java Server Pages)是一种类似于HTML的标记语言,用于创建动态Web页面。与HTML不同的是,JSP页面中可以嵌入Java代码,由Web服务器在动态页面中生成HTML代码,从而实现Web应用程序的前端交互效…...

MySQL数据管理
一、MySQL数据库管理 1、库和表 行(记录):用来描述一个对象的信息 列(字段):用来描述对象的一个属性 2、常用的数据类型 int :整型 float :单精度浮点 4字节32位 double &…...

第十九章 Unity 其他 API
本节介绍一些其他经常使用的Unity类。首先,我们回顾一下Vector3向量类,它既可以表示方向,也可以表示大小。它在游戏中可以用来表示角色的位置,物体的移动/旋转,设置两个游戏对象之间的距离。在我们之前的课程中&#x…...
sha256算法详解,用C语言模拟sha256算法
SHA-256是一种加密算法,它可以将任意长度的数据块计算出一个固定长度的输出值,通常是256位。SHA-256具有以下特点: 1. 固定输出长度:SHA-256的输出长度为256位,不受输入数据的长度限制。 2. 不可逆性:SHA-256采用单向哈希函数,即无法从输出值反向推出输入数据。 3. 抗…...
前端技术未来发展展望
前端技术在未来的发展中将继续保持快速、变化多样和创新性强的趋势。以下是我认为前端技术未来发展的几个方向: 框架和库的演进:框架和库的更新换代将继续加速。React、Vue、Angular等主流框架的更新周期将会缩短,同时各自的生态系统也将更加…...
第四十六天|dp
今天的题还是完全背包的题 139. Word Break 这道题其实用deque也能做,但是需要cache去记录之前尝试过的值,.相对简单的办法就是用完全背包了 这道题worddict就是物品.我们的dp[i]代表到i为止是不是能满足题意分成segmentation 处置化全为false,但是dp[0]True.这是因为为0时…...

汇编语言-复习自用
本文用于自我复习汇编语言,参考b站一位老师的讲解整理而成,感谢老师的无私付出视频链接链接 文章目录 1.第一章1.1计算机组成1.2读取1.3 寄存器及数据存储1.4 mov和and指令1.5 确定物理地址1.6 内存分段表示法1.7debug使用1.8CS:IP1.9jmp指令改变csip1.1…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...