面对一堆烂代码,重构,还是重新开发?

news2024/11/19 1:29:39

hello,大家好,我是张张,「架构精进之路」公号作者。

11e1d1c6d1aeb01eb5a78d1c948a2c8a.jpeg

1、烂代码的形成

写烂代码很容易,但代码写成一坨屎,还能正常运行,那就要有点水平才行。

尤其是一些经验不足的新手,根本不在乎代码质量的重要性,也没啥扩展性的考量,直接出手就是干。

可是几个月之后,他们似乎也没怎么踩坑,但随着业务的不断发展,吸引了更多的人加入到这个项目中来。

语言越来越高级、封装越来越完善,各种技术都在帮助程序员提高生产代码的效率,依靠层层封装,程序员真的不需要了解一丁点技术细节,只要把需求里的内容逐行翻译出来就可以了。

很多程序员不知道要怎么组织代码、怎么提升运行效率、底层是基于什么原理,他们写出来的是在我心目中烂成一坨屎一样的代码。但是那一坨屎一样代码竟然能正常工作。

即使我认为他们写的代码是坨屎,但是从不接触代码的人的视角来看(比如说你的boss),代码编译过了,测试过了,上线运行了一个月都没出问题,你还想要奢求什么?

所以,即使不情愿,也必须承认,别人写的代码能正常运行,且不出错,那就是牛x。

2、烂代码终究是烂代码

但是偶尔有那么几次,写烂代码的人离职了之后,事情似乎又变得不一样了。

想要修改功能时却发现程序里充斥着各种无法理解的逻辑、改完之后莫名其妙的bug一个接一个,接手这个项目的人开始漫无目的的加班,并且原本一个挺乐观开朗的人渐渐的开始喜欢问候别人祖宗了。

792df5f8e02a7d23b0b678a2b8683b78.jpeg

试问:针对烂代码就没有可解的方案了么?

3、重构之道

针对代码重构,有本经典的读本《重构:改善既有代码的设计》,非常全面的阐述了各种重构之术。

而且各种编程范式,比如面向对象编程中的类的重构和函数式编程中的函数的重构也不尽相同;各种语言,比如 elixir(pattern matching, macro),javascript(closure,FP),和 C++(OOP) 三种语言的重构手段就千差万别。

3.1 时时刻刻重构

重构代码最佳的时间点:撰写每行代码的时候,而非火烧屁股的时候。

那什么样的情况你需要进行重构呢?

有道是 bad code smells。存在下面这些让你感到不太舒服的场景时,其实是在提醒你代码该重构了。

1)当你写一段代码时,不得不从别处拷贝粘贴代码

显然,这有悖于 DRY(Don't repeat yourself)。

一段代码(文档,测试,注释)如果要被复制,那么它的逻辑就该被抽取出来,单独成文。这几乎是重构最基础的实践。

然而,这个问题,从小公司到大公司,几乎是每个系统最严重的问题之一。在我以前工作的公司,我维护过一个超过 5000 行的 C 函数,里面的 if-else 层层嵌套下的 copy&paste 让人叹为观止,添加一点逻辑需要检查七八个地方是否需要同样的逻辑,完全可以入选教材作为经典的反面案例。

2)当你修改已有代码添加新功能时,发现已有代码总感觉哪里不对

比如说,逻辑写得太绕,太复杂,太难以理解,循环太多,分支太多,状态太多等等。

这样的代码几乎跪在那里请求你的重构,不重构说不过去。

3)当你调用已有的代码(函数、类),不得不阅读被调用的代码才能确定怎么调用时

  • 这个代码要么接口定义的不好,比如说,一个函数有十多个参数;

  • 要么是文档写的不好,比如说,关键性的函数没有对接口提供足够的说明。

如果说上面所述的是纯粹的代码重构,那么这里就是用户体验的重构。

程序员的代码是什么?那是一个程序员为另一个程序员精心打造的产品,函数(或者类)的 signature,以及对 signature 的说明是这个产品的 UI。

假如你如果打开一个应用,一个个操作按钮是干什么的都不知道,总和你期望的效果不同,你是不是特别想跳起来骂娘。

4)当你写一段代码时,连带着要改很多代码

当这个场景发生的时候,代码的味道相当糟糕,意味着不仅代码本身有问题,相关代码的设计甚至架构也有很大的问题。如果没有一定功底的程序员,重构这样的代码会比较费劲。

3.2 严格自律与他律

稍微大一点的软件项目是多人一起合作完成的。

与人合作,我们要坚信两点:

  • 人天性都是懒惰的,有捷径的话,绝不规规矩矩走大道;

  • 人都会受到 role model 或者社区的感染,如果已有的代码库形成了一个良好的氛围,新加入的人有一种融入已有体系的紧迫感。

