你写的代码就是你的犯罪证据


prtyaa
prtyaa 2023-12-25 13:41:47 65711
分类专栏: 资讯

最近我工作的主要内容,是在和别人结对编程,以对一个大型的遗留系统项目进行重构。

过程中,我发现一个特别有意思的东西,我重构了很多的 if 语句。从这些 if 语句里,大抵是映射出了业务的变化。于是,我便想写一篇文章来记录一下相关的心得。

 

你写的 if 就是你的犯罪证据

业务的复杂性,导致了架构的复杂性。在这些代码故事里,发生得最多的地方就是 if 语句。所以,你可以从大部分的 if 语句里,看到一些代码上的坏味道。

业务条件复杂

你先写了一个 if 语句里面只有一个条件,没问题。但是后来的人,又加了一个条件,因为业务上确实需要这么做。于是,后来,又不得加了一个if 语句,导致了这个条件变得更加复杂。

if (isCondition && isNotASwitchCase && .... && ....) {
}

所以,完了,这些代码越来越难以维护。

于是,我们应对于这类条件判断,有两种做法:提取变量提取方法。当你的判断条件是一个方法的时候,你可以想象一下它的架构是多么的复杂。

难以阅读的字符串判断

开始的人加了一个简单的条件判断,因为当时真的只有这么一种业务场景。你又不能过度设计,成一个 switch-case。但是,后来又多了好多个场景。

if (aCondition == "A") {
} else if (bCondition == "B") {

} 

更不要提有人在每个 if 里写一个: if (myString.toUpperCase().equals(myOtherString.toUpperCase()))

针对于有限的 if 语句来说,可以转为 switch case(在 IDEA 里只需要 alt + enter 就可以自动完成)。

随着时间的推移我们的条件越来越复杂,我们的 if 语句会越来越复杂。

多层嵌套 if 语句

随着 if 条件进一步扩大化,我们的条件语句就变成了一个多层嵌套的循环语句。每多一层嵌套代码复杂度就 * 2,它的阅读难度就越来越大。于是乎:

if (condition) {
 if (blabla) {
 ...
 }
}

面对这一类 if 条件语句,我们能所做的就是:

  • 提供方法
  • 反转 if 语句

诸如于:

if (!condition) {return}; // 为了演示方便
if(blabla){...}

又或者是诸如于三元表达式,不过我讨厌难以阅读的三元表达式——但是,只是 true 和 false 的情况下,还是相当不错的。

复杂的 if 块内逻辑

当业务进一步复杂化的时候,我们的 if 条件里就充斥着各种各样的逻辑。

if (conditionA) {
 blablaA();
 blaA(blabla).blabla();
}

我们的 if 方法随之变得越来越长,于是尝试去抽成一个方法。但是,当你又遇到一个新的场景时,你又加了一个 if 语句。后来,又又加了一个 if 语句。你才发现说,『咦,不对,这些 If 语句违反了开闭原则』。

于是,你尝试把代码重构成多态以替换 if 语句。

你开心的话,还可以转为 Factory + Strategy。

你开心的话,你也可以将它转为 HashMap 。

但是,在你写下第一个 if 的时候,你并不知道它会变成什么样的。所以,不要提前去把它转为这么复杂的架构。

上帝 if

如果你的业务场景真的超级复杂,那么你可能会看到一个非常长的 if 代码。它可能有几十个条件,有几百行到几千行的规模。

那么,你可以尝试使用注册表模式 + 注解,通过反射的方式来重构你的 if 语句。

重构

在你进一步修改代码之前,让我们来又双叕明确一下什么叫重构

重构(Refactoring)就是通过调整程序代码改善软件的质量、性能,使其程序的设计模式和架构更趋合理,提高软件的扩展性和维护性。

换句话来说,重构只是在改善现有的代码,使其更易于阅读,换句话来说就是:Clean Code。而当我们说整洁的代码(Clean Code),说的是易于理解、修改和测试的。易于理解和修改意味着:

  • 易于理解整个系统的架构
  • 易于理解整个应用程序的执行流程
  • 易于理解不同对象如何相互协作
  • 易于理解理解每种方法的作用
  • 易于理解每个表达式和变量的目的是什么

