成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面向?qū)ο缶幊淌怯?jì)算機(jī)科學(xué)的最大錯(cuò)誤

開(kāi)發(fā) 前端
C++和Java可能是計(jì)算機(jī)科學(xué)中最嚴(yán)重的錯(cuò)誤。兩者都受到了OOP創(chuàng)始人Alan Kay本人以及其他許多著名計(jì)算機(jī)科學(xué)家的嚴(yán)厲批評(píng)。然而,C++和Java為最臭名昭著的編程范式--現(xiàn)代OOP鋪平了道路。

 [[385709]]

C++和Java可能是計(jì)算機(jī)科學(xué)中最嚴(yán)重的錯(cuò)誤。兩者都受到了OOP創(chuàng)始人Alan Kay本人以及其他許多著名計(jì)算機(jī)科學(xué)家的嚴(yán)厲批評(píng)。然而,C++和Java為最臭名昭著的編程范式--現(xiàn)代OOP鋪平了道路。

它的普及是非常不幸的,它對(duì)現(xiàn)代經(jīng)濟(jì)造成了極大的破壞,造成了數(shù)萬(wàn)億美元至數(shù)萬(wàn)億美元的間接損失。成千上萬(wàn)人的生命因OOP而喪失。在過(guò)去的三十年里,沒(méi)有一個(gè)行業(yè)不受潛伏的OO危機(jī)的影響,它就在我們眼前展開(kāi)。

為什么OOP如此危險(xiǎn)?讓我們找出答案。

想象一下,在一個(gè)美麗的周日下午,帶著家人出去兜風(fēng)。外面的天氣很好,陽(yáng)光明媚。你們所有人都進(jìn)入車內(nèi),走的是已經(jīng)開(kāi)過(guò)一百萬(wàn)次的同一條高速公路。

 

 

 

[[385710]]

 

然而這次卻有些不一樣了--車子一直不受控制地加速,即使你松開(kāi)油門踏板也是如此。剎車也不靈了,似乎失去了動(dòng)力。為了挽救局面,你鋌而走險(xiǎn),拉起了緊急剎車。這樣一來(lái),在你的車撞上路邊的路堤之前,就在路上留下了一個(gè)150英尺長(zhǎng)的滑痕。

聽(tīng)起來(lái)像一場(chǎng)噩夢(mèng)?然而這正是2007年9月讓-布克特在駕駛豐田凱美瑞時(shí)發(fā)生的事情。這并不是唯一的此類事件。這是眾多與所謂的“意外加速”有關(guān)的事件之一。“意外加速”已困擾豐田汽車十多年,造成近百人死亡。汽車制造商很快就將矛頭指向了“粘性踏板”、駕駛員失誤,甚至地板墊等方面。然而,一些專家早就懷疑可能是有問(wèn)題的軟件在作怪。

為了幫助解決這個(gè)問(wèn)題,請(qǐng)來(lái)了美國(guó)宇航局的軟件專家,結(jié)果一無(wú)所獲。直到幾年后,在調(diào)查Bookout事件的過(guò)程中,另一個(gè)軟件專家團(tuán)隊(duì)才找到了真兇。他們花了近18個(gè)月的時(shí)間來(lái)研究豐田的代碼,他們將豐田的代碼庫(kù)描述為“意大利面條代碼”——程序員的行話,意思是混亂的代碼。

軟件專家已經(jīng)演示了超過(guò)1000萬(wàn)種豐田軟件導(dǎo)致意外加速的方法。最終,豐田被迫召回了900多萬(wàn)輛汽車,并支付了超過(guò)30億美元的和解費(fèi)和罰款。

意大利面條代碼有問(wèn)題嗎?

 

 

[[385711]]

 

Photo by Andrea Piacquadio from Pexels

某些軟件故障造成的100條生命是太多了,真正令人恐懼的是,豐田代碼的問(wèn)題不是唯一的。

兩架波音737 Max飛機(jī)墜毀,造成346人死亡,損失超過(guò)600億美元。這一切都是因?yàn)橐粋€(gè)軟件bug, 100%肯定是意大利面條式代碼造成的。

意大利面條式的代碼困擾著世界上太多的代碼庫(kù)。飛機(jī)上的電腦,醫(yī)療設(shè)備,核電站運(yùn)行的代碼。

程序代碼不是為機(jī)器編寫的,而是為人類編寫的。正如馬丁·福勒(Martin Fowler)所說(shuō):“任何傻瓜都可以編寫計(jì)算機(jī)可以理解的代碼。好的程序員編寫人類可以理解的代碼。”

