長文:程序員思維
起因
首先簡單說一下,為什么我會想到這個話題。主要有這么幾方面的原因。
當我試圖回過頭去總結大學在計算機專業所學習的一些理論和知識的時候。發現,在學校里面學習的一些東西,走了兩個極端。 一個極端是偏向了細節。比如我們學習的那些《***程序設計》的課程。看這幾門課的名稱的我們能夠很明顯的看出,***是一個形容詞定語,用來修飾主題 “程序設計”。但是,你卻非常意外的意識到《C++面向對象程序設計》和面向對象程序設計貌似關系不大,整門課程主要講了一個更好用的C,比C好用的地方 是在于人家有對象。學習了這一系列《***程序設計》的課程之后的結果是:你知道了匯編的語法,知道了C的語法,知道了 C++ 的語法;但是用他們能做些什么卻不知道。 另外一個極端是偏向了宏觀。在我們對工程是個什么東西,項目是個什么東西,軟件又是個什么東東還沒有構建起最基本概念的時候。我們上了《軟件工程》這樣的 課程。劈頭蓋臉的理論砸下來了,沒有消化也沒有吸收。你甚至找不到,學這些課程對于你的編程實踐有什么樣的版主。等你寫代碼的時候,你真真切切的發現軟件 工程這個東西對于我這個函數怎么命名,模塊怎么劃分真的幫助不是很大啊。 其實,隨著時間一點點的流逝,工作年限的增加。你能夠發現,這兩個極端的東西還是有作用的。只不過,學校里面的課程少了一些能夠把它們融會貫通,串聯起來 的東西。而這個中間起到粘連作用的東西就是我所思考的。
另外一個原因是,當與其他同學或同事去寫同一個程序的時候。他們有些時候看到你的代碼,然后就會評論:你這代碼耦合性太緊,內聚性太差,不符合 高內聚低耦合的概念啊。你當然,有點氣不過啊。你憑什么說我代碼沒高內聚低耦合啊。于是你就問他為什么這么說。結果絕大多數時候,對方只是說”我感覺“。 即使有些時候他們根據他們多年的編程經驗說出了一些什么東西。但是你還是感覺說服不了你。你心里會暗自嘀咕,不就是你感覺嘛。你感覺的東西也不一定對。 同樣的問題,也會發生在當你去評論別人的代碼質量差的時候。要想讓別人認識到問題所在是異常困難的。果然世界上最難的事情有兩個:把別人的錢放進自己的口 袋里面,把自己的思想放進別人的腦袋里面。 于是,你就會去思考,有沒有一種理論或者評價的方法,是大家都認可的。而且的確能夠衡量出一個設計耦合性和內聚性的強弱來呢?
還有一個原因。和上面的原因有點類似,在編程中接觸到的很多同事。或者同樣是編程的人。我發現他們的能力參差不齊。而且,有些時候這種能力的參 差不齊不止是因為經驗造成的。當然,一個有十年多編程經驗的人肯定比一個剛剛入門的小孩寫的程序靠譜。但是,你會驚奇的發現有些人寫了四五年程序后,程序 的質量甚至比十幾年經驗的人要好很多。與他們聊天的時候,就發現導致這種現象的原因在于他們思維方式的不同。有很多十幾年編程經驗的同事,很多時候只是在 用感覺編程。在長期編程時間中形成的某些思維定勢幫助他們能夠快速的完成編碼工作,但是僅限于此。而那些年少卻有能力的同事,雖然年輕但是能夠編寫高質量 的代碼。因為他們不是通過經驗積累獲得編碼能力;而是通過理論學習,并且快速的消化掌握了和十年多經驗同事一樣的思維定勢。不一樣的是,他們還能通過理論 觸類旁通。寫出更高質量的代碼。 以前有個同事(他不是干程序員的,而是產品經理),他和其他同齡人最大的不同就是思維方式。他總喜歡干一件事情就是找規律。后來,他想自己做點東西,一時 又沒有拉到程序員一起干,就自己操刀學習 JS。你看他的代碼,才一兩個月的時間,代碼質量和以 JS 為職業的人已經有的一拼了。每當想到這,我就想:我們還能說對于編程這件事情經驗是最重要的嗎?
總結一下上面的原因就是,在我們的編程實踐中,我們需要找到一種思維框架來幫助我們設計和解釋我們的程序。這個東西就是要討論的程序員思維。
從哪里來,是什么
先講一個笑話,說是一個外國的哲學家來中國做客。中途去一個小區找一個朋友,然后就發現原來中國的小區保安都是哲學家。他進門的時候,保安問了 哲學家三個問題: 你從哪里來? 你是誰? 你到哪里去? 哲學家就感慨這是終極問題啊,自己窮其一生也沒能解答,沒想到這么個小地方還有人關心哲學的終極問題。其實人家保安就是想搞明白這個“哲學家”嘛。因為你 要弄明白一個概念,只要能夠回答好這三個問題,基本上就比較 OK 了。同樣我們要弄明白“程序員思維”,也要問三個問題?
- 程序員思維是什么?
- 程序員思維從哪里來?
- 程序員思維到哪里去? </ol>
- 把核桃放在硬質的地上。
- 找到一塊非常堅硬的石頭。
- 抬高石頭,用力砸核桃。
- 監察核桃是否碎裂,如果碎裂執行5,沒有碎裂執行3
- 吃掉核桃 </ol>
- 1943 – Plankalkül (Konrad Zuse)
- 1943 – ENIAC coding system
- 1949 – C-10 </ul>
- Fortran (1955),名稱取自”FORmula TRANslator”(公式翻譯器),由約翰·巴科斯等人所發明;
- LISP,名稱取自”LISt Processor”(列舉處理器),由約翰·麥卡錫等人所發明;
- COBOL,名稱取自”COmmon Business Oriented Language”(通用商業導向語言),由被葛麗絲·霍普深刻影響的 Short Range Committee 所發明。 </ul>
- 巢狀區塊結構:可以將有意義的程式碼片段群組成一個區塊(block),而非轉成分散且特定命名的程序。也就是我們所熟悉的模塊化設計。
- 詞匯范圍(lexical scoping):區塊可以有區塊外部無法透過名稱存取,屬于區塊本身的變量、程序以及函式。就是我們所熟悉的作用域。 </ul>
- 語法跟語意變的更加正交(orthogonal)
- 采用匿名的歷程(routines)
- 采用高階(higher-order)功能的遞回式輸入(typing)系統等等。 </ul>
- 1951 – Regional Assembly Language
- 1952 – Autocode
- 1954 – FORTRAN
- 1954 – IPL (LISP 的先驅)
- 1955 – FLOW-MATIC (COBOL 的先驅)
- 1957 – COMTRAN (COBOL 的先驅)
- 1958 – LISP
- 1958 – ALGOL 58
- 1959 – FACT (COBOL 的先驅)
- 1959 – COBOL
- 1962 – APL
- 1962 – Simula
- 1962 – SNOBOL
- 1963 – CPL (C的先驅)
- 1964 – BASIC
- 1964 – PL/I
- 1967 – BCPL (C的先驅) </ul>
- Simula,于 1960 年代晚期由奈加特與 Dahl 以 Algol 60 超集合的方式發展,同時也是第一個設計支援面向對象進行開發的編程語言。
- C,于 1969 至 1973 年間由貝爾實驗室的研究人員丹尼斯·里奇與肯·湯普遜所開發,是一種早期的系統程式設計(en:system programming)語言。
- Smalltalk,于 1970 年代中期所開發,是一個完全從零開始(ground-up)設計的面向對象編程語言。
- Prolog,于 1972 年由 Colmerauer、Roussel,以及 Kowalski 所設計,是第一個邏輯程式語言。
- ML,于 1973 年由羅賓·米爾納所發明,是一個基于 Lisp 所建構的多型(polymorphic)型態系統,同時也是靜態型別函數編程語言的先驅。 </ul>
- 1968 – Logo
- 1970 – Pascal
- 1970 – Forth
- 1972 – C 語言
- 1972 – Smalltalk
- 1972 – Prolog
- 1973 – ML
- 1975 – Scheme
- 1978 – SQL (起先只是一種查詢語言,擴充之后也具備了程式結構) </ul>
- 泛型存在(generics being)
- 本質(essence)
- 參數化模組(parameterized modules) </ul>
- 1980 – Ada
- 1983 – C++ (就像有類別的C)
- 1984 – Common Lisp
- 1985 – Eiffel
- 1986 – Erlang
- 1987 – Perl
- 1988 – Tcl
- 1989 – FL (Backus) </ul>
- 1990 – Haskell
- 1991 – Python
- 1991 – Visual Basic
- 1993 – Ruby
- 1993 – Lua
- 1994 – CLOS (part of ANSI Common Lisp)
- 1995 – Java
- 1995 – Delphi (Object Pascal)
- 1995 – JavaScript
- 1995 – PHP
- 1997 – REBOL
- 1999 – D </ul>
- 在語言中增加安全性與可靠性驗證機制:額外的堆棧檢查、資訊流(information flow)控制,以及靜態執行緒安全。
- 提供模組化的替代機制:混入(en:mixin)、委派(en:delegates),以及觀點導向。
- 元件導向(component-oriented)軟件開發
- 元編程、反射或是存取抽象語法樹(en:Abstract syntax tree)
- 更重視分散式及移動式的應用。
- 與數據庫的整合,包含 XML 及關聯式數據庫。
- 支援使用 Unicode 編寫程式,所以源代碼不會受到 ASCII 字符集的限制,而可以使用像是非拉丁語系的腳本或延伸標點符號。
- 圖形化使用者接口所使用的 XML (XUL、XAML)。 </ul>
- 2001 – C#
- 2001 – Visual Basic .NET
- 2002 – F#
- 2003 – Scala
- 2003 – Factor
- 2006 – Windows PowerShell
- 2007 – Clojure
- 2009 – Go </ul>
- 創造工具來滿足人們現實生活中的需求,比如金融工具、QQ、微信
- 不斷創造更加好用的硬件基礎。并且創造響應的軟件來適應更快的硬件。
- 隨著硬件規模和軟件規模的不斷擴大,發展相應的理論去控制規模擴大帶來的影響,即控制復雜性。 </ol>
- 高內聚低耦合
- 是否滿足設計模式的六大基本原則 </ol>
- 許多機能封裝在一類型內,可以借由方法供外界使用,但機能彼此類似之處不多。
- 在方法中進行許多不同的機能,使用的是相關性低或不相關的數據。 </ul>
- 增加理解模塊的困難度。
- 增加維護系統的困難度,因為一個邏輯修改會影響許多模塊,而一個模塊的修改會使得一些相關模塊也要修改。
- 增加模塊復用困難度,因為大部份的應用程序無法復用一個由許多不一定相關的機能組成的模塊。 </ul>
- 偶然內聚性(Coincidental cohesion,最低)偶然內聚性是指模塊中的機能只是剛好放在一起,模塊中各機能之間唯一的關系是其位在同一個模塊中(例如:“工具”模塊)。
- 邏輯內聚性(Logical cohesion)邏輯內聚性是只要機能只要在邏輯上分為同一類,不論各機能的本質是否有很大差異,就將這些機能放在同一模塊中(例如將所有的鼠標和鍵盤都放在輸入處理副程序中)。
- 時間性內聚性(Temporal cohesion)時間性內聚性是指將相近時間點運行的程序,放在同一個模塊中(例如在捕捉到一個異常后調用一函數,在函數中關閉已打開的文件、產生錯誤日志、并告知用戶)。
- 程序內聚性(Procedural cohesion)程序內聚性是指依一組會依照固定順序運行的程序放在同一個模塊中(例如一個函數檢查文件的權限,之后打開文件)。
- 聯絡內聚性(Communicational cohesion)聯絡內聚性是指模塊中的機能因為處理相同的數據,因此放在同一個模塊中(例如一個模塊中的許多機能都訪問同一個記錄)。
- 依序內聚性(Sequential cohesion)依序內聚性是指模塊中的各機能彼此的輸入及輸出數據相關,一模塊的輸出數據是另一個模塊的輸入,類似工廠的生產線(例如一個模塊先讀取文件中的數據,之后再處理數據)。
- 功能內聚性(Functional cohesion,最高)功能內聚性是指模塊中的各機能是因為它們都對模塊中單一明確定義的任務有貢獻(例如 XML 字符串的詞法分析)。 </ol>
- 內容耦合(content coupling,耦合度最高)也稱為病態耦合(pathological coupling)是指一個模塊依賴另一個模塊的內部作業(例如,訪問另一個模塊的局域變量),因此修改第二個模塊處理的數據(位置、形態、時序)也就影 響了第一個模塊。
- 共用耦合(common coupling)也稱為全局耦合(global coupling.) 是指二個模塊分享同一個全局變量,因此修改這個共享的資源也就要更動所有用到此資源的模塊。
- 外部耦合(external coupling)發生在二個模塊共用一個外加的數據格式、通信協議或是設備界面,基本上和模塊和外部工具及設備的溝通有關。
- 控制耦合(control coupling)是指一個模塊借由傳遞“要做什么”的信息,控制另一個模塊的流程(例如傳遞相關的旗標)。
- 特征耦合(stamp coupling)也稱為數據結構耦合,是指幾個模塊共享一個復雜的數據結構,而每個模塊只用其中的一部份,甚至各模塊用到的部份不同(例如傳遞一筆記錄給一個函數,而函數只需要其中的一個字段。
- 數據耦合(data coupling)是指模塊借由傳入值共享數據,每一個數據都是最基本的數據,而且只分享這些數據(例如傳遞一個整數給計算平方根的函數)。
- 信息耦合(message coupling,是無耦合之外,耦合度最低的耦合)可以借由以下二個方式達成:狀態的去中心化(例如在對象中),組件間利用傳入值或信息傳遞 (計算機科學)來通信。
- 無耦合模塊完全不和其他模塊交換信息。 </ol>
- di: 輸入數據參數的個數
- ci: 輸入控制參數的個數
- do: 輸出數據參數的個數
- co: 輸出控制參數的個數 </ul>
- gd: 用來存儲數據的全局變量
- gc: 用來控制的全局變量 </ul>
- w: 此模塊調用的模塊個數(扇出)
- r: 調用此模塊的模塊個數(扇入) </ul>
- 單一職責原則
- 里氏替換原則
- 依賴倒置原則
- 接口隔離原則
- 迪米特法則
- 開閉原則 </ol>
好吧,這是三個終極的問題。沒有標準答案,也沒有什么不標準的答案。我只是試圖給出自己的一個思考的總結。
類比法的一個描述
對于程序員思維這個東西現在還給不出一個大家都能夠接受的描述來定義它。當我們無法非常準確的定義一個東西的時候,我們回去找這個東西的類似的 東西來描述它。就像字典里面用同義詞來解釋某一個詞語一樣。我們先來看看程序員思維像個什么東西。說的具體一點就是我們編程敲代碼這個事情像是什么? 這里有不同的說法。 有些人說像是做數學證明題。你看到了一道數學題,然后就開始在你腦袋里面搜羅能夠用來證明這個題目的定理和方法。然后,按照一定的順序把這些定理和方法組 織起來,一步接一步的,就證明了。而寫程序,有些時候就是產品來了一個需求,我們就開始在腦袋里搜羅能夠幫助我們實現這個需求的方法和工具,很多時候是一 些算法或者程序的組織形式,然后把這些東西一個字符一個字符的敲下來,不出意外的情況下,產品的需求就實現了。 有些人說,編程序就像是在操作機器。和司機了沒有多大的區別。你往左打方向盤,車就往左開;你往右打方向盤,車就往右開。你給機器下達一條進行加法的命 令,機器即開始進行加法運算;你給機器下達一條進行減法的命令,機器就開始進行減法運算。 有些人說,程序設計或者編程這個東西。就像是作家寫作,都是在操作字符。都是敲敲打打的寫了一大堆字符,然后竟然還能夠通過這些字符賺錢。 有些人說,整個軟件的制作過程和蓋房子差不多。都有終端的用戶,一個是買房,一個是軟件用戶。有了需求然后就有了公司,房地產公司和軟件公司。公司就開始 招人了。房地產公司找了建筑設計師,軟件公司找了架構師。有了設計,就得動工啊。房地產公司找了包工頭把項目包給了報共同,軟件公司招了一批項目經理來負 責控制進度。包工頭找了幾個能挑頭的熟練工,然后每個熟練工后面跟著一批農民工。項目經理開始給高級程序員布置任務,每個高級程序員手下都有幾個碼農。然 后開始沒日沒夜的干活。最后把東西交付到終端用戶手上。 。。。。。 如果我們繼續這樣類比下去,可能這是個無窮無盡的大列表。咱們適可而止。 不知道通過上面的這些類別有沒有發現一些什么東西。上面說的這些事情,都是在用工具來解決問題或者通過工具來達到一些目的。編程或者程序設計也沒有逃出這 個框架,我們用程序這個工具來完成需求。 馬克思*韋伯在《新教理論與資本主義》中首次提出了一個概念能夠很好的解釋上面列舉的事情的共性——工具理性。所謂“工具理性”,就是通過實踐的途徑確認 工具(手段)的有用性,從而追求事物的最大功效,為人的某種功利的實現服務。工具理性是通過精確計算功利的方法最有效達至目的的理性,是一種以工具崇拜和 技術主義為生存目標的價值觀,所以“工具理性”又叫“功效理性”或者說“效率理性”。 仔細一想,程序員思維就是在工具理性這個大的思維框架下面。所以一,程序員思維勢必符合工具理性的一些特征。這有點想父類的子類的關系。工具理性是父類, 程序員思維是子類。既然如此我們要了解程序員思維,那么我們先來看看工具理性。
工具理性
雖然工具理性是在 19 世紀提出來的一個概念。但是像絕大部分的概念和定理一樣,雖然我們沒有認知到它,但是它已經在那里。哥白尼之前人們沒有認識到地球是圍繞著太陽轉的,但是 太陽在那之前也是圍繞著太陽轉的。雖然我們在很長一段時間內沒有明確的提出工具理性的概念,但是我們確實一直在實踐著工具理性,而且是從一開始。 人從靈長類的猿開始進化的時候,與猿最大的不同就是我們開始使用工具。WIKI 上關于工具的定義是這樣的:工具(英語:Tool)或裝備、器材(英語:Equipment)是指能夠方便人們完成工作的器具,它的好處可以是機械性,也 可以是智能性的。大部分工具都是簡單機械;例如一根鐵棍可以當作杠桿使用,力點離開支點越遠,杠桿傳遞的力就越大。 雖然絕大部分的篇幅是在描述機械性的工具,但是其中很短的一句“也可以是智能性的”貌似說出了些什么。有很多人類學家認為人與動物的最大卻在于使用工具, 后來又有一部分人對這句話做出了修正:人與動物最大的卻別是在于能夠使用智力工具。試想一下,對于使用石頭這個工具來砸核桃這個事情來說,是這個工具石頭 重要,還是知道用什么樣的石頭,怎樣的區砸重要呢? 或許從砸核桃這個事情上,你就能夠看到后來我們稱之為“算法”的東西的影子。
而在這個過程中,是哪塊石頭并不重要,重要的是它能夠幫助我們完成上面的步驟。真正的核心還是步驟。 古希臘有個叫泰勒斯的數學家和哲學家。生活窮困潦倒,竟然靠借貸度日。但是,他醉心研究哲學和數學。周圍的鄰居就嘲笑他,說他凈整些沒用的。思考的那些東 西又不能當飯吃。剛開始,泰勒斯沒太當回事。后來周圍的人都以此為笑柄,甚至教育孩子不要學他。于是,在某一年的春季。那年的春天比較干旱,人們都預計這 年的橄欖的收成會很不好。但是,泰勒斯借錢,用極低的價格買斷了當地榨汁機的使用權。當秋天到來,結果橄欖豐收。但是榨汁機的使用權卻在泰勒斯手上,泰勒 斯高價出售了榨汁機的使用權。大賺!原來泰勒斯,在很早之前就通過自己的思考和分析,預見到今年橄欖會豐收。漂亮的給了嘲笑他的人響亮的回擊。 這個過程中,橄欖重要嗎?榨油機重要嗎?都重要,但是沒有泰勒斯的思維重要。是他思維的工具幫助他賺到了這一筆錢。同樣思維方式或者思維工具起到決定性作 用的例子數不勝數。比如以少勝多的赤壁之戰之類。 在工具這個層面理解的話,思維工具要比機械性的工具要重要的多。而仔細分析,其實機械性的工具只不過是把我們的思維工具固化成了實物——把我們對鋒利的認 知、理解與分析物化成了刀子;把我們對色彩的認知理解分支物化成了筆;把我們對水流動性的認知物化成了杯子。。。。。。不一而足。的確思維工具要想對現實 產生作用,必須經過物化這一層。思維工具只有變成一個實物了才能夠真正的對現實世界產生作用。于是機械性工具的作用,不過就是承載我們思維工具的嘛,不就 是我們思維工具的物化嘛! 而程序呢,通過計算機這個機械性的工具物化了,然后又鏈接到了各式各樣的物化的工具上面。而神奇的是,我們在有了計算機之后創造工具的方式與以前有天壤之 別,我們不需要直接去創造機械性的工具了。程序讓我們有了間接操作機械性工具的能力。我們只需要負責思考就好了。而這思考的內容是我們目前為止掌握的所有 的知識。 程序這個東西實在物化我們現在幾乎所有能夠掌握的知識。我們通過程序協作,通過程序作圖,通過程序喂豬,通過程序通信,通過程序定飯店。。。 于是程序設計就是利用計算機將知識物化,并利用知識的可復現性來對現實產生作用。程序員所要做的事情就是用理性的工具來完成這一過程。而程序員思維就是幫 助我們來完成這個事情的那一整套的思維框架。
一些歷史
大家比較公認的世界上第一個程序員是個女程序員。阿達·洛芙萊斯(Ada Lovelace)的名字是否使你想起什么呢?沒有?它應該在電腦、平板或手機上出現過。這位維多利亞時代的女士、三個孩子的母親出生于 1815 年,是世界上第一個計算機程序員。 他是查爾斯·巴貝齊(Charles Babbage)的朋友,巴貝奇發明了一個很奇怪的機器(可以把它看作是第一臺計算機)——差分機,洛芙萊斯用巴貝齊的數學機器翻譯意大利數學家路易吉· 蒙博(Luigi Menabrea)里的筆記。洛芙萊斯進行的很順利,用她自己豐富的數學知識擴展了蒙博里的筆記,她用一種算法使計算機能夠識別一系列數字,有效的發明了 第一個計算機程序。 她最要的貢獻就是提出了類似于軟件或者程序的概念,將思維工具與具體的機械屬性剝離。在單一的機械工具上你能夠物化不同的思維工具。這就是程序的魅力所 在,它讓思維工具減少了對機械的依賴。 她和巴貝奇所處的時代是工業革命爆發的時代,或者話句話說他們所處的時代是一個工具大爆炸的時代。通常認為人類生產力突飛猛進式的躍進有三個時期: 第一個是農業革命,我們發明了農業,將天文學、數學。。。。那個時候我們能夠掌握的絕大部分知識應用在了耕作這個事情上。產生了生產力的躍進。 第二個是工業革命,正是巴貝奇所處的時代。工業化生產出現,人們使用大型工具,組織起工廠來生產。文藝復興和航海大發現以來,所做的知識儲備在工業革命得 到直接物化。 第三個是信息革命,即現在。我們在使用信息技術,當然主要就是編寫程序來間接物化知識。讓知識能夠不直接變成機械性的物體也能夠作用于現實。 其實這三次生產力躍進時間附近都有人類的知識大爆發: 農業革命:在國外對應著古希臘文明,在中國對應著三皇五帝到春秋戰國。 工業革命之前是文藝復興和航海大發現。 信息革命,現在時近現代科學體系的完善。 而有些人把文藝復興稱之為工具理性的復興。文藝復興的本意是指古希臘文明的復興。古希臘文明也是工具理性的一次興盛。即使到了現在,現代科學體系下面的, 工具理性依然是核心骨架。在整個人類文明中,工具理性起到了舉足輕重的作用。每一次革命都是知識大爆發的時代,也是我們把知識物化成工具的時代。 到上面為止,我簡單的說了一下自己對于程序員思維父類——工具理性的認知。我自己在構建起工程理性這個概念之后。帶著這些認知,看一下軟件(程序員思維) 的歷史,準確說應該是編程的歷史。 關于編程的歷史推薦大家看一本書《信息簡史》,其中第四章到第七章從信息的角度切入講解了程序的一個起源。包括硬件層面和軟件層面。當然作為 Code Monkey 我們比較關心的是軟件層面的問題。 上面說到了 Ada Lovelace,第一個提出了程序的概念,減小了思維工具對機械工具依賴性的人。而她背后的那個人——實現她的程序硬件的巴貝奇,也是非常重要的。巴貝 奇的差分機被認為是第一臺計算機。一個能夠生產數的機器。但是從巴貝奇到第一臺現代計算機 ENAIC 誕生的一百多年的時間里面。人們可能更多的是關注,直接用機械來物化思維工具。但是他們在做著為軟件能夠真正意義上的誕生做著基礎性工作——他們創造了信 息論。 信息論的誕生,為我們物化思維工具,嚴格意義上說是間接的物化思維工具提供了一整套的理論依據和方法論。我們不再需要直接去制作機械性的工具就能夠改變現 實。我們在信息論的基礎上。軟件或者程序設計開始突飛猛進。在短短的 60 年間,已經完成了幾個量級的跨越。為了更好的展現程序設計的歷史,我們從兩個方面來看。一個是軟件的發展;一個是計算機程序語言的發展歷史。
軟件歷史
計算機軟件技術發展很快。50 年前,計算機只能被高素質的專家使用,今天,計算機的使用非常普遍,甚至沒有上學的小孩都可以靈活操作;40 年前,文件不能方便地在兩臺計算機之間進行交換,甚至在同一臺計算機的兩個不同的應用程序之間進行交換也很困難,今天,網絡在兩個平臺和應用程序之間提供 了無損的文件傳輸;30 年前,多個應用程序不能方便地共享相同的數據,今天,數據庫技術使得多個用戶、多個應用程序可以互相覆蓋地共享數據。了解計算機軟件的進化過程,對理解計 算機軟件在計算機系統中的作用至關重要。
第一代軟件(1946-1953)
第一代軟件是用機器語言編寫的,機器語言是內置在計算機電路中的指令,由 0 和 1 組成。例如計算2+6 在某種計算機上的機器語言指令如下: 10110000 00000110 00000100 00000010 10100010 01010000 第一條指令表示將“6”送到寄存器 AL 中,第二條指令表示將“2”與寄存器 AL 中的內容相加,結果仍在寄存器 AL 中,第三條指令表示將 AL 中的內容送到地址為 5 的單元中。 不同的計算機使用不同的機器語言,程序員必須記住每條及其語言指令的二進制數字組合,因此,只有少數專業人員能夠為計算機編寫程序,這就大大限制了計算機 的推廣和使用。用機器語言進行程序設計不僅枯燥費時,而且容易出錯。想一想如何在一頁全是 0 和 1 的紙上找一個打錯的字符! 在這個時代的末期出現了匯編語言,它使用助記符(一種輔助記憶方法,采用字母的縮寫來表示指令)表示每條機器語言指令,例如 ADD 表示加,SUB 表示減,MOV 表示移動數據。相對于機器語言,用匯編語言編寫程序就容易多了。例如計算2+6 的匯編語言指令如下: MOV AL,6 ADD AL,2 MOV #5,AL 由于程序最終在計算機上執行時采用的都是機器語言,所以需要用一種稱為匯編器的翻譯程序,把用匯編語言編寫的程序翻譯成機器代碼。編寫匯編器的程序員簡化 了他人的程序設計,是最初的系統程序員。
第二代軟件(1954-1964)
當硬件變得更強大時,就需要更強大的軟件工具使計算機得到更有效地使用。匯編語言向正確的方向前進了一大步,但是程序員還是必須記住很多匯編指 令。第二代軟件開始使用高級程序設計語言(簡稱高級語言,相應地,機器語言和匯編語言稱為低級語言)編寫,高級語言的指令形式類似于自然語言和數學語言 (例如計算2+6 的高級語言指令就是2+6),不僅容易學習,方便編程,也提高了程序的可讀性。 IBM 公司從 1954 年開始研制高級語言,同年發明了第一個用于科學與工程計算的 FORTRAN 語言。1958 年,麻省理工學院的麥卡錫(John Macarthy)發明了第一個用于人工智能的 LISP 語言。1959 年,賓州大學的霍普(Grace Hopper)發明了第一個用于商業應用程序設計的 COBOL 語言。1964 年達特茅斯學院的凱梅尼(John Kemeny)和卡茨(Thomas Kurtz)發明了 BASIC 語言。 高級語言的出現產生了在多臺計算機上運行同一個程序的模式,每種高級語言都有配套的翻譯程序(稱為編譯器),編譯器可以把高級語言編寫的語句翻譯成等價的 機器指令。系統程序員的角色變得更加明顯,系統程序員編寫諸如編譯器這樣的輔助工具,使用這些工具編寫應用程序的人,稱為應用程序員。隨著包圍硬件的軟件 變得越來越復雜,應用程序員離計算機硬件越來越遠了。那些僅僅使用高級語言編程的人不需要懂得機器語言和匯編語言,這就降低了對應用程序員在硬件及機器指 令方面的要求。因此,這個時期有更多的計算機應用領域的人員參與程序設計。 由于高級語言程序需要轉換為機器語言程序來執行,因此,高級語言對軟硬件資源的消耗就更多,運行效率也較低。由于匯編語言和機器語言可以利用計算機的所有 硬件特性并直接控制硬件,同時,匯編語言和機器語言的運行效率較高,因此,在實時控制、實時檢測等領域的許多應用程序仍然使用匯編語言和機器語言來編寫。 在第一代和第二代軟件時期,計算機軟件實際上就是規模較小的程序,程序的編寫者和使用者往往是同一個(或同一組)人。由于程序規模小,程序編寫起來比較容 易,也沒有什么系統化的方法,對軟件的開發過程更沒有進行任何管理。這種個體化的軟件開發環境使得軟件設計往往只是在人們頭腦中隱含進行的一個模糊過程, 除了程序清單之外,沒有其他文檔資料。
第三代軟件(1965-1970)
在這個時期,由于用集成電路取代了晶體管,處理器的運算速度得到了大幅度的提高,處理器在等待運算器準備下一個作業時,無所事事。因此需要編寫 一種程序,使所有計算機資源處于計算機的控制中,這種程序就是操作系統。 用作輸入/輸出設備的計算機終端的出現,使用戶能夠直接訪問計算機,而不斷發展的系統軟件則使計算機運轉得更快。但是,從鍵盤和屏幕輸入輸出數據是個很慢 的過程,比在內存中執行指令慢得多,這就導致了如何利用機器越來越強大的能力和速度的問題。解決方法就是分時,即許多用戶用各自的終端同時與一臺計算機進 行通信。控制這一進程的是分時操作系統,它負責組織和安排各個作業。 1967 年,塞繆爾(A.L.Samuel)發明了第一個下棋程序,開始了人工智能的研究。1968 年荷蘭計算機科學家狄杰斯特拉(Edsgar W.Dijkstra)發表了論文《GOTO 語句的害處》,指出調試和修改程序的困難與程序中包含 GOTO 語句的數量成正比,從此,各種結構化程序設計理念逐漸確立起來。 20 世紀 60 年代以來,計算機用于管理的數據規模更為龐大,應用越來越廣泛,同時,多種應用、多種語言互相覆蓋地共享數據集合的要求越來越強烈。為解決多用戶、多應用 共享數據的需求,使數據為盡可能多的應用程序服務,出現了數據庫技術,以及統一管理數據的軟件系統——數據庫管理系統 DBMS。 隨著計算機應用的日益普及,軟件數量急劇膨脹,在計算機軟件的開發和維護過程中出現了一系列嚴重問題,例如:在程序運行時發現的問題必須設法改正;用戶有 了新的需求必須相應地修改程序;硬件或操作系統更新時,通常需要修改程序以適應新的環境。上述種種軟件維護工作,以令人吃驚的比例消耗資源,更嚴重的是, 許多程序的個體化特性使得他們最終成為不可維護的,“軟件危機”就這樣開始出現了。1968 年,北大西洋公約組織的計算機科學家在聯邦德國召開國際會議,討論軟件危機問題,在這次會議上正式提出并使用了“軟件工程”這個名詞。
第四代軟件(1971-1989)
20 世紀 70 年代出現了結構化程序設計技術,Pascal 語言和 Modula-2 語言都是采用結構化程序設計規則制定的,Basic 這種為第三代計算機設計的語言也被升級為具有結構化的版本,此外,還出現了靈活且功能強大的C語言。 更好用、更強大的操作系統被開發了出來。為 IBM PC 開發的 PC-DOS 和為兼容機開發的 MS-DOS 都成了微型計算機的標準操作系統,Macintosh 機的操作系統引入了鼠標的概念和點擊式的圖形界面,徹底改變了人機交互的方式。 20 世紀 80 年代,隨著微電子和數字化聲像技術的發展,在計算機應用程序中開始使用圖像、聲音等多媒體信息,出現了多媒體計算機。多媒體技術的發展使計算機的應用進入 了一個新階段。 這個時期出現了多用途的應用程序,這些應用程序面向沒有任何計算機經驗的用戶。典型的應用程序是電子制表軟件、文字處理軟件和數據庫管理軟件。 Lotus1-2-3 是第一個商用電子制表軟件,WordPerfect 是第一個商用文字處理軟件,dBase III 是第一個實用的數據庫管理軟件。
第五代軟件(1990-今)
第五代軟件中有三個著名事件:在計算機軟件業具有主導地位的 Microsoft 公司的崛起、面向對象的程序設計方法的出現以及萬維網(World Wide Web)的普及。 在這個時期,Microsoft 公司的 Windows 操作系統在 PC 機市場占有顯著優勢,盡管 WordPerfect 仍在繼續改進,但 Microsoft 公司的 Word 成了最常用的文字處理軟件。20 世紀 90 年代中期,Microsoft 公司將文字處理軟件 Word、電子制表軟件 Excel、數據庫管理軟件 Access 和其他應用程序綁定在一個程序包中,稱為辦公自動化軟件。 面向對象的程序設計方法最早是在 20 世紀 70 年代開始使用的,當時主要是用在 Smalltalk 語言中。20 世紀 90 年代,面向對象的程序設計逐步代替了結構化程序設計,成為目前最流行的程序設計技術。面向對象程序設計尤其適用于規模較大、具有高度交互性、反映現實世界 中動態內容的應用程序。Java、C++、C#等都是面向對象程序設計語言。 1990 年,英國研究員提姆·柏納李(Tim Berners-Lee)創建了一個全球 Internet 文檔中心,并創建了一套技術規則和創建格式化文檔的 HTML 語言,以及能讓用戶訪問全世界站點上信息的瀏覽器,此時的瀏覽器還很不成熟,只能顯示文本。 軟件體系結構從集中式的主機模式轉變為分布式的客戶機/服務器模式(C/S)或瀏覽器/服務器模式(B/S),專家系統和人工智能軟件從實驗室走出來進入 了實際應用,完善的系統軟件、豐富的系統開發工具和商品化的應用程序的大量出現,以及通信技術和計算機網絡的飛速發展,使得計算機進入了一個大發展的階 段。 在計算機軟件的發展史上,需要注意“計算機用戶”這個概念的變化。起初,計算機用戶和程序員是一體的,程序員編寫程序來解決自己或他人的問題,程序的編寫 者和使用者是同一個(或同一組)人;在第一代軟件末期,編寫匯編器等輔助工具的程序員的出現帶來了系統程序員和應用程序員的區分,但是,計算機用戶仍然是 程序員;20 世紀 70 年代早期,應用程序員使用復雜的軟件開發工具編寫應用程序,這些應用程序由沒有計算機背景的從業人員使用,計算機用戶不僅是程序員,還包括使用這些應用軟 件的非專業人員;隨著微型計算機、計算機游戲、教育軟件以及各種界面友好的軟件包的出現,許多人成為計算機用戶;萬維網的出現,使網上沖浪成為一種娛樂方 式,更多的人成為計算機的用戶。今天,計算機用戶可以是在學習閱讀的學齡前兒童,可以是在下載音樂的青少年,可以是在準備畢業論文的大學生,可以是在制定 預算的家庭主婦,可以是在安度晚年的退休人員,所有使用計算機的人都是計算機用戶。
(PS:摘自 WIKI)
1940 之前
第一個編程語言比現代的計算機還早誕生。首先,這種語言是種編碼(en:code)。 于 1801 年發明的提花織布機(或稱甲卡提花織布機,英文:en:Jacquard loom),運用打孔卡上的坑洞來代表縫紉織布機的手臂動作,以便自動化產生裝飾的圖案。 Ada Lovelace 在 1842 年至 1843 年間花費了九個月,將意大利數學家 Luigi Menabrea 關于查爾斯·巴貝奇新發表機器分析機的回憶錄翻譯完成。她于那篇文章后面附加了一個用分析機計算伯努利數方法的細節,被部分歷史學家認為是世界上第一個電 腦程序。這個故事我們上面也說過。 Herman Hollerith 在觀察列車長對乘客票根在特定位置打洞的方式后,意識到他可以把資訊編碼記載到打孔卡上,隨后根據這項發現使用打孔卡來編碼并紀錄 1890 年的人口統計資料。 第一個嚴格意義上的計算機程式碼是針對他們的應用面設計的。在 20 世紀的前十年主要是用十進制來算數,后來人們發現不只是用文字,也可以用數字來表現邏輯。舉例來說,阿隆佐·邱奇曾以公式化(formulaic)的方式 表達λ演算。圖靈機是一種紙帶標記(tape-marking)機器(就像電話公司用的那種)操作方法抽象化后的集合。圖靈機這種透過有限數字 (finite number)呈現機器的方式,奠定了程式如同馮·諾伊曼結構計算機中的資料一樣地儲存的基礎。但不同于λ演算,圖靈機的程式碼并沒有辦法成為高階編程語 言的基石,這是是因為它主要的用途是分析算法的復雜度。 就像許多歷史上的”第一次”一樣,第一個現代編程語言也很難界定。最一開始是因為硬件限制而限定了語言,打孔卡允許 80 行(column)的長度,但某幾行必須用來記錄卡片的順序。FORTRAN 則納入了一些與英文字詞相同的關鍵字,像是”IF”、”GOTO”(原字詞為 go to),以及”CONTINUE”。之后采用磁鼓(magnetic drum)作為內存使用,也代表計算機程式也必須插入(interleave)到磁鼓的轉動(rotation)中。和現今比較起來,這也讓編程語言必須 更加依賴硬件(hardware-dependent)。 對部分的人認為必須在”編程語言”的狀態確立之前,根據能力(power)以及可讀性(human-readability)的程度來決定歷史上第一個編 程語言是什么語言。提花織布機和查爾斯·巴貝奇所制作的差分機(en:Difference Engine)都具備在大量限制下,簡單描述機器應執行行為的語言。也有種并非設計給人類運用的受限特定領域語言(en:domain-specific language),是將打孔卡運用到自動演奏鋼琴(en:player piano)上。
1940 年代
最早被確認的現代化、電力啟動(electrically powered)的計算機約在 1940 年代被創造出來。程式設計師在有限的速度及內存容量限制之下,撰寫人工調整(hand tuned)過的組合語言程式。而且很快就發現到使用組合語言的這種撰寫方式需要花費大量的腦力(intellectual effort)而且很容易出錯(error-prone)。 Konrad Zuse 于 1948 年發表了他所設計的 Plankalkül編程語言的論文[1]。但是在他有生之年卻未能將該語言實作,而他原本的貢獻也被其他的發展所孤立。 在這段期間被開發出來的重要語言包括有:
1950 與 1960 年代
有三個現代編程語言于 1950 年代被設計出來,這三者所衍生的語言直到今日仍舊廣泛地被采用:
另一個 1950 年代晚期的里程碑是由美國與歐洲計算機學者針對”算法的新語言”所組成的委員會出版的 ALGOL 60 報告(名稱取自”ALGOrithmic Language”(算法語言))。這份報告強化了當時許多關于計算的想法,并提出了兩個語言上的創新功能:
另一個創新則是關于語言的描述方式:一種名為巴科斯-諾爾范式 (BNF)的數學化精確符號被用于描述語言的語法。之后的編程語言幾乎全部都采用類似 BNF 的方式來描述程式語法中上下文無關的部份。BNF 主要使用在了 Algol 60 的設計上面。而 Algol 60 對之后語言的設計上帶來了特殊的影響,在其他部分的語言設計中這種設計思想很快的就被廣泛采用。并且后續為了開發 Algol 的擴充子集合,設計了一個名為 Burroughs (en:Burroughs large systems)的大型系統。而延續 Algol 的關鍵構想所產生的成果就是 ALGOL 68:
整個語言及語意的部分都透過為了描述語言而特別設計的 Van Wijngaarden grammar 來進行正式的定義,而不僅止于上下文無關的部份。Algol 68 一些較少被使用到的語言功能(如同步與并列區塊)、語法捷徑的復雜系統,以及型態自動強制轉換(coercions),使得實作者興趣缺缺,也讓 Algol 68 獲得了很難用(diffcult)的名聲。尼克勞斯·維爾特就干脆離開該設計委員會,另外在開發出更簡單的 Pascal 語言。 在這段期間被開發出來的重要語言包括有:
1967-1978:確立了基礎范式
1960 年代晚期至 1970 年代晚期的期間中,編程語言的發展也有了重大的成果。大多數現在所使用的主要語言范式都是在這段期間中發明的:
這些語言都各自演展出自己的家族分支,現今多數現代編程語言的祖先都可以追朔他們其中至少一個以上。 在 1960 年代以及 1970 年代中結構化程式設計的優點也帶來許多的爭議,特別是在程式開發的過程中完全不使用 GOTO。這項爭議跟語言本身的設計非常有關系:某些語言并沒有包含 GOTO,這也強迫程式設計師必須結構化地編寫程式。盡管這個爭議在當時吵翻了天,但幾乎所有的程式設計師都同意就算語言本身有提供 GOTO 的功能,在除了少數罕見的情況下去使用 GOTO 是種不良的程序風格。結果是之后世代的編程語言設計者發覺到結構化編程語言的爭議實在既乏味又令人眼花撩亂。 在這段期間被開發出來的重要語言包括有:
1980 年代:增強、模組、效能
1980 年代的編程語言與之前相較顯得更為強大。C++合并了面向對象以及系統程式設計。美國政府標準化一種名為 Ada 的系統編程語言并提供給國防承包商使用。日本以及其他地方運用了大量的資金對采用邏輯編程語言結構的第五代語言進行研究。函數編程語言社群則把焦點轉移到 標準化 ML 及 Lisp 身上。這些活動都不是在開發新的范式,而是在將上個世代發明的構想進一步發揚光大。 然而,在語言設計上有個重大的新趨勢,就是研究運用模組或大型組織化的程式單元來進行大型系統的開發。Modula、Ada,以及 ML 都在 1980 年代發展出值得注意的模組化系統。模組化系統常拘泥于采用泛型程式設計結構:
盡管沒有出現新的主要編程語言范式,許多研究人員仍就擴充之前語言的構想并將它們運用到新的內容上。舉例來說,Argus 以及 Emerald 系統的語言配合面向對象語言運用到分散式系統上。 1980 年代的編程語言實際情況也有所進展。計算機系統結構中 RISC 假定硬件應當為編譯器設計,而并非為人類設計。借由中央處理器速度增快的幫助,編譯技術也越來越進展神速,RISC 的進展對高階語言編譯技術發展來不小的貢獻。 在這段期間被開發出來的重要語言包括有:
1990 年代:互聯網時代
1990 年代未見到有什么重大的創新,大多都是以前構想的重組或變化。這段期間主要在推動的哲學思想是提升程式設計師的生產力。許多”快速應用程式開發” (RAD) 語言也應運而生,這些語言大多都有相應的集成開發環境、垃圾回收等機制,且大多是先前語言的衍生語言。這類型的語言也大多是面向對象的編程語言,包含有 Object Pascal、Visual Basic,以及C#。Java 則是更加保守的語言,也具備垃圾回收機制。與其他類似語言相比,也受到更多的觀注。新的腳本語言則比 RAD 語言更新更好。這種語言并非直接從其他語言衍生,而且新的語法更加開放地(liberal)與功能契合。雖然腳本語言比 RAD 語言來的更有生產力,但大多會有因為小程式較為簡單,但是大型程式則難以使用腳本語言撰寫并維護的顧慮[來源請求]。盡管如此,腳本語言還是網絡層面的應 用上大放異彩。 在這段期間被開發出來的重要語言包括有:
現今的趨勢
編程語言持續在學術及企業兩個層面中發展進化,目前的一些趨勢包含有:
在這段期間被開發出來的重要語言包括有:
需求
在回顧這些歷史的時候發現,我們無論是創造程序語言還是計算機,或者軟件也好,最終的目的都是為了兩個字——需求。我們遵循著工具理性的框架,追尋著完成需求的目標。而在計算機發展的過程的過程中,主要的需求有哪些?
當然,我們必須先解決的第一個需求就是我們創造計算機的原始需求:創造工具來滿足人們現實生活中的需求。但是像絕大部分工具一樣,一旦我們穿鑿 了它,它本省也會衍生出來很多需求。工具本身也需要演化。而工具本身的需求就是后兩條。 滿足第一條需求的方式,千奇百怪!基本上會涉及到人類現已掌握的知識的各個層面。比如一個圖書分享網站,最起碼要涉及:管理學、心理學、營銷、產品設計、 美術設計、交互設計、圖書館管理等等。而這些知識通過軟件設計物化在了網站這個東西上面。然后我們就能通過網站這個工具,來滿足我們圖書分享的需求。 但是,我們能夠發現,其實程序設計(程序員思維的最主要的展現形式)雖然與第一條需求有關,但又關系不是很大。的確,我們是通過軟件設計這件事情,物化了 我們的知識。但是在這個過程中,軟件設計并不關系人們的需求具體是什么,是圖書網站,還是聊天軟件和軟件設計并沒有直接的關系。相對來說,軟件設計比較關 心的是后面兩個需求:來自工具本身的需求。用一句話說就是:Make it work, Keep it simple。 首先你必須讓這個工具能夠工作,其次你必須讓這個工具能夠持續穩定的工具的工作(不會因為規模擴大,復雜性增長而招致災難)。而這就是程序員思維中在工具 理性下面最為核心的兩個具體的概念:Make it work, keep it simple。 明白了這一點,我們再回過頭去看一下剛剛所述的軟件和程序設計的歷史。剛開始人們需要有一個機器替代人進行計算于是有了差分機和 ENIAC,有了硬件之后,自然就需要一種驅動機制能夠讓這些機器能夠運轉起來,于是我們發明了程序語言和軟件。而隨著硬件的不斷發展和軟件規模的不斷擴 大,人們發現最原始的計算機語言(機器語言)不使用于快速開發。于是就有了匯編這樣的低級語言。后來低級語言也被證明在開發速度上存在缺陷,也不太適合快 速開發,于是我們有了高級語言,比如 Lisp、C、fortran。剛開始的時候這些高級語言,的確能夠滿足快速開發的需求。但是,隨著軟件規模的不斷擴大。我們開始發現:靠,我們創造了軟 件卻控制不了軟件。計算機和軟件這個工具的規模已經超出了人類能夠認知的規模,它的復雜性已經開始變得不可控了。這怎么能行呢,于是我們開始創造了面向對 象和軟件工程等理論工具來幫助我們控制這種軟件復雜性。 而到了今天,我們看一下我們日常 Coding 中常見的那些理論的方法,基本上也都是圍繞著 Make it work, keep simple 展開的。其實這兩個問題是不能夠割裂開闡述的,為了理解上方面,我們就先單獨說吧,不過中間會有概念的穿插。
Make it work (編程范式,程序語言的世界觀)
如何讓計算機按照我們制定的方式工作,如何讓軟件能夠按照我們假象的方式運行?我們把完成這兩個需求的過程叫做程序設計。就是我們在前文中所 說:程序設計就是利用計算機將知識物化,并利用知識的可復現性來對現實產生作用。但是,這只是一個概念啊。如何才能把它落實到實踐上呢?這就要說一下編程 范式了,我們對于程序語言是什么的世界觀。 編程范型或編程范式(英語:Programming paradigm),(范即模范之意,范式即模式、方法),是一類典型的編程風格,是指從事軟件工程的一類典型的風格(可以對照方法學)。如:函數式編 程、程序編程、面向對象編程、指令式編程等等為不同的編程范型。 編程范型提供了(同時決定了)程序員對程序執行的看法。例如,在面向對象編程中,程序員認為程序是一系列相互作用的對象,而在函數式編程中一個程序會被看 作是一個無狀態的函數計算的串行。編程范式就是我們程序設計的世界觀,他決定了程序在我們眼中是個什么樣,而我們又怎樣去操作或者使用程序語言。 正如軟件工程中不同的群體會提倡不同的“方法學”一樣,不同的編程語言也會提倡不同的“編程范型”。一些語言是專門為某個特定的范型設計的(如 Smalltalk 和 Java 支持面向對象編程,而 Haskell 和 Scheme 則支持函數式編程),同時還有另一些語言支持多種范型(如 Ruby、Common Lisp、Python 和 Oz)。 很多編程范型已經被熟知他們會禁止使用哪些技術,同時又允許使用哪些技術。 例如,純粹的函數式編程不允許有副作用;結構化編程不允許使用 goto。可能是因為這個原因,新的范型常常被那些慣于較早的風格的人認為是教條主義或過分嚴格。然而,這樣避免某些技術反而更加證明了關于程序正確性 ——或僅僅是理解它的行為——的法則,而不用限制程序語言的一般性。 編程范型和編程語言之間的關系可能十分復雜,由于一個編程語言可以支持多種范型。例如,C++設計時,支持過程化編程、面向對象編程以及泛型編程。然而, 設計師和程序員們要考慮如何使用這些范型元素來構建一個程序。一個人可以用 C++ 寫出一個完全過程化的程序,另一個人也可以用 C++ 寫出一個純粹的面向對象程序,甚至還有人可以寫出雜揉了兩種范型的程序。 下面是我們比較常見的幾種“程序語言的世界觀”:
名稱 | 代表語言 | 核心概念 | 運行機制 | 關鍵突破 | 實現原理 | 主要目的 | 常見應用 | </tr> </thead>|||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
命令式/過程式(Impreative/procedural) | Fortran/Pascal/C | 命令、過程 | 命令執行 | 突破單一主程序和非結構化程序的限制 | 引入邏輯控制和子程序 | 模擬機器思維,實現自頂向下的模塊設計 | 交互式、事件驅動型系統、數值計算等 | </tr>|||||||||||||||||||
函數式、應用式(Functional、Applicative) | Scheme/Haskell | 函數 | 表達式計算 | 突破機器思維的限制引入高階函數、將函數作為數據處理 | 模擬數學思維,簡化代碼,減少副作用 | 微積分計算、數學邏輯、博弈等 | </tr> | |||||||||||||||||||
邏輯式 | Prolog/Mercury | 斷言 | 邏輯推理 | 突破邏輯與控制粘合的限制 | 利用推理引擎在已知的事實和規則的基礎上進行邏輯推斷 | 專注邏輯分析、減少代碼 | 機器證明、專家系統、自然語言處理、語義網、決策分析、業務規則管理等 | </tr>|||||||||||||||||||
對象式(Object-Oriented) | Smaltalk/Java/Objc | 對象 | 對象間信息交互 | 突破數據與代碼分隔的限制 | 引入封裝、繼承和多態機制 | 迎合人類認知模式,提高軟件的易用性和重用性 | 大型復雜交互系統等 | </tr>|||||||||||||||||||
并發式/并行式(Concurrent/Parallel) | Erlang/Oz | 進程、線程 | 進程、線程、協程間通信與同步 | 突破串行的限制 | 引入并行的線程模塊以及模塊間的通信與同步機制 | 充分利用資源、提供運行效率、提高軟件的響應能力 | 圖形界面,IO 處理,多任務系統,計算密集型系統 | </tr>|||||||||||||||||||
泛型式(Generic) | Ada/Eiffel/C++ | 算法 | 算法實例化(多發生于編譯期) | 突破靜態類型語言的限制 | 利用模板推遲類型指定 | 提高算法的普適性 | 普適性算法如排序、搜索等,集合類容器等 | </tr>|||||||||||||||||||
元編程(Meta programming) | Lisp/Ruby/JavaScript | 元程序 | 動態生成代碼或者自動修改執行指令 | 突破語言的常規語法限制 | 利用代碼生成或語言內奸的反射、動態等機制,將程序語言作為數據處理 | 減少手工編碼、提高語言級別 | 自動代碼生成、定義結構化配置文件,IDE、編譯器,解釋器,人工智能、領域特定語言等 | </tr>|||||||||||||||||||
切面式(Aspect-Oriented) | AspectJ/AspectC++ | 切面 | 在接入點處執行建議 | 突破橫切關注點無法模塊化的限制 | 通過編制將附加行為嵌入主題程序 | 實現橫切關注點分割 | 日志輸出、代碼耿宗、性能監控、異常處理、安全檢查等 | </tr>|||||||||||||||||||
時間驅動(Event-Driven) | C#/VB.NET | 事件 | 監聽器收到事件后做出響應 | 突破順序、同步的流程限制 | 引入控制反轉和異步機制 | 調用者與被調用者在代碼和時間上雙重解耦 | 圖形界面、網絡應用、服務器、異步輸入等、DOM 等 | </tr> </tbody> </table>