开源项目其实可以给我们很多启发,看看那些著名的开源项目,很多参与其中的人在他们各自的公司里都未必有这么好的习惯,但在开源项目中,项目本身的检测和社区带来的压力会让它们自律。

整个过程和代码重构看上去没什么关系,但处处要求程序员重构代码以达到比较高的标准。相信我,这么做即便大家开始不适,等渐渐建立信心之后,会自我追求更高质量的代码。

4f24f086fc99279a754f86855de86640.jpeg

4、更应该注意的点

在你决定重构或彻底重写之前,你要先做好几件事:

  1. 让公司的技术负责人以及尽可能多的领导知道目前的状况。

  2. 要让他们清楚重构和彻底重写分别面临哪些困难,如果失败会面临什么境况。

  3. 你只给出意见,一定要让领导做出决定。留下可以追溯的证据,例如邮件或会议记录。

往往技术人员都比较单纯,都是纯粹从技术的角度考虑问题解决问题,很少考虑“政治”因素。

上面三点做到位,干不成,和你没多大关系;干成了,成绩比你想象的大。

上面三点做不到位,干成了,领导认为很正常;干不成,你自己也只好灰溜溜跑路。

要注意,很多时候,技术问题在技术之外花费的功夫更大。

5、总结

说了那么多,结论其实只有两条,作为程序员:

⊱ 不要奢望其他人会写出高质量的代码

⊱ 不要以为自己写出来的是高质量的代码

不写代码的人认为应该重构,重构很简单,无论新人还是老人都有责任做重构。

写代码老手认为应该迟早应该重构,重构很难,现在凑合用,这事别落在我头上。

写代码的新手认为不出bug就谢天谢地了,我也不知道怎么重构。

其实写好代码是很难

与写出烂代码不同的是,想写出好代码有很多前提:

✔ 理解要开发的功能需求。

✔ 了解程序的运行原理。

✔ 做出合理的抽象。

✔ 组织复杂的逻辑。

✔ 对自己开发效率的正确估算。

✔ 持续不断的练习。

写出好代码的方法论很多,但我认为写出好代码的核心反而是听起来非常low的“持续不断的练习”。

0fe29e3d34251e598d8b0113afb04422.jpeg


往期热文推荐:

  • 太强了,全面解析缓存应用经典问题

  • 如何把团队带成一盘散沙?

  • MD5 到底算不算一种加密算法?

关注公众号,免费领学习资料

如果您觉得还不错,欢迎关注和转发~     

f15072b901a8b5a41f957b3ce2a69d73.png

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

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

相关文章

小年 —— 送日历福利啦!(acwing)