如果代碼不能運(yùn)行,那么它就是壞的。然而如果人們不能理解代碼,那么它就會(huì)被破壞。很快就會(huì)。

我們繞個(gè)彎子,說(shuō)說(shuō)人腦。人腦是世界上最強(qiáng)大的機(jī)器。然而,它也有自己的局限性。我們的工作記憶是有限的,人腦一次只能思考5件事情。這就意味著,程序代碼的編寫要以不壓垮人腦為前提。

意大利面條代碼使人腦無(wú)法理解代碼庫(kù)。這具有深遠(yuǎn)的影響--不可能看到某些改變是否會(huì)破壞其他東西,對(duì)缺陷的詳盡測(cè)試變得不可能。

是什么導(dǎo)致意大利面條代碼?

 

 

[[385712]]

 

Photo by Craig Adderley from Pexels

為什么代碼會(huì)隨著時(shí)間的推移變成意大利面條代碼?因?yàn)殪?-宇宙中的一切最終都會(huì)變得無(wú)序、混亂。就像電纜最終會(huì)變得糾纏不清一樣,我們的代碼最終也會(huì)變得糾纏不清。除非有足夠的約束條件。

為什么我們要在道路上限速?是的,有些人總會(huì)討厭它們,但它們可以防止我們撞死人。為什么我們要在馬路上設(shè)置標(biāo)線?為了防止人們走錯(cuò)路,防止事故的發(fā)生。

類似的方法在編程時(shí)完全有意義。這樣的約束不應(yīng)該讓人類程序員去實(shí)施。它們應(yīng)該由工具自動(dòng)執(zhí)行,或者最好由編程范式本身執(zhí)行。

為什么OOP是萬(wàn)惡之源?

 

 

[[385713]]

 

Photo by NeONBRAND on Unsplash

我們?nèi)绾螆?zhí)行足夠的約束以防止代碼變成意大利面條?兩個(gè)選擇--手動(dòng),或者自動(dòng)。手動(dòng)方式容易出錯(cuò),人總會(huì)出錯(cuò)。因此,自動(dòng)執(zhí)行這種約束是符合邏輯的。

不幸的是,OOP并不是我們一直在尋找的解決方案。它沒(méi)有提供任何約束來(lái)幫助解決代碼糾纏的問(wèn)題。人們可以精通各種OOP的最佳實(shí)踐,比如依賴注入、測(cè)試驅(qū)動(dòng)開(kāi)發(fā)、領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)等(確實(shí)有幫助)。然而,這些都不是編程范式本身所能強(qiáng)制執(zhí)行的(而且也沒(méi)有這樣的工具可以強(qiáng)制執(zhí)行最佳實(shí)踐)。

內(nèi)置的OOP功能都無(wú)助于防止意大利面條代碼——封裝只是將狀態(tài)隱藏并分散在程序中,這只會(huì)讓事情變得更糟。繼承性增加了更多的混亂,OOP多態(tài)性再次讓事情變得更加混亂——在運(yùn)行時(shí)不知道程序到底要走什么執(zhí)行路徑是沒(méi)有好處的,尤其是涉及到多級(jí)繼承的時(shí)候。

OOP進(jìn)一步加劇了意大利面條代碼的問(wèn)題

缺乏適當(dāng)?shù)募s束(以防止代碼變得混亂)不是OOP的唯一缺點(diǎn)。

在大多數(shù)面向?qū)ο蟮恼Z(yǔ)言中,默認(rèn)情況下所有內(nèi)容都是通過(guò)引用共享的。實(shí)際上把一個(gè)程序變成了一個(gè)巨大的全局狀態(tài)的blob,這與OOP的初衷直接沖突。OOP的創(chuàng)造者Alan Kay有生物學(xué)的背景,他有一個(gè)想法,就是想用一種類似生物細(xì)胞的方式來(lái)編寫計(jì)算機(jī)程序的語(yǔ)言(Simula),他想讓獨(dú)立的程序(細(xì)胞)通過(guò)互相發(fā)送消息來(lái)進(jìn)行交流。獨(dú)立程序的狀態(tài)絕不會(huì)與外界共享(封裝)。

