尽量不写一行if...elseif...写出高质量可持续迭代的项目代码

背景

无论是前端代码还是后端代码,都存在着定位困难,不好抽离,改造困难的问题,造成代码开发越来越慢,此外因为代码耦合较高,总是出现改了一处地方,然后影响其他地方,要么就是要修改一个逻辑,结果耗费了大量时间进行改造,代码写得耦合较高,造成这种情况的原因无非就是程序员本身没有管理者的思维,喜欢取巧,合并,凑数,偷懒造成的,说白了,想比做的少,更多的是先动手去干,而不是先想好过去/现在/未来三种情况再干,这样撸着撸着,就会将代码撸得让自己越来越反感,越枯燥!

新语法,高阶语法无心尝试,这些东西并非为了装逼用,大佬创造他们并设为标准,就是为了解决代码可能存在的问题。

问题一:顺向思维

需求交接后,并不对旧逻辑 + 新逻辑进行整合过滤,而忙于添加一个 if...elseif 就着手开发了,一个例子就是智能养号,拿到需求后,快速得出 3 个按钮的组合是 4 种可能,实际上整体思考后,会发现其中 团队开关开启和互养池开关开启 只走互养池逻辑,也即 3 个逻辑。

以下是伪代码,主要讲述主逻辑展示的必要性,子逻辑仍然要遵循一条线法继续拆分函数,直到最小颗粒度的函数体,才去实现,而函数体不应该超过 100 行,否则很有必要继续拆分

@router.post('/target-wid')
async def get_target_wid(user_id: int = Depends(get_user_id),company_id: int = Depends(get_company_id),item: TargetWhatsappIdGetParam = Body()
):'''第一层代码纯主逻辑 绝无细节 未来还可能有更多主逻辑而未来追加新逻辑链路只是再加一行代码而已第一层逻辑绝无 elsif 因为要一条线到底'''if huyang.switch:return huyang.match_numbers()if team_huyang.switch:return team_huyang.match_numbers()return selfyang.match_numbers()

问题二:不封装函数

无论是前端还是后端,现在都已经有了面向对象的概念,尤其是 ES6 的存在,相同逻辑的东西可以封装成函数,但是目前前端的代码封装密集度不够。仍然是面向过程的开发。

问题三:面向对象

python 本身已支持面向对象,而后端程序员都是科班出身,同时又都学过 java,但是代码写得不尽人意,仍然是赤裸裸地面向过程,更别提面向切面了,连个装饰器都没有尝试写过,真的不需要吗?还是懒得去总结代码,划分出来这些东西?

model 是什么?

model 是编程语言映射数据库字段的中转对象,将 mysql 二进制字符对应转化为编程语言的类型,每条记录对应一个 model

  1. model 是编程语言对象,是对象除了属性还是有行为,行为就是静态函数或者成员函数

    1. 静态函数往往处理本表的一些转换性操作,例如创建对象时的前置数据处理,保存对象前的前置处理,获取对象后的后置处理,都是静态成员函数的工作,不针对于某个对象,而是针对于所有对象的面向切面的操作

    2. 成员函数,往往是对于从数据库查询了特定记录,针对这一条记录进行数据的处理,处理完成后返回某值,或者入库

    3. 以上两个操作都是 model 的操作范畴

service 是什么?

service 是针对功能模块下的一堆逻辑的操作集合,它含有各种函数,又可以将各种函数进行组合再构成新函数,主要的目的就是将逻辑进行最大化的封装,不暴露细节,而细节都在私有函数里

举个例子我想下单,那么就有 OrderService,OrderService 对外提供一个 public 函数,createOrder(orderInfo, userId),那么 OrderService.createOrder(orderInfo, userId),创建完订单后还要干什么,那就是其他各种公共函数了,createOrder 函数里面例如提取可用优惠券,drawCanUseCoupons(userId),这个就是私有函数,提取后还得计算优惠券的匹配情况 getMatchCoupons(orderInfo, coupons)等等各类私有函数,这些私有函数在取消订单时也会用到,但是你单独使用 drawCanUseCoupons(userId),例如用户卡券包,这时你发现可以再抽出一个 UserService,将drawCanUseCoupons(userId)挪过去,因为这个跟订单信息无关,跟用户信息有关,这就是 Service

service 存在意义?

service 存在意义是将需求主逻辑变得特别简洁易懂,不暴露任何细节,如图:

这是一个巨复杂的创建订单的前置校验,如果我直接将 createOrder 暴露出来,这个代码得有 1000 行,但是为了要保持函数代码的体积,这里只将主逻辑呈现,细节继续细化

而 createOrder 主逻辑也仅仅 40 行代码

createOrder 主体逻辑也是由大量其他 model 和 service 逻辑函数组合而成

这样写的好处就是主逻辑结构一直很清晰,自己需要记忆的东西是分层的,每次进入一个函数,或者跳出一个函数,都不用带着巨大的上下文来思考,只需要集中在这个单元函数里,保证单元函数的正确性即可,整体逻辑组合在一起,是不可能出现大差错的。