acwing每日一题集日历除夕夜瓜分10000ac币啦! 手慢就没了┗|`O′|┛ 嗷~~ 上次在acwing上面留言送日历,结果送着送着,连老本都给送没了,这波集齐了把其他的也给发出来了 AcWing【集日历瓜分10000AC币活动】赠送1月日历…

基于Java SSM springboot健身管理系统设计和实现

基于Java SSM springboot健身管理系统设计和实现 博主介绍:5年java开发经验,专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码联…

Uniswap v3 详解(四):交易手续费

以普通用户的视角来看,对比 Uniswap v2,Uniswap v3 在手续费方面做了如下改动: 添加流动性时,手续费可以有 3个级别供选择:0.05%, 0.3% 和 1%,未来可以通过治理加入更多可选的手续费率Uniswap v2 中手续费…

《啊哈算法》第三章--枚举很暴力

从无到有学算法(看漫画学算法) (๑•̀ㅂ•́)و✧ 爱要坦荡荡 - 萧潇 - 单曲 - 网易云音乐 一,坑爹的奥数 枚举算法又叫穷举算法,非常的暴力,它的基本思想是“有序地去尝试每一种可能” 题目1 □3 x 6528 3□ x …

【JavaEE】网络初识之网络通信基础

✨哈喽,进来的小伙伴们,你们好耶!✨ 🛰️🛰️系列专栏:【JavaEE】 ✈️✈️本篇内容:网络初识之网络通信基础。 🚀🚀代码存放仓库gitee:JavaEE初阶代码存放! ⛵⛵作者简介…

Uniswap v3 详解(二):创建交易对/提供流动性

前文已经说过 Uniswap v3 的代码架构。一般来说,用户的操作都是从 uniswap-v3-periphery 中的合约开始。 创建交易对 创建交易对的调用流程如下: 用户首先调用 NonfungiblePositionManager 合约的 createAndInitializePoolIfNecessary 方法创建交易对&…

【软件测试】软件测试分类

1. 按照测试对象划分 界面测试 界面测试(简称UI测试),测试用户界面的功能模块的布局是否合理、整体风格是否一致、各个控件的放置位置是 否符合客户使用习惯,此外还要测试界面操作便捷性、导航简单易懂性,页面元素的可用性&…

U3751频谱分析仪

18320918653 U3751 频谱分析仪爱德万U3751特点: 频率范围:9kHz~8GHz 大输入电平:30dBm RBW:300Hz~3MHz 体积小,重量轻(5.6公斤),测量速度快 户外量测:W-CDMA&#xff…

unity日记10(无头盔开发vr XR Device Simulator操作说明| 模之屋模型导入unity )

目录 XR Device Simulator配置参考视频 XR Device Simulator操作方法参考视频 模之屋模型导入unity参考视频 XR Device Simulator操作方法(个人心得) 1.摄像机 1.摄像机左右移动 右键移动鼠标 2.摄像机前后移动 右键滚动滚轮 3.摄像…

Vulnhub之HACKABLE: II

1.信息收集 使用arp-scan扫描存活网段 使用nmap对192.168.239.126进行端口扫描,发现存在21(可匿名登录)、22、80端口 2.漏洞发现 使用ftp 192.168.239.126进行匿名登录,注意:anonymous都要小写。执行dir命令发现CALL.html 执行get CALL…

mybatis 的mapper接口没有实现类,那么他是如何工作的

一、mybatis使用动态代理要实现的功能。 mybatis 的底层实际上运行的还是ibatis,即需要把接口和xml映射翻译成 ibatis 需要的这种格式。 二、mapper接口的动态代理 当使用 sqlSession.getMapper 获取一个Mapper 的时候一般是使用 sqlSession 的 DefaultSqlSession…

K_A11_006 基于STM32等单片机采集雨水模块 串口与OLED0.96双显示

K_A11_006 基于STM32等单片机采集雨水模块 串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:四、部分代码说明1、接线说明1.1、STC89C52RC雨水模块1.2、STM32F103C8T6雨水模块五、基础知识学习与相关资料下载六、视频…

电脑开机找不到启动设备怎么办?

如果你的电脑弹出错误消息并提示“找不到启动的设备”,不用担心,本文将告诉你5种不同的方法,可以轻松修复无可引导的设备的问题!“找不到启动设备”是什么意思?可引导设备(又称启动设备)是一种存…

Vue.js学习笔记

vue.js学习笔记 Vue.js 是一款流行的 JavaScript 前端框架,Vue 所关注的核心是 MVC 模式中的视图层,它也方便地获取数据更新,实现视图与模型的交互。 1.创建代码片段 声明式渲染:Vue.js 的核心是一个允许采用简洁的模板语法来声…

kafka开kerberos认证报错the client is being asked for a password

Kafka kerberos认证错误记录TOC kafka开发调试 kerberos认证错误记录 背景 kafka 开发调试,开 kerberos情况下遇到的错误。 错误日志 Could not login: the client is being asked for a password, but the Kafka client code does not currently support obta…

隐私计算主流技术

隐私计算目前主流的技术路线有三种:多方安全计算、联邦学习和TEE。 1. MPC多方安全计算 百万富翁问题: 两个富翁,分别为张三和李四,他们自己都清楚自己有几千万财产即他们心里清楚 1~10中的一个数(代表自己千万级的财富)。他们想知道到底谁的数更大一些。 1.1 MPC定义 …

【博学谷学习记录】大数据课程-学习第三周总结

1. 大数据课程导论 数据分析的前提是有数据,数据存储的目的是支撑数据分析。究竟怎么去存储庞大的数据量,是开展数据分析的企业在当下面临的一个问题。传统的数据存储模式存储容量是有大小限制或者空间局限限制的,怎么去设计出一个可以支撑大…

【UE4 第一人称射击游戏】49-僵尸攻击动画

上一篇:【UE4 第一人称射击游戏】48-僵尸死亡设置本篇效果:可以看到僵尸在移动到玩家面前会从移动状态转为攻击状态,播放相应的攻击动画。步骤:打开“SimpleAI”,删除所有和“Character看见pawn时”、“AI随机移动”的…

动态规划算法刷题笔记【背包问题】

01背包问题 dp[i-1][j]指没纳入当前物品,dp[i-1][j-ci]wi指纳入当前物品,并且是和j-ci体积下的价值作和 滚动数组优化空间复杂度 [NOIP2005 普及组] 采药 辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜…

基于jsp+mysql+Spring的Springboot旅游网站管理系统设计和实现

基于jspmysqlSpring的Springboot旅游网站管理系统设计和实现 博主介绍:5年java开发经验,专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末…