Alan Kay從未打算讓“細(xì)胞”直接進(jìn)入其他細(xì)胞的內(nèi)部進(jìn)行改變。然而,這正是現(xiàn)代OOP中所發(fā)生的事情,因?yàn)樵诂F(xiàn)代OOP中,默認(rèn)情況下,所有東西都是通過(guò)引用來(lái)共享的。這也意味著,回歸變得不可避免。改變程序的一個(gè)部分往往會(huì)破壞其他地方的東西(這在其他編程范式,如函數(shù)式編程中就不那么常見(jiàn)了)。

我們可以清楚地看到,現(xiàn)代OOP存在著根本性的缺陷。它是每天工作中會(huì)折磨你的“怪物”,而且它還會(huì)在晚上纏著你。

讓我們來(lái)談?wù)効深A(yù)測(cè)性

 

 

[[385714]]

 

Photo by samsommer on Unsplash

意大利面代碼是個(gè)大問(wèn)題,面向?qū)ο蟮拇a特別容易意大利化。

意大利面條代碼使軟件無(wú)法維護(hù),然而這只是問(wèn)題的一部分。我們也希望軟件是可靠的。但這還不夠,軟件(或任何其他系統(tǒng))被期望是可預(yù)測(cè)的。

任何系統(tǒng)的用戶無(wú)論如何都應(yīng)該有同樣的可預(yù)測(cè)的體驗(yàn)。踩汽車油門踏板的結(jié)果總是汽車加速。按下剎車應(yīng)該總是導(dǎo)致汽車減速。用計(jì)算機(jī)科學(xué)的行話來(lái)說(shuō),我們希望汽車是確定性的。

汽車出現(xiàn)隨機(jī)行為是非常不可取的,比如油門無(wú)法加速,或者剎車無(wú)法制動(dòng)(豐田問(wèn)題),即使這樣的問(wèn)題在萬(wàn)億次中只出現(xiàn)一次。

然而大多數(shù)軟件工程師的心態(tài)是“軟件應(yīng)該足夠好,讓我們的客戶繼續(xù)使用”。我們真的不能做得更好嗎?當(dāng)然,我們可以,而且我們應(yīng)該做得更好!最好的開(kāi)始是解決我們方案的非確定性。

非確定性101

 

 

[[385715]]

 

在計(jì)算機(jī)科學(xué)中,非確定性算法是相對(duì)于確定性算法而言的,即使對(duì)于相同的輸入,也可以在不同的運(yùn)行中表現(xiàn)出不同的行為。

——維基百科關(guān)于非確定性算法的文章

如果上面維基百科上關(guān)于非確定性的引用你聽(tīng)起來(lái)不順耳,那是因?yàn)榉谴_定性沒(méi)有任何好處。我們來(lái)看看一個(gè)簡(jiǎn)單調(diào)用函數(shù)的代碼樣本。

 

  1. console.log( 'result', computea(2) ); 
  2. console.log( 'result', computea(2) ); 
  3. console.log( 'result', computea(2) ); 
  4.  
  5. // output
  6. // result 4 
  7. // result 4 
  8. // result 4 

我們不知道這個(gè)函數(shù)的作用,但似乎在給定相同輸入的情況下,這個(gè)函數(shù)總是返回相同的輸出。現(xiàn)在,讓我們看一下另一個(gè)示例,該示例調(diào)用另一個(gè)函數(shù) computeb:

 

  1. console.log( 'result', computeb(2) ); 
  2. console.log( 'result', computeb(2) ); 
  3. console.log( 'result', computeb(2) ); 
  4. console.log( 'result', computeb(2) ); 
  5.  
  6. // output
  7. // result 4 
  8. // result 4 
  9. // result 4 
  10. // result 2    <=  not good 

這次,函數(shù)為相同的輸入返回了不同的值。兩者之間有什么區(qū)別?前者的函數(shù)總是在給定相同的輸入的情況下產(chǎn)生相同的輸出,就像數(shù)學(xué)中的函數(shù)一樣。換句話說(shuō),函數(shù)是確定性的。后一個(gè)函數(shù)可能會(huì)產(chǎn)生預(yù)期值,但這是不保證的。或者換句話說(shuō),這個(gè)函數(shù)是不確定的。

