专栏首页phodal你写的代码就是你的犯罪证据

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

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

过程中,我发现一个特别有意思的东西,我重构了很多的 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 一样弹钢琴。

结论

开心就好。

本文分享自微信公众号 - phodal(phodal-weixin),作者:Phodal

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 如何运营一个开源项目并取得较大影响力?

    开源需要一些营销的技巧,这些技巧可以帮你吸引关注。举个简单的例子,司徒正美的 avalon 框架出身得很早,也 MV* 方面也做得很不错,但是在 marketi...

    Phodal
  • RePractise前端篇: 前端演进史

    细细整理了过去接触过的那些前端技术,发现前端演进是段特别有意思的历史。人们总是在过去就做出未来需要的框架,而现在流行的是过去的过去发明过的。如,响应式设计不得不...

    Phodal
  • 重构的自动化

    这些日子里,由于项目的缘故,我又双叕开始学着造轮子了。故事的开始是代码的不规范堆砌,导致软件大楼摇摇欲坠;故事的终点是,重新唤醒程序员对匠艺的追求。而故事的中间...

    Phodal
  • R语言写2048游戏

           2048 是一款益智游戏,只需要用方向键让两两相同的数字碰撞就会诞生一个翻倍的数字,初始数字由 2 或者 4 构成,直到游戏界面全部被填满,游戏结...

    用户1680321
  • R条件语句

    但如果你有一长串 if 语句,那么就要考虑重写了。重写的一种方法是使用 switch() 函数, 它先对第一个参数求值,然后按照名称或位置在后面的参数列表中匹...

    生信编程日常
  • python条件执行

    mwangblog
  • 【python系统学习04】条件判断语句

    学过 js 的你,看到这个肯定小 case 吧!肯定第一时间得到答案,打印出“1”吧!

    xing.org1^
  • 计算机科学中的数学(一)

    数学函数三要素:定义域、对应法则、值域。 对应于编程语言中的函数:形式参数、函数主体(逻辑、计算规则)、返回值。

    城市中的游牧民族
  • 【趣解编程】条件语句if

    遇见if,就是走到了分岔路口,需要根据当前拥有的条件和环境,来决断到底要走哪一条路。

    一斤代码
  • 嘿~这里有一份超实用的 switch 教程,真的好想推荐给你

    在上次推文中介绍了关系运算符和条件运算符,今天介绍它们的好搭档,分支结构。如下图所示,左侧是顺序结构,右侧是分支结构

    谭庆波

扫码关注云+社区

领取腾讯云代金券