理论篇|如何避免写出面条代码?_资讯推荐

阿里开发者 2023-05-17 18:17:19

点击链接阅读原文,获取更多技术内容:


(相关资料图)

本文是“面条代码系列”文章的第一篇,在这个系列里,我将从理论开始,再通过实践和大家一起来探讨如何才能写好代码。

作者 | 陆争辉(剡溪)

来源 | 阿里开发者公众号

面条代码系列文章目的

一直以来有一个问题困扰着我,大家好像都在不断的批判面条代码,但不知不觉中,每个人又不停的在写着面条代码,为什么?随着与越来越多的人沟通,我慢慢了解到,这其实是一个非常底层的问题,是一个对什么是好代码的认知的问题,所以要解决面条代码的问题,还是要从什么是好代码着手。

我期望通过本文,能颠覆你对好代码的认知,让你能从认知上有一个转变,“哥白尼式的转变”,什么意思呢?

你试想一下,当你现在回过头去看“地心说”时,你会有什么想法?而在之前一段很久很久的时间里,人们一直是坚信着地球才是宇宙的中心啊!当你理解了“日心说”以后,就再也回不去了,你已经没有办法再回到“地心说”了,并不是以前的人傻,而是你的认知发生了改变,一种不可逆的改变。因此,今天我试图从“什么是好代码”的认知讲起,期望能刷新你对好代码的认识,从而解决“面条代码’的问题。

什么是好代码

什么是好代码?我相信每个人心中都会有自己的答案,比如抽象层度、可扩展、可读性、是否符合设计模式等等,好代码的维度有很多,这些都没有错,今天我想从另一个维度来聊聊什么是好代码。

先说一个东西“星盘”,星盘是古代天文学家用来进行天文测量的仪器,通过转动星盘,可以模拟各天体的运动,从而预测太阳、月亮、金星、火星等天体在宇宙中的位置。星盘是天空模型的机械实现。通过星盘这个模型完整的呈现了星空中各星体的运行。在这个星盘中,沉淀了大量对于星体运行轨迹的知识,这些知识都融合进了星盘这个模型中。

而我们的代码是把我们运行在线下的日常业务,通过软件模型呈现到了我们的系统中,同样线下的业务中含有大量的业务知识,这些业务知识有时候是一个行业几十年的沉淀。如果我们的代码只是实现了功能,但没有与业务知识相匹配的模型,虽然功能实现了,但无法承载海量的业务知识,随着业务不断的衍进,必然会让线下业务与线上的系统脱节,从业务到系统的翻译成本越来越大,系统对业务的表达力越来越弱,就算一个小需求,从业务到产品,再到技术和测试,整个沟通成本也会很大。这时,我们就会说这个系统的代码太烂了,已经无法维护了。

因此,一个小小的星盘,完整的阐释了“什么是好代码”,好代码一定是能够完整的表达业务,能够把现实中的业务反映在我们的系统中。

到这里,我相信我们已经有目标了,如何才能写出像星盘一样的代码?我们先从一段面条代码开始。

面条代码的由来

面条代码(spaghetti code)是指非结构化和难以维护的源代码,要了解面条代码,我们先从下面的一个需求开始。

人员签到的需求:* 当签到时间>班次开始时间N分钟后,签到状态为迟到* N根据不同的业务可以灵活配置,比如:门店为5,配送为0

根据上面的需求,再来看一下我们的实现代码:

public void 人员签到(班次ID,人员ID) {    班次 = 班次Repo.获取班次(班次ID)    迟到可容忍时间 = 配置服务.获取可容忍时间(业务域);    签到状态 = null;    if( 签到时间 >(班次.开始时间 +迟到可容忍时间)) {      签到状态 = 迟到;    } else {      签到状态 = 正常;    }    //更新数据库状态 }

看完上面的实现代码,大家想一下,如果让你来写,你会怎么写呢?如果大家没有看出问题来,那很抱歉,我可以说大家平时就是在写面条代码。

上面的代码有两个问题:

迟到可容忍时间 = 配置服务.获取可容忍时间(业务域);

问题一:在签到方法内需要去查询配置服务,我相信这样的场景会出现在我们大量的方法中,有时候一个操作需要查询大量的其它服务来准备数据,慢慢的我们的方法会越来越长,即便我们可以把这些查询封装在一个方法中,但其实不解决实质性的问题。

if( 签到时间 >(班次.开始时间 +迟到可容忍时间)) {      签到状态 = 迟到;    } else {      签到状态 = 正常;    }

问题二:签到的业务逻辑揉合在签到方法中,形成了面向过程式的代码片段,随着业务的不断变化,签到方法有可能会越来越复杂。

这两个问题是所有面条代码中最典型的例子,问题一和问题二在复杂的现实业务中,可以演变成庞然大物,有时为了做某个操作,我们可能需要写上百行的代码来准备数据,有时一个复杂的业务逻辑,我们也可能会写上上百行代码。如果能解决上面的两个问题,我们就能在很大层度上解决面条代码的问题,接下来,我们来看看怎么来解决?

如何解决面条代码的问题

其实你并不孤单,关于上面的面条代码代码早在2004年就已经被人提出来了,要解决这个问题,我们需要引入三个模式: 值对象(Value Object) 无副作用方法(Side-Effect-Free Function) 语义化接口(Intention-Revealing Interface)

模式一:值对象(Value Object)

我们从一个灵魂拷问开始,在问题一中,“迟到可容忍时间”是可以按不同的业务配置的,那在处理迟到时,当然要从一个配置服务中去获取啊,感觉没毛病。真的是这样吗?

在上面代码中,我们有一个“班次”模型,除了入参“签到时间”外,为什么我们还需要模型之外的数据?大家有没有想过,是不是我们的模型有问题?既然系统要反应真实的业务,那我们回到现实的业务中,当班次安排下去以后,“迟到可容忍时间”还会有变化吗?今天“迟到可容忍时间”是5分钟,明天是10分钟,会这样吗?当然不是,当一个班次安排下去后,“迟到可容忍时间”必然是已经确定了的,如果真的要发生变化,业务也会在班次安排之前,提前通知到大家。因此,当班次被创建出来时,“迟到可容忍时间”就已经确定了,而不是当发生签到时,再去获取“迟到可容忍时间”。

阿里云开发者社区,千万开发者的选择。百万精品技术内容、千节免费系统课程、丰富的体验场景、活跃的社群活动、行业专家分享交流,尽在:

标签:

广告

Copyright ?   2015-2023 非洲商场网版权所有  备案号:沪ICP备2022005074号-8   联系邮箱:58 55 97 3@qq.com