问题三:重复函数的使用

程序员有个习惯,尤其是面向过程的习惯

看一个 python 代码,这里为了要承接上面代码最终结果的过滤,就用了大量的 if...else 以及嵌套的 if...else

如果改造完了之后,应该就是 3 个主逻辑函数,分别调用 NurtureService.xxx1/2/3 三种逻辑,每个函数都是 return,针对 filter,再各自调用 NurtureService.filter(numbers),如果 filter 里面还需要 if...else 判断,则再将 filter 拆分为 filter1/2/3,也即将逻辑改为一顺而下,而非底层汇编语言的来回 jump,每个 while 和每个 if 都是一次 jump,jump 计算机会中断,人脑也会中断,阅读识别都不方便

而函数对于计算机来说,用完即焚,会快速清理内存,而上面这种面向过程的代码,就很难做到清理内存,if 过程中产生的变量都会存在内存里,直到这个函数运行完毕。

代码重复一定要封装,函数重复没问题,函数名在底层就是 16 进制,而且并不是重复存储,所以大胆地将函数重复调用,将代码逻辑实现完美解耦。

下面就是一个好例子

问题四:善用文件夹

程序员养成了一个习惯,就是通过命名前缀来区分代码文件,加多了就造成命名冗长,同时单个文件夹下的代码文件巨多,看这里 OrderController,我都用一个命名,通过文件夹的方式进行区分,任何语言都有命名空间的概念,所以这样既能让代码命名简洁,不来回乱起,还能保持层次分明

问题五:控制反转和反射机制

我们的习惯是一个类的处理逻辑必须由自己实现,也即 order.createOrder,实际上我们可以将这种权力交出去,让其他对象来处理它,例如

OrderService.createOrder(order),如果前面的 OrderService 可以通过上面的那种命名空间的方式用反射机制,这种方式可以根据传入参数,这种方式可有效减少 if...else 的使用,但也造成了代码的不易读,最好用 Factory 工厂模式,通过传入参数,显式地调用具体的类,这样可读性就高了很多,代码可维护性也提高了很多,而且每个逻辑都是隔离的,改动起来不会对其他逻辑产生任何影响

class_name = "api.OrderService"
my_class = globals()[class_name]# 创建对象实例
instance = my_class()# 调用对象的方法
print(instance.createOrder(order))

问题六:很少对单函数进行异常预测和收集

如果上面 5 个问题都得到了很好的处理,那么剩下的就是异常的预测和收集,每个单元函数都会出现异常,go 语言就很好,返回值总是,result,err = xxxx(),其中 err 就是一个错误,错误产生后,可以通过人为判断是否向上抛出,或者自行消化,再或者 push 到一个错误收集器里

顶级函数外层都会进行错误捕获和处理,这里 PHP 做得比较粗糙了些

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

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

相关文章

通讯录(C语言详细版)

