原文:https://herbertograca.com/2017/07/10/programming-language-evolution/
這篇文章是軟件架構(gòu)編年史(譯)的一部分,這部編年史由一系列關(guān)于軟件架構(gòu)的文章組成。在這一系列文章中,我將寫下我對軟件架構(gòu)的學(xué)習(xí)和思考,以及我是如何運用這些知識的。如果你閱讀了這個系列中之前的文章,本篇文章的的內(nèi)容將更有意義。
編程語言本身并不是架構(gòu)的產(chǎn)出,但是如果沒有涵蓋編程語言的內(nèi)容,我會覺得軟件架構(gòu)編年史中總是缺點什么。
所以,我們來快速回顧一下編程語言的歷史和演進(jìn)過程,看看我們能學(xué)到些什么。出于好奇,我在這里加入了一些并不算精確的時間,但重要的是演進(jìn)的順序和它們試圖解決的問題。
20世紀(jì)50年代 – 非結(jié)構(gòu)化編程
匯編 ~1951
軟件開發(fā)曾經(jīng)是一項高深莫測的活動,只發(fā)生在世界上很少的地方。那時匯編是最熱門的語言,它使用非常底層的“add”“sub”“goto”操作并直接操縱內(nèi)存地址。創(chuàng)建一個簡單的應(yīng)用程序都很困難,也要花費很長的時間。它需要好幾行代碼才能實現(xiàn)條件語句,而實現(xiàn)循環(huán)就需要更多代碼行了...劃分和重用代碼段的能力是它之后的事情了,所以它的編碼風(fēng)格就是一路到底,代碼重用僅限于在單個文件中或多個文件之間復(fù)制粘貼代碼。
20世紀(jì)60年代 – 結(jié)構(gòu)化編程
Algol ~1958
結(jié)構(gòu)化編程語言出現(xiàn)了,帶來了代碼塊、控制結(jié)構(gòu)(if/then/else、case、for、while、do…) 和子例程。這樣我們才能創(chuàng)建一些有趣的代碼流,而更重要的是,我們可以劃分代碼質(zhì)量并重用它們了,盡管還有一些限制,例如子例程只能作用于同樣的全局變量。這是重用思想第一次變?yōu)楝F(xiàn)實。
20世紀(jì)70年代 – 過程式編程 & 函數(shù)式編程
Pascal ~1970, C ~1972
過程式和函數(shù)式代碼誕生于20世紀(jì)70年代。這時我們終于擁有了:
- 過程:一組不返回數(shù)據(jù)的指令;
- 函數(shù):一組返回數(shù)據(jù)的指令;
- 數(shù)據(jù)結(jié)構(gòu):記錄,和關(guān)聯(lián)數(shù)組類似;
- 模塊:可以在其它代碼文件中導(dǎo)入的代碼文件。
“意大利面式的代碼”也是在這個時代提出的,1968年它出現(xiàn)在Edsger W. Dijkstra發(fā)表在計算機(jī)協(xié)會通信(CACM)上題為“Go To Statement Considered Harmful*”的文章中。
20世紀(jì)70年代末,面向事件編程的思想開始浮現(xiàn),Trygve Reenskaug撰寫了關(guān)于MVC的論文(其中用到了事件)。
伴隨著這些改進(jìn),我們有了更好的重用性,因為子例程(過程或函數(shù))可以對不同的數(shù)據(jù)執(zhí)行同樣的邏輯。我們還可以通過將關(guān)聯(lián)的數(shù)據(jù)劃分在一起編程復(fù)雜的數(shù)據(jù)接口來對領(lǐng)域概念建模。最后,我們邁出了解耦和模塊化的第一步,我們可以創(chuàng)建在其他代碼文件中重用的代碼,還可以創(chuàng)建事件來分離調(diào)用方代碼和執(zhí)行邏輯。
20世紀(jì)80年代 – 面向?qū)ο缶幊?OOP)
Simula ~1965, Smalltalk-71 ~1971, C++ ~1980, Erlang ~1986, Perl ~1987,
Python ~1991, Ruby ~1993, Delphi, Java, Javascript, PHP ~1995
OOP的思想和理論早在20世紀(jì)60年代就開始萌芽了而且在那個年代第一次被Simula 實現(xiàn)了。
然而,現(xiàn)在這種編程范式的使用方法卻是在20世紀(jì)80年代形成的:擁有可見性級別、方法(消息)、對象、類以及包的面向?qū)ο缶幊獭M瑫r封裝和模塊化**也被越來越多地提及。
- 可見性級別 讓我們控制一組特定的數(shù)據(jù)能被哪些代碼訪問;
- 類 讓我們定義/建模領(lǐng)域概念;
- 對象 讓我們創(chuàng)建出同樣領(lǐng)域概念的不同實例;
- 包 讓我們可以將類劃分到一組表示領(lǐng)域概念或功能概念,來共同完成某個任務(wù);
- 方法 從功能性角度來看代表了過程和函數(shù),而在概念性交付來看則應(yīng)該被看作是可以發(fā)給指定類型對象的消息(或者更好的名字,命令)。
20 世紀(jì) 90 年代 – 面向主觀編程和面向方面編程
面向主觀編程和面向方面編程在 20 世紀(jì) 90 年代橫空出世。
面向主觀編程需要對象根據(jù)誰在“觀察”它展現(xiàn)不同的表現(xiàn)形式。例如,在人類的眼中樹可能就是木材,而在鳥類的眼中樹可能是食物和庇護(hù)所。對應(yīng)到編程范式中,這意味著對象的屬性和行為會根據(jù)是誰給它發(fā)的消息(誰觸發(fā)了對象的方法)而不同。
面向方面編程試圖通過在“編譯”期注入額外的代碼來將橫切面的關(guān)注點從真正的業(yè)務(wù)邏輯中分離出來。例如,一個方面就是一個方法名,一個橫切的關(guān)注點則是日志。使用 AOP,我們可以通過簡單的系統(tǒng)配置就可以將日志代碼注入到所有名字符合格式的方法中,比如,“記錄所有對以‘find’開頭的方法的調(diào)用”。(TYPO3 就是一個使用 AOP 的 CMS 實例)
OOP 之外
在 OOP 流行起來之后,我們的注意力就放在了 Web 編程,為了 Web 開發(fā)改進(jìn)現(xiàn)有語言和創(chuàng)造新語言,為了現(xiàn)如今大量的請求和數(shù)據(jù)調(diào)整工具和架構(gòu)。
也有一些編程范式的嘗試,比如面向主觀編程(根據(jù)發(fā)起行為的主觀對象具有不同的行為)或者面向方面編程(編譯期的代碼注入),但實質(zhì)上編程語言范式并沒有發(fā)生變化,大多數(shù)情況下我們?nèi)匀皇褂玫氖?OOP。盡管最近函數(shù)式語言又重新得到了一些應(yīng)用(也許是炒作?)。
總結(jié)
我想表達(dá)的觀點是在軟件開發(fā)歷史的最初的年代,編程語言不僅僅是為了重要性在演進(jìn),它們也讓軟件可以擁抱變化(改變功能,重構(gòu)或者完全替換一段代碼),它們在模塊化(低耦合)和封裝(高內(nèi)聚)兩個方向上同時演進(jìn)。在接下來的文章中,你將看到架構(gòu)也在演進(jìn),只不過是在更高的抽象級別。
引用來源
1979 – Trygve Reenskaug – MVC
1993 – Alan C. Kay – The Early History of Smalltalk
1993 – William Harrison, Harold Ossher – Subject-Oriented Programming: A Critique of Pure Objects
1997 – Gregor Kiczales, John Lamping, Anurag Mendhekar, Chris Maeda, Cristina Videira Lopes, Jean-Marc Loingtier, John Irwin – Aspect Oriented Programming
2005 – David R. Tribble – Go To Statement Considered Harmful: A Retrospective
2017* – Wikipedia – Programming Paradigm
2018* – Wikipedia – Simula