最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

理論篇|如何避免寫出面條代碼

2023-06-26 17:20 作者:阿里云  | 我要投稿

面條代碼系列文章目的

一直以來有一個(gè)問題困擾著我,大家好像都在不斷的批判面條代碼,但不知不覺中,每個(gè)人又不停的在寫著面條代碼,為什么?隨著與越來越多的人溝通,我慢慢了解到,這其實(shí)是一個(gè)非常底層的問題,是一個(gè)對(duì)什么是好代碼的認(rèn)知的問題,所以要解決面條代碼的問題,還是要從什么是好代碼著手。

我期望通過本文,能顛覆你對(duì)好代碼的認(rèn)知,讓你能從認(rèn)知上有一個(gè)轉(zhuǎn)變,“哥白尼式的轉(zhuǎn)變”,什么意思呢?

你試想一下,當(dāng)你現(xiàn)在回過頭去看“地心說”時(shí),你會(huì)有什么想法?而在之前一段很久很久的時(shí)間里,人們一直是堅(jiān)信著地球才是宇宙的中心??!當(dāng)你理解了“日心說”以后,就再也回不去了,你已經(jīng)沒有辦法再回到“地心說”了,并不是以前的人傻,而是你的認(rèn)知發(fā)生了改變,一種不可逆的改變。因此,今天我試圖從“什么是好代碼”的認(rèn)知講起,期望能刷新你對(duì)好代碼的認(rèn)識(shí),從而解決“面條代碼’的問題。

什么是好代碼

什么是好代碼?我相信每個(gè)人心中都會(huì)有自己的答案,比如抽象層度、可擴(kuò)展、可讀性、是否符合設(shè)計(jì)模式等等,好代碼的維度有很多,這些都沒有錯(cuò),今天我想從另一個(gè)維度來聊聊什么是好代碼。

先說一個(gè)東西“星盤”,星盤是古代天文學(xué)家用來進(jìn)行天文測(cè)量的儀器,通過轉(zhuǎn)動(dòng)星盤,可以模擬各天體的運(yùn)動(dòng),從而預(yù)測(cè)太陽、月亮、金星、火星等天體在宇宙中的位置。星盤是天空模型的機(jī)械實(shí)現(xiàn)。通過星盤這個(gè)模型完整的呈現(xiàn)了星空中各星體的運(yùn)行。在這個(gè)星盤中,沉淀了大量對(duì)于星體運(yùn)行軌跡的知識(shí),這些知識(shí)都融合進(jìn)了星盤這個(gè)模型中。而我們的代碼是把我們運(yùn)行在線下的日常業(yè)務(wù),通過軟件模型呈現(xiàn)到了我們的系統(tǒng)中,同樣線下的業(yè)務(wù)中含有大量的業(yè)務(wù)知識(shí),這些業(yè)務(wù)知識(shí)有時(shí)候是一個(gè)行業(yè)幾十年的沉淀。如果我們的代碼只是實(shí)現(xiàn)了功能,但沒有與業(yè)務(wù)知識(shí)相匹配的模型,雖然功能實(shí)現(xiàn)了,但無法承載海量的業(yè)務(wù)知識(shí),隨著業(yè)務(wù)不斷的衍進(jìn),必然會(huì)讓線下業(yè)務(wù)與線上的系統(tǒng)脫節(jié),從業(yè)務(wù)到系統(tǒng)的翻譯成本越來越大,系統(tǒng)對(duì)業(yè)務(wù)的表達(dá)力越來越弱,就算一個(gè)小需求,從業(yè)務(wù)到產(chǎn)品,再到技術(shù)和測(cè)試,整個(gè)溝通成本也會(huì)很大。這時(shí),我們就會(huì)說這個(gè)系統(tǒng)的代碼太爛了,已經(jīng)無法維護(hù)了。

因此,一個(gè)小小的星盤,完整的闡釋了“什么是好代碼”,好代碼一定是能夠完整的表達(dá)業(yè)務(wù),能夠把現(xiàn)實(shí)中的業(yè)務(wù)反映在我們的系統(tǒng)中。