是什么使函數(shù)具有確定性或不確定性?

  • 不依賴外部狀態(tài)的函數(shù)是100%確定性的。
  • 僅調(diào)用其他確定性函數(shù)的函數(shù)是確定性的。

 

  1. function computea(x) { 
  2.   return x * x; 
  3.  
  4. function computeb(x) { 
  5.   returnMath.random() < 0.9 
  6.           ? x * x 
  7.           : x; 

在上面的例子中,computea 是確定性的,在給定相同輸入的情況下,它總是會(huì)給出相同的輸出。因?yàn)樗妮敵鲋蝗Q于它的參數(shù) x 。

另一方面,computeb 是非確定性的,因?yàn)樗{(diào)用了另一個(gè)非確定性函數(shù) Math.random()。我們?cè)趺粗繫ath.random()是非確定性的?在內(nèi)部,它依賴于系統(tǒng)時(shí)間(外部狀態(tài))來(lái)計(jì)算隨機(jī)值。它也不接受任何參數(shù)--這是一個(gè)依賴于外部狀態(tài)的函數(shù)的致命漏洞。

確定性與可預(yù)測(cè)性有什么關(guān)系?確定性的代碼是可預(yù)測(cè)的代碼,非確定性代碼是不可預(yù)測(cè)的代碼。

從確定性到非確定性

我們來(lái)看看一個(gè)加法函數(shù):

 

  1. function add(a, b) { 
  2.   return a + b; 
  3. }; 

我們始終可以確定,給定 (2, 2) 的輸入,結(jié)果將始終等于 4。我們?cè)趺茨苓@么肯定呢?在大多數(shù)編程語(yǔ)言中,加法運(yùn)算都是在硬件上實(shí)現(xiàn)的,換句話說(shuō),CPU負(fù)責(zé)計(jì)算的結(jié)果要始終保持不變。除非我們處理的是浮點(diǎn)數(shù)的比較,(但這是另一回事,與非確定性問(wèn)題無(wú)關(guān))。現(xiàn)在,讓我們把重點(diǎn)放在整數(shù)上。硬件是非常可靠的,可以肯定的是,加法的結(jié)果永遠(yuǎn)是正確的。

現(xiàn)在,讓我們將值 2 裝箱:

 

  1. const box = value => ({ value }); 
  2.  
  3. const two = box(2); 
  4. const twoPrime = box(2); 
  5.  
  6. function add(a, b) { 
  7.   return a.value + b.value; 
  8.  
  9. console.log("2 + 2' == " + add(two, twoPrime)); 
  10. console.log("2 + 2' == " + add(two, twoPrime)); 
  11. console.log("2 + 2' == " + add(two, twoPrime)); 
  12.  
  13. // output
  14. // 2 + 2' == 4 
  15. // 2 + 2' == 4 
  16. // 2 + 2' == 4 

到目前為止,函數(shù)是確定性的!

現(xiàn)在,我們對(duì)函數(shù)的主體進(jìn)行一些小的更改:

 

  1. function add(a, b) { 
  2.   a.value += b.value; 
  3.   return a.value; 
  4.  
  5. console.log("2 + 2' == " + add(two, twoPrime)); 
  6. console.log("2 + 2' == " + add(two, twoPrime)); 
  7. console.log("2 + 2' == " + add(two, twoPrime)); 
  8.  
  9. // output
  10. // 2 + 2' == 4 
  11. // 2 + 2' == 6 
  12. // 2 + 2' == 8 

怎么了?突然間,函數(shù)的結(jié)果不再是可預(yù)測(cè)的了!它第一次工作正常,但在隨后的每次運(yùn)行中,它的結(jié)果開(kāi)始變得越來(lái)越不可預(yù)測(cè)。它第一次運(yùn)行得很好,但在隨后的每一次運(yùn)行中,它的結(jié)果開(kāi)始變得越來(lái)越不可預(yù)測(cè)。換句話說(shuō),這個(gè)函數(shù)不再是確定性的。

為什么它突然變得不確定了?該函數(shù)修改了其范圍外的值,引起了副作用。

讓我們回顧一下

確定性程序可確保 2 + 2 == 4,換句話說(shuō),給定輸入 (2, 2),函數(shù) add 始終應(yīng)得到 4 的輸出。不管你調(diào)用函數(shù)多少次,不管你是否并行調(diào)用函數(shù),也不管函數(shù)外的世界是什么樣子。

非確定性程序正好相反,在大多數(shù)情況下,調(diào)用 add(2, 2) 將返回 4 。但偶爾,函數(shù)可能會(huì)返回3、5,甚至1004。在程序中,非確定性是非常不可取的,希望你現(xiàn)在能明白為什么。

非確定性代碼的后果是什么?軟件缺陷,也就是通常所說(shuō)的 “bug”。錯(cuò)誤使開(kāi)發(fā)人員浪費(fèi)了寶貴的調(diào)試時(shí)間,如果他們進(jìn)入生產(chǎn)領(lǐng)域,會(huì)大大降低客戶體驗(yàn)。

為了使我們的程序更可靠,我們應(yīng)該首先解決非確定性問(wèn)題。

副作用

 

 

[[385716]]

 

Photo by Igor Yemelianov on Unsplash

這給我們帶來(lái)了副作用的問(wèn)題。

什么是副作用?如果你正在服用治療頭痛的藥物,但這種藥物讓你惡心,那么惡心就是一種副作用。簡(jiǎn)單來(lái)說(shuō),就是一些不理想的東西。

想象一下,你已經(jīng)購(gòu)買了一個(gè)計(jì)算器,你把它帶回家,開(kāi)始使用,然后突然發(fā)現(xiàn)這不是一個(gè)簡(jiǎn)單的計(jì)算器。你給自己弄了個(gè)扭曲的計(jì)算器!您輸入 10 * 11,它將輸出 110,但它同時(shí)還向您大喊一百和十。這是副作用。接下來(lái),輸入 41+1,它會(huì)打印42,并注釋“42,生命的意義”。還有副作用!你很困惑,然后開(kāi)始和你的另一半說(shuō)你想要點(diǎn)披薩。計(jì)算器聽(tīng)到了對(duì)話,大聲說(shuō)“ok”,然后點(diǎn)了一份披薩。還有副作用!

讓我們回到加法函數(shù):

 

  1. function add(a, b) { 
  2.   a.value += b.value; 
  3.   return a.value; 

是的,該函數(shù)執(zhí)行了預(yù)期的操作,將 a 添加到 b。然而,它也引入了一個(gè)副作用,調(diào)用 a.value += b.value 導(dǎo)致對(duì)象 a 發(fā)生變化。函數(shù)參數(shù) a 引用的是對(duì)象 2,因此是 2,value 不再等于 2。第一次調(diào)用后,其值變?yōu)?4,第二次調(diào)用后,其值為 6,依此類推。

純度

在討論了確定性和副作用之后,我們準(zhǔn)備談?wù)劶兒瘮?shù),純函數(shù)是指既具有確定性,又沒(méi)有副作用的函數(shù)。

