程式語言的世代演進,可以說是江山代有才人出,雖然不至於一代新人換舊人,有時卻也是老兵不死只是淍零,受歡迎的程式語言,終究還是會有較高的市場占有率、被更多的程式設計者所採用。

撰寫程式會面臨到的兩種困難
在軟體大師Frederick P. Brooks的著名文章〈No Silver Bullet〉一文中指出了,撰寫程式要克服兩種困難,一種稱為附屬性(accidental)的困難,而另一種則是本質上的困難。

之所以會有附屬性的困難,是因為程式設計的工具不對,這邊的程式設計工具,可能包括程式語言、程式設計的模型或方法等等。這類型的困難,可以透過改變、提升所使用的程式設計工具來獲得解決。例如,在C/C++中讓程式設計者自行配置所欲使用的記憶體空間(malloc/free或new/delete),而這類的程式設計模型下,程式設計者容易犯錯,有很多的程式設計問題,例如memory leak,都是因為這樣的程式設計模型衍生出來的。而在Java這個程式語言中,便利用垃圾收集機制(Garbage Collection),改變記憶體操作的程式設計模型,因而規避掉了因為記憶體配置、釋放所造成的各種問題。這就是用程式設計工具解決的附屬性困難。

但是,另一類的本質性的困難,就像是要處理程式碼之間交錯影響的各種複雜效應,例如一旦修改了某一段程式碼,想評估所有受到影響的其他程式碼。這類型的困難,從Frederick P. Brooks大師的觀點來看,是沒有辦法透過程式設計工具來解決的。

程式語言的世代變化,基本上,逐步地解決各種附屬性困難。

例如,組合語言的問世,解決了人們必須單純使用機器語言這種完全不具可讀性、難以記憶的方式來撰寫程式的障礙。因為早期人們利用電腦程式所解決的問題,大多是數學或是工程計算的問題,以組合語言來撰寫並不便利。

而像Fortran之類的程式語言,則進一步讓人們可以以類似代數形式的寫作方式,來描述如何進行計算,這又是一個很大的演進。

之後的結構化程式語言,解決了諸如GOTO之類指令隨意進行流程跳躍,而造成程式複雜度大增的問題。而物件導向程式語言,更嘗試著以新的思維來解決軟體複雜度的問題。

我們可以說,程式語言世代的交替更迭,在解決各種附屬性困難的同時,幾乎都是為了同一個目標在努力,也就是提高軟體開發時的生產力,讓程式設計者,可以花更少的時間,進而開發出更好品質的軟體。

程式語言的選擇
約在2006年時,我留意到Ruby這個程式語言,是因為臺灣開始有一些網站採用RoR進行開發,而且在生產力上得到了不錯的結果。生產力始終是最吸引程式設計者的一項因素,在那之後,身邊陸續便有不少朋友投入Ruby/RoR的領域,開始採用它們來開發Web應用程式。

當時,我已經採用Java開發Web應用程式好一段時間了,而Java也已經成了十分主流的Web應用程式開發語言,自然而然的,Ruby/RoR的組合時常會拿來和以Java為基礎的Web應用程式開發進行比較。那為什麼我不採用Ruby/RoR來開發呢?

關於這個問題的答案,一方面基於個人的偏好,我比較喜歡編譯式的程式語言、而且也比較喜歡靜態型別的程式語言。而另一方面,是因為我們利用Java來開發,並沒有遭遇到太嚴重的生產力問題。

事實上,我認為軟體開發的生產力是由許多環節所影響著,不單只是由程式語言或應用程式框架所導致。會影響生產力的因素包括了程式語言、程式庫、應用程式框架、你所做的設計、你所採用的開發工具、甚至開發方法及流程,也都深深地牽動開發時的生產力。

選擇從一個程式語言及平臺遷移到另一個程式語言及平臺,是關係極大的一件事,因為這意謂著你之前在這個語言、平臺上所開發的眾多既有程式碼、程式庫及經驗,都即將歸零,而新語言、新應用程式框架的重新適應及熟悉,都需要時間,倘若不會產生明顯提升,因而,遷移到另一個語言及應用程式框架上,不見得能在生產力上得到真正的好處。當影響生產力的因素眾多時,從語言或應用程式框架上所帶來的生產力、影響力,就有可能在眾多的因素中稀釋。

在眾多影響生產力的因素中,無疑的,程式語言本身是程式設計者最關心的因素之一。從各世代程式語言的演變,就能明白程式語言的發明者嘗試著為程式語言加入新的概念,試圖解決生產力問題的努力。

C++ vs. Java
從Java程式語言改善C++問題的方法上,我們可以觀察到一些端倪。

C++推出的時候,以C的語法為基礎,加入了物件導向的觀念。或許很多人會批評C++的物件導向不夠純粹,但即使現在回顧,都可以理解,這些在物件導向純粹性上所做的折衷,其實大多都是為了效率的考量。

在當時的時空背景下,要推出一個讓世人在效能上可以接受、但又能融入重要的物件導向特性,我想C++的發明者已經做了最大的努力,也取得了一個他心目中完美的平衡點。不過,在現實的開發生活中,C++還是讓程式設計者遭遇到一些困難。

之後Java興起,成了一個主流的程式語言,我們可以說Java試著以C++做為一個模仿、但同時也是一個反省的目標,反省它讓程式設計者在現實開發生活中所遭遇到的困難,試著進行一些改進。

所以有人說,Java是C++ --。它一方面削除了C++中所具備的一些強力機制,試著讓Java變得更簡單一點,而在損失一些威力的情況下,卻可以讓Java在開發上更有生產力。另一方面,也試著改變一些從C/C++以降的既有程式設計模型,即使Java和它們流著同源的血統。

舉例來說,Java引入了垃圾收集的機制,這改變了傳統C/C++中將記憶體配置及釋放的工作,交由程式設計者自行操控的情況。這是一個很大的改變。垃圾收集的概念在Java問世之前就已經存在很久,但始終沒有成為主流,有個關鍵的原因就是效率的問題。當垃圾收集機制運作時,它會嘗試開始收集需要被回收的記憶體空間,而判斷及回收都需時間,這些都要在執行期間付出成本。那為什麼Java寧可付出效率做為代價,來換取垃圾收集機制呢?這實在是因為,讓程式設計者自行配置、釋放記憶體,會對生產力造成很大的影響。

在C/C++程式中,有很高比例的程式臭蟲來自於記憶體配置所衍生的問題,例如,程式中可能配置了記憶體但卻沒有加以釋放,因而產生了memory leak,另一方面,程式設計者也有可能重複釋放了同一塊記憶體區域,因而造成了錯誤。無論是那一種情況,讓程式設計者自行配置、釋放記憶體空間的程式設計模型,會增加程式設計者犯錯的機會,滋生程式中的臭蟲。而這會深深地影響到生產力。因為,不論你寫程式有多快,只要程式中暗藏了一個臭蟲,那麼你就必須付出數倍於撰寫這段程式碼的代價,才能加以修正,這當然是生產力的大敵。

而Java從避免程式設計者犯錯的角度來進行改變,期望能夠藉此增加生產力。

專欄作者

熱門新聞

Advertisement