到這里,我相信我們已經(jīng)有目標(biāo)了,如何才能寫出像星盤一樣的代碼?我們先從一段面條代碼開始。

面條代碼的由來

面條代碼(spaghetti code)是指非結(jié)構(gòu)化和難以維護(hù)的源代碼,要了解面條代碼,我們先從下面的一個(gè)需求開始。


根據(jù)上面的需求,再來看一下我們的實(shí)現(xiàn)代碼:


看完上面的實(shí)現(xiàn)代碼,大家想一下,如果讓你來寫,你會(huì)怎么寫呢?如果大家沒有看出問題來,那很抱歉,我可以說大家平時(shí)就是在寫面條代碼。

上面的代碼有兩個(gè)問題:

問題一:在簽到方法內(nèi)需要去查詢配置服務(wù),我相信這樣的場(chǎng)景會(huì)出現(xiàn)在我們大量的方法中,有時(shí)候一個(gè)操作需要查詢大量的其它服務(wù)來準(zhǔn)備數(shù)據(jù),慢慢的我們的方法會(huì)越來越長,即便我們可以把這些查詢封裝在一個(gè)方法中,但其實(shí)不解決實(shí)質(zhì)性的問題。

問題二:簽到的業(yè)務(wù)邏輯揉合在簽到方法中,形成了面向過程式的代碼片段,隨著業(yè)務(wù)的不斷變化,簽到方法有可能會(huì)越來越復(fù)雜。

這兩個(gè)問題是所有面條代碼中最典型的例子,問題一和問題二在復(fù)雜的現(xiàn)實(shí)業(yè)務(wù)中,可以演變成龐然大物,有時(shí)為了做某個(gè)操作,我們可能需要寫上百行的代碼來準(zhǔn)備數(shù)據(jù),有時(shí)一個(gè)復(fù)雜的業(yè)務(wù)邏輯,我們也可能會(huì)寫上上百行代碼。如果能解決上面的兩個(gè)問題,我們就能在很大層度上解決面條代碼的問題,接下來,我們來看看怎么來解決?

如何解決面條代碼的問題

其實(shí)你并不孤單,關(guān)于上面的面條代碼代碼早在2004年就已經(jīng)被人提出來了,要解決這個(gè)問題,我們需要引入三個(gè)模式:
值對(duì)象(Value Object)
無副作用方法(Side-Effect-Free Function)
語義化接口(Intention-Revealing Interface)

模式一:值對(duì)象(Value Object)

我們從一個(gè)靈魂拷問開始,在問題一中,“遲到可容忍時(shí)間”是可以按不同的業(yè)務(wù)配置的,那在處理遲到時(shí),當(dāng)然要從一個(gè)配置服務(wù)中去獲取啊,感覺沒毛病。真的是這樣嗎?

在上面代碼中,我們有一個(gè)“班次”模型,除了入?yún)ⅰ昂灥綍r(shí)間”外,為什么我們還需要模型之外的數(shù)據(jù)?大家有沒有想過,是不是我們的模型有問題?既然系統(tǒng)要反應(yīng)真實(shí)的業(yè)務(wù),那我們回到現(xiàn)實(shí)的業(yè)務(wù)中,當(dāng)班次安排下去以后,“遲到可容忍時(shí)間”還會(huì)有變化嗎?今天“遲到可容忍時(shí)間”是5分鐘,明天是10分鐘,會(huì)這樣嗎?當(dāng)然不是,當(dāng)一個(gè)班次安排下去后,“遲到可容忍時(shí)間”必然是已經(jīng)確定了的,如果真的要發(fā)生變化,業(yè)務(wù)也會(huì)在班次安排之前,提前通知到大家。因此,當(dāng)班次被創(chuàng)建出來時(shí),“遲到可容忍時(shí)間”就已經(jīng)確定了,而不是當(dāng)發(fā)生簽到時(shí),再去獲取“遲到可容忍時(shí)間”。