再一次,確定性意味著可預(yù)測(cè)--在給定相同輸入的情況下,函數(shù)總是返回相同的結(jié)果。而無(wú)副作用意味著該函數(shù)除了返回一個(gè)值之外,不會(huì)做任何其他事情,這樣的函數(shù)才是純粹的。

純函數(shù)有什么好處?正如我已經(jīng)說(shuō)過(guò)的,它們是可以預(yù)測(cè)的。這使得它們非常容易測(cè)試,對(duì)純函數(shù)進(jìn)行推理很容易——不像OOP,不需要記住整個(gè)應(yīng)用程序的狀態(tài)。您只需要關(guān)心正在處理的當(dāng)前函數(shù)。

純函數(shù)可以很容易地組合(因?yàn)樗鼈儾粫?huì)改變其作用域之外的任何東西)。純函數(shù)非常適合并發(fā),因?yàn)楹瘮?shù)之間不共享任何狀態(tài)。重構(gòu)純函數(shù)是一件非常有趣的事情——只需復(fù)制粘貼,不需要復(fù)雜的IDE工具。

簡(jiǎn)而言之,純函數(shù)將歡樂(lè)帶回到編程中。

面向?qū)ο缶幊痰募兌热绾?

為了舉例說(shuō)明,我們來(lái)討論一下OOP的兩個(gè)功能:getter和setter。

getter的結(jié)果依賴于外部狀態(tài)——對(duì)象狀態(tài)。多次調(diào)用getter可能會(huì)導(dǎo)致不同的輸出,這取決于系統(tǒng)的狀態(tài)。這使得getter具有內(nèi)在的不確定性。

現(xiàn)在說(shuō)說(shuō)setter,Setters的目的是改變對(duì)象的狀態(tài),這使得它們本身就具有副作用。

這意味著OOP中的所有方法(也許除了靜態(tài)方法)要么是非確定性的,要么會(huì)引起副作用,兩者都不好。因此,面向?qū)ο蟮某绦蛟O(shè)計(jì)絕不是純粹的,它與純粹完全相反。

有一個(gè)銀彈

但是我們很少有人敢嘗試。

 

 

 

[[385717]]

 

Photo by Mohamed Nohassi on Unsplash

無(wú)知不是恥辱,而是不愿學(xué)習(xí)。

— Benjamin Franklin