而易于理解的前提便是能让每个团队成员快速理解。(PS:当然了,若是有些人智商不够或者经验不够,他/她需要去需要去增强这方面的能力)。这便意味着,出于这样的目的,你不能编写过于抽象、简练的逻辑。而你又不能写得过于繁琐,充满大量地无用字符。

若是想使代码易于测试,则要先使代码可测试。而在这没有测试之前,我们是难以对代码进行大规模重构。所以,我们就陷入了一个死循环,没有测试,测试不了,没法重构。

WHY

等等,那我们为什么要进行重构呢?为了 ¥¥¥¥¥¥¥$$$$$$$$$ => 快速发布软件。

当软件是一个产品而不是一个项目的时候,我们就需要不断发布新功能,以满足客户的要求。而为了快速发布应用,我们需要让每次的改动最小,测试最少,才能实现快速发布。基于这样一个目标,我们会发现我们的诸多实践都是以此为出发点的。比如说,我们采用插件化、微服务化、组件化的方式,都是为了将软件的改动变小,这样一来,就减少了相应部分的测试工作,从某种意义上来说,就加快了软件发布的流程,从而更好的实现业务价值。因此,我们的第一步就是使二进制改动最小。而要做到二进制改动最小,那么我们就要做到高内聚、低耦合

因此,不论是在编程还是在设计架构的时候,我们都要尽量满足 SOLID 五项原则中的:

  • 单一职责原则:它规定一个类应该只有一个发生变化的原因。
  • 开闭原则:软件中的对象应该对于扩展是开放的,但是对于修改是封闭的

回到问题上

既然,我们都已经知道了,如何去重构,如何用设计模式来解决问题。那么,我们会让我们的代码变得更好吗?不会,因为在流水线式的生产里,每个人都能找到合理的理由。

我们日常开发的模式是:红-绿-重构。而因为时间的原因,我们少去了重构这一步。

上吊绳驱动开发

在上吊绳(deadline)的驱动下,我写了一这篇文章。尽管预先写好了文章的大纲,但是有很多字是打错的。

而对于真实的业务开发来说,要事先设计好相关功能的架构,意味着你得有充足的时间。这样一来说,你在大的方面上才不会犯错。可是呢,你真的有那么多的时间可以设计吗?你今天加的班,还好吗?

代码所有权

改动了你的代码,我就要负责。所以,我不去修改别人的代码。

惧怕修改

没有测试,难以理解代码背后的业务原因。外加之组织文化,导致的沟通障碍;又或者是大家都很忙,没人愿意解释/回顾一下这一块的代码。

能力不够

对,大部分的问题本质都是人的问题。

因为你只需要按下 IDEA 的快捷键,就能完成上面的大部分重构工作。当然了,需要有技巧的按,而不是像 Monkey 一样弹钢琴。

网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。

本文链接:https://www.xckfsq.com/news/show.html?id=30299
赞同 0
评论 0 条
prtyaaL0
粉丝 1 发表 2554 + 关注 私信
上周热门
银河麒麟添加网络打印机时,出现“client-error-not-possible”错误提示  1447
银河麒麟打印带有图像的文档时出错  1364
银河麒麟添加打印机时,出现“server-error-internal-error”  1150
统信桌面专业版【如何查询系统安装时间】  1072
统信操作系统各版本介绍  1069
统信桌面专业版【全盘安装UOS系统】介绍  1027
麒麟系统也能完整体验微信啦!  984
统信【启动盘制作工具】使用介绍  626
统信桌面专业版【一个U盘做多个系统启动盘】的方法  574
信刻全自动档案蓝光光盘检测一体机  483
本周热议
我的信创开放社区兼职赚钱历程 40
今天你签到了吗? 27
信创开放社区邀请他人注册的具体步骤如下 15
如何玩转信创开放社区—从小白进阶到专家 15
方德桌面操作系统 14
我有15积分有什么用? 13
用抖音玩法闯信创开放社区——用平台宣传企业产品服务 13
如何让你先人一步获得悬赏问题信息?(创作者必看) 12
2024中国信创产业发展大会暨中国信息科技创新与应用博览会 9
中央国家机关政府采购中心:应当将CPU、操作系统符合安全可靠测评要求纳入采购需求 8

添加我为好友,拉您入交流群!

请使用微信扫一扫!