當(dāng)然,除了“遲到可容忍時(shí)間”外,對(duì)于班次,我們其實(shí)還有很多這樣的配置,我們把這些配置抽象成一個(gè)對(duì)象“班次配置”,然后在班次生成的時(shí)候,把這些數(shù)據(jù)放進(jìn)去,在班次持久化時(shí),再把班次配置冗余到班次對(duì)象上?!鞍啻闻渲谩睂?duì)象就是一個(gè)值對(duì)象。

再回過頭來看問題一,因?yàn)槲覀儗?duì)業(yè)務(wù)的理解不夠深入,沒有把業(yè)務(wù)完全的反映到我們的模型和代碼上,導(dǎo)致了每次簽到,都需要去查詢配置服務(wù)。再來看我們的解決方案,“班次”對(duì)象上冗余了“班次配置”,我們?cè)僖膊恍枰诤灥綍r(shí),去查詢配置服務(wù)了,班次本身就能回答本次簽到是否遲到了。

那我們是否就能把“考勤狀態(tài)判定”這件事交給“班次”呢?我們進(jìn)入下一個(gè)話題,無副作用方法。

模式二:無副作用方法(Side-Effect-Free Function)

“副作用”原意是指“意外的結(jié)果”,而在這里無副作用方法(Side-Effect-Free Function)是指方法被調(diào)用后,不會(huì)對(duì)系統(tǒng)狀態(tài)產(chǎn)生任何影響。那很多同學(xué)就會(huì)覺得自己之前寫的service全都是無副作用方法,真的是這樣嗎?如果從定義上來看,沒錯(cuò),是的。但是我今天想和大家聊的不是一個(gè)方法,而是一種架構(gòu),這有什么區(qū)別嗎?回答這個(gè)問題前我先提一個(gè)問題:


很多時(shí)候,一個(gè)看似“無副作用”的方法,調(diào)用了方法A,方法A再調(diào)用方法B,再調(diào)用方法C,方法D,方法E,最后在方法E中更新了一下數(shù)據(jù)庫狀態(tài)。所以你有什么底氣回答上面的問題?憑什么?可能有讀者覺得我是在抬杠,當(dāng)然不是,我是在講一個(gè)嚴(yán)肅的架構(gòu)問題。好的架構(gòu),是能讓你的系統(tǒng)中能產(chǎn)生一個(gè)像“重力”一樣的東西,就像建筑學(xué)中的“重力”你必須得去遵守它。好的軟件架構(gòu),也是一樣的,能夠創(chuàng)造出一個(gè)像“重力”一樣的規(guī)則,讓你不得不遵守它。請(qǐng)看下面的定義:



值對(duì)象本身從嚴(yán)格意義上來說是一個(gè)不可變對(duì)象,我們只能替換它,而不能改變它。同時(shí)在值對(duì)象當(dāng)中,我們是無法訪問其它service的。基于這兩個(gè)前提,放在值對(duì)象上的“無副作用”方法,就是完完全全可被信任的方法,這樣的方法是最好的資產(chǎn),可以被其它同學(xué)放心的復(fù)用。

接下來讓我們繼續(xù)回到上面的代碼,我們要把考勤狀態(tài)判定抽成一個(gè)“無副作用”方法,同時(shí)還要把班次變成一個(gè)值對(duì)象,看下面班次的示例代碼:

上面代碼中的方法就是長在“值對(duì)象”上的一個(gè)“無副作用”方法,這樣的方法是明確抽象了業(yè)務(wù)邏輯的方法,是最好的可復(fù)用資產(chǎn)。

當(dāng)然,在我們抽象方法時(shí),需要為抽象出來的方法取一個(gè)名字,而取名通常會(huì)難倒一大批“高手”,其實(shí)我們完全錯(cuò)了,不是你不會(huì)取名字,而是你的架構(gòu)有問題,接下來我們來聊最后一個(gè)問題。