在軟件失敗的陰霾世界中,仍有一線希望,那將會(huì)解決大部分問(wèn)題,即使不是所有問(wèn)題。一個(gè)真正的銀彈。但前提是你愿意學(xué)習(xí)和應(yīng)用——大多數(shù)人都不愿意。

銀彈的定義是什么?可以用來(lái)解決我們所有問(wèn)題的東西。數(shù)學(xué)是靈丹妙藥嗎?如果說(shuō)有什么區(qū)別的話,那就是它幾乎是一顆銀彈。

我們應(yīng)該感謝成千上萬(wàn)的聰明的男人和女人,幾千年來(lái)他們辛勤工作,為我們提供數(shù)學(xué)。歐幾里得,畢達(dá)哥拉斯,阿基米德,艾薩克·牛頓,萊昂哈德·歐拉,阿朗佐·丘奇,還有很多很多其他人。

如果不確定性(即不可預(yù)測(cè))的事物成為現(xiàn)代科學(xué)的支柱,你認(rèn)為我們的世界會(huì)走多遠(yuǎn)?可能不會(huì)太遠(yuǎn),我們會(huì)停留在中世紀(jì)。這在醫(yī)學(xué)界確實(shí)發(fā)生過(guò)——在過(guò)去,沒(méi)有嚴(yán)格的試驗(yàn)來(lái)證實(shí)某種特定治療或藥物的療效。人們依靠醫(yī)生的意見(jiàn)來(lái)治療他們的健康問(wèn)題(不幸的是,這在俄羅斯等國(guó)家仍然發(fā)生)。在過(guò)去,放血等無(wú)效的技術(shù)一直很流行。像砷這樣不安全的物質(zhì)被廣泛使用。

不幸的是,今天的軟件行業(yè)與過(guò)去的醫(yī)藥太相似了。它不是建立在堅(jiān)實(shí)的基礎(chǔ)上。相反,現(xiàn)代軟件業(yè)大多是建立在一個(gè)薄弱的搖搖欲墜的基礎(chǔ)上,稱為面向?qū)ο蟮木幊獭H绻说纳苯右蕾囉谲浖琌OP早就消失了,就像放血和其他不安全的做法一樣,被人遺忘了。

堅(jiān)實(shí)的基礎(chǔ)

 

 

[[385718]]

 

Photo by Zoltan Tasi on Unsplash

有沒(méi)有其他選擇?在編程的世界里,我們能不能有像數(shù)學(xué)一樣可靠的東西?是的,可以!許多數(shù)學(xué)概念可以直接轉(zhuǎn)化為編程,并為所謂的函數(shù)式編程奠定基礎(chǔ)。

是什么讓它如此穩(wěn)健?它是基于數(shù)學(xué),特別是Lambda微積分。

來(lái)做個(gè)比較,現(xiàn)代的OOP是基于什么呢?是的,真正的艾倫·凱是基于生物細(xì)胞的。然而,現(xiàn)代的Java/C# OOP是基于一組荒謬的思想,如類、繼承和封裝,它沒(méi)有天才Alan Kay所發(fā)明的原始思想,剩下的只是一套創(chuàng)可貼,用來(lái)彌補(bǔ)其劣等思想的缺陷。

函數(shù)式編程呢?它的核心構(gòu)建塊是一個(gè)函數(shù),在大多數(shù)情況下是一個(gè)純函數(shù),純函數(shù)是確定性的,這使它們可預(yù)測(cè),這意味著由純函數(shù)組成的程序?qū)⑹强深A(yù)測(cè)的。它們會(huì)永遠(yuǎn)沒(méi)有bug嗎?不,但是如果程序中有一個(gè)錯(cuò)誤,它也是確定的——相同的輸入總是會(huì)出現(xiàn)相同的錯(cuò)誤,這使得它更容易修復(fù)。

我怎么到這里了?

在過(guò)去,在過(guò)程/函數(shù)出現(xiàn)之前 goto 語(yǔ)句在編程語(yǔ)言中被廣泛使用。goto 語(yǔ)句只是允許程序在執(zhí)行期間跳轉(zhuǎn)到代碼的任何部分。這讓開(kāi)發(fā)人員真的很難回答 “我是怎么執(zhí)行到這一步的?” 的問(wèn)題。是的,這也造成了大量的BUG。

如今,一個(gè)非常類似的問(wèn)題正在發(fā)生。只不過(guò)這次的難題是 “我怎么會(huì)變成這個(gè)樣子”,而不是 “我怎么會(huì)變成這個(gè)執(zhí)行點(diǎn)”。