1. 前言 通讯录是在动态顺序表的基础上实现的,其实就是顺序表的每个元素存储的不再是数字,而是存储一个联系人的结构体,所以如果有些小伙伴看不懂的话,可以移步参考一下动态顺序表的实现:顺序表(C语言详细…

【C语言】auto 关键字

在C语言中,auto关键字用于声明局部变量,但它的使用已经变得很少见。事实上,从C99标准开始,auto关键字的默认行为就是隐含的,因此在大多数情况下无需显式使用它。 基本用法 在C语言中,auto关键字用于指定变…

ntp服务

https://blog.csdn.net/weixin_39168541/article/details/123741031

SpringBoot应用配置桥接Prometheus入门

SpringBoot应用配置Prometheus步骤 SpringBoot应用依赖要求PrometheusGrafanaGrafana监控界面模板 SpringBoot应用依赖要求 <!-- 监控系统健康情况的工具 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot…

【3分钟准备前端面试】vue3

目录 Vue3比vue2有什么优势vue3升级了哪些重要功能生命周期变化Options APIComposition APIreftoRef和toRefstoReftoRefsHooks (代码复用)Vue3 script setupsetupdefineProps和defineEmitsdefineExposeVue3比vue2有什么优势 性能更好体积更小更好的TS支持更好的代码组织更好的逻…

104.二叉树的最大深度——二叉树专题复习

深度优先搜索&#xff08;DFS&#xff09;是一种常用的递归算法&#xff0c;用于解决树形结构的问题。在计算二叉树的最大深度时&#xff0c;DFS方法会从根节点开始&#xff0c;递归地计算左右子树的最大深度&#xff0c;然后在返回时更新当前节点所在路径的最大深度。 如果我…

PyAutoGUI 使用详解

文章目录 简介PyAutoGUI 的原理安装 PyAutoGUI基本使用示例鼠标控制键盘控制截屏图像识别消息框 高级功能防止误操作多屏幕支持鼠标平滑移动 结论 简介 PyAutoGUI 是一个用于自动化控制鼠标和键盘的 Python 库。它可以帮助开发者编写脚本&#xff0c;以模拟用户在计算机上的操…

每日复盘-20240704

今日关注&#xff1a; 20240704 六日涨幅最大: ------1--------300391--------- 长药控股 五日涨幅最大: ------1--------300391--------- 长药控股 四日涨幅最大: ------1--------300391--------- 长药控股 三日涨幅最大: ------1--------300391--------- 长药控股 二日涨幅最…

[笔记]小米CyberDog机器狗仿真调试记录

从官方github的所有源码库来看&#xff0c;所有的source命令只有两条&#xff0c;执行它以配置环境变量&#xff1a; source /opt/ros/galactic/setup.bash source /home/cyberdog_ws/install/setup.bash 如果运行脚本之后gazebo正常启动及机器狗模型在悬空状态&#xff0c;问…

三位数重新排列c++

题目描述 给你一个三位数 n&#xff08;保证最高位不是 0&#xff09;&#xff0c;你可以重新调整它三个数位的顺序&#xff0c;请输出结果最小的一种。 输入 第一行一个整数 n。 输出 一行一个整数&#xff0c;重新调整顺序后&#xff0c;最小的结果。 注意&#xff0c;…

文心一言 VS 讯飞星火 VS chatgpt (295)-- 算法导论21.4 4题

四、利用练习 21.4-2 &#xff0c;请给出一个简单的证明&#xff0c;证明在一个不相交集合森林上使用按秩合并策略而不使用路径压缩策略的运行时间为 O(m lgn) 。21.4-2 的内容是&#xff1a;“证明&#xff1a;每个结点的秩最多为 ⌊lgn⌋ 。”。如果要写代码&#xff0c;请用…

objdump

objdump是一个用于在Linux系统中查看和解析对象文件&#xff08;如可执行文件、目标文件和共享库&#xff09;的命令行工具。它可以展示文件的多种信息&#xff0c;包括汇编代码、符号表、调试信息等。objdump的常用选项包括&#xff1a; -d 或 --disassemble&#xff1a;反汇编…

vue模板语法v-html

模板语法v-html vue使用一种基于HTML的模板语法&#xff0c;使我们能够声明式的将其组件实例的数据绑定到呈现的DOM上&#xff0c;所有的vue模板都是语法层面的HTML&#xff0c;可以被符合规范的浏览器和HTML解释器解析。 一.文本插值 最基本的数据绑定形式是文本插值&#…

Kafka 为何如此之快?深度解析其背后的秘密

目录 前言 一、生产者 1. 异步发送 2. 多分区并行 3. 消息批量发送 4.支持消息压缩 二、存储端 1. 分区和副本 2. 页缓存 3. 磁盘顺序写入 4. 零拷贝技术 5. 稀疏索引 三、消费端 1. 消费者群组 2. 批量拉取 3. 高效的偏移量管理 4. 并行消费 总结 前言 Kafk…

CS算法(二)—— 斜视SAR点目标仿真

SAR成像专栏目录 我们按照Cumming教授所著的《合成孔径雷达成像——算法与实现》7.6节的点目标参数进行仿真,斜视角设置为8,中心斜距改为1000km。先放最终的仿真结果: 1. 参数配置 在中心点和中心的的上下左右方向设置5个点目标 : function para=config_sar_para_cumming(…

【python数据处理】— “2020-01-01 05:20:15“日期格式数据

文章目录 一、数据说明及目标二、实现方式1.提取date2.提取hour3.提取weekday4.提取month 一、数据说明及目标 数据说明 数据表有一列名为"datetime"表示时间数据&#xff0c;该列的数据格式是"2020-01-01 05:20:15"。 import pandas as pd datapd.read_e…

[数据集][目标检测]刀具匕首持刀检测数据集VOC+YOLO格式8810张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;8810 标注数量(xml文件个数)&#xff1a;8810 标注数量(txt文件个数)&#xff1a;8810 标注…

C++基础语法:引用

前言 "打牢基础,万事不愁" .C的基础语法的学习 引入 引用是C里的概念,和C语言里的"指针常量"是类似的.在C里用得还挺多的,书中明确说明了类对象做参数时,传入类对象的引用.在<<C Prime Plus>> 6th Edition第274页有使用推荐 .用引用来回顾指针…

uniapp+python使用临时签名上传腾讯云oss对象储存方案

概述 uniapp使用临时签名上传腾讯云oss对象储存方案&#xff0c;支持小程序、app、h5&#xff1b; 前端不依赖腾讯云SDK工具类&#xff1b; 后端使用python实现&#xff0c;需要安装qcloud-python-sts&#xff1b; 其中计算文件md5值使用了条件编译&#xff0c;因为每个环境获…

堆结构、堆排序

堆 是完全二叉树&#xff0c;类似这种样式的 而这种有右子节点&#xff0c;没左子节点的就不是完全二叉树 分为大根堆和小根堆 大根堆是二叉树里每一颗子树的父节点都是这颗子树里最大的&#xff0c;即每一棵子树最大值是头节点的值 小根堆相反 把数组中从0开始的一段数人…