模式三:語義化接口(Intention-Revealing Interface)

一個(gè)容易被重用的方法或類至少要滿足下面這個(gè)條件:

如何給方法取名字?如果你覺得是因?yàn)槟阌⑽牟缓脤?dǎo)致的取不出好名字,那你又錯(cuò)了。取名字和英文好壞沒關(guān)系,因?yàn)槲铱梢院茇?fù)責(zé)任的和你說,就算你用中文給方法取名字,你還是無法通過名稱來表達(dá)出方法真正做的事情。因?yàn)檫@是人與人之間的共識(shí)問題,你不可能通過一個(gè)名稱來和別人達(dá)成共識(shí),達(dá)成共識(shí)是一個(gè)很復(fù)雜的過程,通常要經(jīng)過溝通、確認(rèn),再溝通再確認(rèn),多次溝通后,人與人之間才能達(dá)成某種共識(shí)。在寫代碼時(shí),我們不可能針對(duì)每一個(gè)我需要重用的方法,找寫這個(gè)方法的人一遍又一遍的溝通和確認(rèn),那還不如我自己看一下方法里面的邏輯,或者自己重寫一個(gè),這才是我們今天面臨的真正問題,因?yàn)闊o法達(dá)成共識(shí),導(dǎo)致代碼很難被重用。

要解決這個(gè)問題,我們要引入第三個(gè)模式,語義化接口(Intention-Revealing Interface),語義化接口是指用業(yè)務(wù)正在使用的語言來為我為接口或方法命名,而業(yè)務(wù)正在使用的語言,我們?cè)贛RD、PRD階段已經(jīng)為此達(dá)成過共識(shí)了,這是業(yè)務(wù)、產(chǎn)品、開發(fā)和測(cè)試都能理解的,你也可以把它理解成DDD中的“通用語言”。如果領(lǐng)域?qū)拥哪P秃湍P蜕系姆椒ǘ际恰罢Z義化”的,那我相信,這樣的代碼是可被理解,并且沒有歧義的,使用方可以去放心使用的。

最后放上修改前后的示意代碼:

總結(jié)

本文的目的是期望能刷新你對(duì)好代碼的認(rèn)識(shí),從而解決“面條代碼’的問題。我們先通過定義什么是“好代碼”,讓大家先從認(rèn)知上理解,不是“面條代碼”有問題,而是我們自己的認(rèn)知有問題。當(dāng)我們認(rèn)可了“好代碼”的標(biāo)準(zhǔn)后,通過一個(gè)例子,借助三個(gè)模式,完成了代碼的重構(gòu),這三個(gè)模式分別是:

當(dāng)然,這是一個(gè)非常簡單的例子,我在這里只是通過這個(gè)例子表達(dá)我的觀點(diǎn),實(shí)際項(xiàng)目中的需求比這復(fù)雜的多的多的多,這是這個(gè)系列的第一篇,理論篇,后面我將會(huì)通過實(shí)際的例子,更加詳細(xì)的說明我們是如何把這個(gè)理論運(yùn)用到我們?nèi)粘5拇a中的。

擴(kuò)展閱讀:領(lǐng)域驅(qū)動(dòng)設(shè)計(jì):https://book.douban.com/subject/26819666


理論篇|如何避免寫出面條代碼的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
九江县| 泰来县| 高安市| 福建省| 宁河县| 贵定县| 香港| 治多县| 扎兰屯市| 贵溪市| 巴林右旗| 鄂托克前旗| 曲麻莱县| 天祝| 壶关县| 原平市| 奉贤区| 政和县| 濮阳市| 保康县| 南城县| 铜陵市| 德庆县| 许昌市| 昌邑市| 长丰县| 湖州市| 黑龙江省| 吉林市| 杭锦后旗| 炉霍县| 宁远县| 民县| 达拉特旗| 文昌市| 涡阳县| 博野县| 双柏县| 温州市| 哈密市| 南漳县|