OOP(以及一般的命令式編程)使得回答 “我是如何達(dá)到這個(gè)狀態(tài)的?” 這個(gè)問(wèn)題變得很難。在OOP中,所有的東西都是通過(guò)引用傳遞的。這在技術(shù)上意味著,任何對(duì)象都可以被任何其他對(duì)象突變(OOP沒(méi)有任何限制來(lái)阻止這一點(diǎn))。而且封裝也沒(méi)有任何幫助--調(diào)用一個(gè)方法來(lái)突變某個(gè)對(duì)象字段并不比直接突變它好。這意味著,程序很快就會(huì)變成一團(tuán)亂七八糟的依賴關(guān)系,實(shí)際上使整個(gè)程序成為一個(gè)全局狀態(tài)的大塊頭。

有什么辦法可以讓我們不再問(wèn) “我怎么會(huì)變成這樣” 的問(wèn)題?你可能已經(jīng)猜到了,函數(shù)式編程。

過(guò)去很多人都抵制停止使用 goto 的建議,就像今天很多人抵制函數(shù)式編程,和不可變狀態(tài)的理念一樣。

但是等等,意大利面條代碼呢?

在OOP中,它被認(rèn)為是 “優(yōu)先選擇組成而不是繼承” 的最佳實(shí)踐。從理論上講,這種最佳做法應(yīng)該對(duì)意大利面條代碼有所幫助。不幸的是,這只是一種 “最佳實(shí)踐”。面向?qū)ο蟮木幊谭妒奖旧聿](méi)有為執(zhí)行這樣的最佳實(shí)踐設(shè)置任何約束。這取決于你團(tuán)隊(duì)中的初級(jí)開(kāi)發(fā)人員是否遵循這樣的最佳實(shí)踐,以及這些實(shí)踐是否在代碼審查中得到執(zhí)行(這并不總是發(fā)生)。

那函數(shù)式編程呢?在函數(shù)式編程中,函數(shù)式組成(和分解)是構(gòu)建程序的唯一方法。這意味著,編程范式本身就強(qiáng)制執(zhí)行組成。這正是我們一直在尋找的東西!

函數(shù)調(diào)用其他函數(shù),大的函數(shù)總是由小的函數(shù)組成,就是這樣。與OOP中不同的是,函數(shù)式編程中的組成是自然的。此外,這使得像重構(gòu)這樣的過(guò)程變得極為簡(jiǎn)單——只需簡(jiǎn)單地剪切代碼,并將其粘貼到一個(gè)新的函數(shù)中。不需要管理復(fù)雜的對(duì)象依賴關(guān)系,不需要復(fù)雜的工具(如Resharper)。

可以清楚地看到,OOP對(duì)于代碼組織來(lái)說(shuō)是一個(gè)較差的選擇。這是函數(shù)式編程的明顯勝利。

但是OOP和FP是相輔相成的!

抱歉讓您失望,它們不是互補(bǔ)的。

面向?qū)ο缶幊膛c函數(shù)式編程完全相反。說(shuō)OOP和FP是互補(bǔ)的,可能就等于說(shuō)放血和抗生素是互補(bǔ)的,是嗎?

OOP違反了許多基本的FP原則:

  • FP提倡純凈,而OOP提倡雜質(zhì)。
  • FP代碼基本上是確定性的,因此是可預(yù)測(cè)的。OOP代碼本質(zhì)上是不確定性的,因此是不可預(yù)測(cè)的。
  • 組合在FP中是自然的,在OOP中不是自然的。
  • OOP通常會(huì)導(dǎo)致錯(cuò)誤百出的軟件和意大利面條式的代碼。FP產(chǎn)生了可靠、可預(yù)測(cè)和可維護(hù)的軟件。
  • 在FP中很少需要調(diào)試,而簡(jiǎn)單的單元測(cè)試往往不需要調(diào)試。另一方面,OOP程序員生活在調(diào)試器中。
  • OOP程序員把大部分時(shí)間花在修復(fù)bug上。FP程序員把大部分時(shí)間花在交付結(jié)果上。

歸根結(jié)底,函數(shù)式編程是軟件世界的數(shù)學(xué)。如果數(shù)學(xué)已經(jīng)為現(xiàn)代科學(xué)打下了堅(jiān)實(shí)的基礎(chǔ),那么它也可以以函數(shù)式編程的形式為我們的軟件打下堅(jiān)實(shí)的基礎(chǔ)。

采取行動(dòng),為時(shí)已晚

OOP是一個(gè)非常大且代價(jià)高昂的錯(cuò)誤,讓我們最終都承認(rèn)吧。

想到我坐的車運(yùn)行著用OOP編寫的軟件,我就害怕。知道帶我和我的家人去度假的飛機(jī)使用面向?qū)ο蟮拇a并沒(méi)有讓我感到更安全。

現(xiàn)在是我們大家最終采取行動(dòng)的時(shí)候了。我們都應(yīng)該從一小步開(kāi)始,認(rèn)識(shí)到面向?qū)ο缶幊痰奈kU(xiǎn),并開(kāi)始努力學(xué)習(xí)函數(shù)式編程。這不是一個(gè)快速的過(guò)程,至少需要十年的時(shí)間,我們大多數(shù)人才能實(shí)現(xiàn)轉(zhuǎn)變。我相信,在不久的將來(lái),那些一直使用OOP的人將會(huì)被視為 “恐龍”,就像今天的COBOL程序員一樣,被淘汰。C ++和Java將會(huì)消亡, C#將死亡,TypeScript也將很快成為歷史。

我希望你今天就行動(dòng)起來(lái)——如果你還沒(méi)有開(kāi)始學(xué)習(xí)函數(shù)式編程,就開(kāi)始學(xué)習(xí)吧。成為真正的好手,并傳播這個(gè)詞。F#、ReasonML和Elixir都是入門的好選擇。

巨大的軟件革命已經(jīng)開(kāi)始。你們會(huì)加入,還是會(huì)被甩在后面?

責(zé)任編輯:華軒 來(lái)源: 前端全棧開(kāi)發(fā)者
相關(guān)推薦

2021-01-15 11:37:28

面向?qū)ο缶幊?/a>計(jì)算機(jī)科學(xué)OOP

2013-01-09 09:27:09

面向?qū)ο?/a>計(jì)算機(jī)編程

2011-10-17 09:50:38

編程

2012-09-10 09:43:21

編程編程學(xué)習(xí)編程錯(cuò)誤

2021-01-26 09:19:50

計(jì)算機(jī)數(shù)據(jù)中心故障IT服務(wù)

2019-04-30 15:14:11

數(shù)據(jù)科學(xué)家計(jì)算機(jī)

2019-09-10 12:58:03

電腦編程語(yǔ)言硬件

2010-07-21 16:10:25

計(jì)算機(jī)

2021-05-28 05:34:06

Golang語(yǔ)言編程

2013-01-10 10:05:29

編程面向?qū)ο缶幊?/a>

2023-01-10 09:38:09

面向對(duì)象系統(tǒng)

2023-07-07 10:53:08

2017-05-15 12:58:00

編程javaapl

2020-11-11 11:00:58

計(jì)算機(jī)程序員編程

2009-05-22 10:43:44

2012-01-17 09:34:52

JavaScript

2017-04-21 09:07:39

JavaScript對(duì)象編程

2018-07-06 14:12:50

計(jì)算機(jī)薪酬錢景

2010-11-17 11:31:22

Scala基礎(chǔ)面向?qū)ο?/a>Scala

2024-03-06 14:36:08

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 色播av| 伊人伊成久久人综合网站 | 日韩欧美中文 | 毛片免费在线 | 91一区二区三区在线观看 | 亚洲理论在线观看电影 | www一级片| 99热播精品 | 亚洲国产精品一区二区第一页 | 午夜欧美 | 天堂资源最新在线 | 成人免费视频网站在线看 | 国产精品不卡 | 色播99| 一区二区福利视频 | 亚洲欧美日韩精品 | 日日碰狠狠躁久久躁96avv | 欧美国产日本一区 | 亚洲国产精品一区二区三区 | 中文字幕乱码亚洲精品一区 | 日韩欧美国产精品一区二区三区 | 国产ts人妖系列高潮 | 国产一区二区三区日韩 | 亚洲精品久久久久久国产精华液 | 天天在线操 | 成人精品国产免费网站 | 久久精品亚洲一区二区三区浴池 | 欧美精品久久久久久久久老牛影院 | 欧美中文一区 | 国产精品欧美一区喷水 | 久久99国产精品 | 亚洲精品99999| 亚洲一区国产 | 日韩欧美国产成人一区二区 | 国产99久久| 国产a视频 | 黄色免费在线网址 | 国产亚洲欧美日韩精品一区二区三区 | 欧美精品在线免费 | 欧美激情区 | 国产免费视频 |