無論是哪個一開始號稱簡單、優雅、彈性的語言或技術,終究會因為聚集或為了聚集更多使用者,而納入越來越多的特性,逐漸地,若不是一開始參與而是半路投入之開發者會開始迷路,因而必須勾勒出技術地圖或生態樹以避免迷失,而從起初時就追著技術跑的開發者,亦開始抱怨生態系日趨複雜,就如《The Productive Programmer》作者Neal Ford之言:「再演進的話,就會變得笨重,然後因其自身之重量而崩塌。」接著,另一個技術生態興起,然後,再度上演相同的戲碼。

腫脹的技術與專案生態

經濟學家Pareto從義大利20%人口擁有80%財產的觀察中,提出了80/20法則,指出在眾多現象中,80%的結果取決於20%的原因,這個法則在軟體中也常被觀察到,像是80%左右的執行次數發生在20%左右的程式碼。

不少號稱簡單、快速的開發技術,或多或少也是明示或暗示地這麼宣傳著:「多數的情況下你只需要這些功能」,然而就如Joel Spolsky在〈腫脹軟體與80/20迷思〉中提到:「很不幸地,那20%是會變的。每個人會用到不同的功能集。」

因為每個人會用到不同的功能集,隨著人群聚集,語言或技術生態會逐漸腫脹,正因為每個人會用到不同的功能集,專案中也逐漸在單一技術不符合需求時,納入了更多種技術,以因應日趨複雜的軟體需求。

看看那些Polyglot programming、Polyglot persistence、Polyglot paradigm等文章,往往很容易成為熱門話題,就可以發現:軟體系統彷彿符合熱力學中熵(失序)不會減少的定律,技術的複雜程度只會日益增加,開發者得疲於應付層出不窮的新風格、新概念、新模型或典範。

Java怎麼來到這個地步?

任何語言或技術的出現,當然都是為了解決現存語言或技術的某些問題,Java也不例外,它消減了C/C++的一些功能,避免了這些功能可能引發的問題,它在適當時間(網際網路興起之時)與地點(瀏覽器)出現,迅速地贏得越來越多開發者的青睞,在開發者認為瀏覽器不是執行大型應用的好地方時,Java順勢地從瀏覽器轉移至伺服端舞臺,這更大的舞臺吸引到更多的開發者,Java被寄于更多的期待,生態因而日趨複雜,就連語言本身也加入越來越多的複雜元素……

很少人會為了把事情搞得複雜,而加入複雜的元素,多半是一開始聽起來很棒,單方面看來能讓程式撰寫更簡便的東西。

泛型(Generic)顯然就是如此,追溯泛型的本意,是為了減輕開發者使用靜態語言時必須時刻在意型態的負擔,並讓編譯器能協助開發者檢查出型態錯誤,然而如我先前專欄〈參數多型用於減輕型態負擔〉中探討過的,Java泛型實際上是對過去參數多型(Parametric polymorphism)概念的一種實現,不過它並非Java與生俱來,而是對Java既有型態系統作擴充,新能力帶來的好處,是以加深既有型態系統複雜度為代價。

程式設計越來越常面對平行處理需求,人們遭受的挫折也就越來越多,在尋找方案的過程中,目光逐漸往函數式設計投射,比Java晚生幾年的Scala,打著整合物件導向和函數式的旗鼓,向Java生態圈揮軍而來,而在Java生態圈中,亦有不少程式庫試圖實現函數式概念,只不過仍得使用醜陋的Functor與匿名類別,最後Java還是加入了Lambda語法來解除窘境,過去泛型的聲名狼藉,在結合型態推斷(Type inference)與Lambda表示式(Expression)時,稍稍獲得了平反,只不過,複雜度不會憑空消失,看看JDK8中java.util.function與java.util.stream套件的API就知道,重擔子終究會落到設計函式介面(Functional interface)與API的開發者身上。

Java引入Lambda不只是為了解決醜陋的匿名類別,還打算併入這些日子以來,一些其他語言生態中看似好的元素,惰性求值、流暢API、高階語義程式庫等,當然還有其最初之目的,增進Java的平行處理能力,為了讓這些概念在既存API上擴充實現,Java還做了另一個強力擴展語言能力的決定:解放了介面過去不能定義實作的限制。實際上明眼人一看也知道,這是引入更多實現多重繼承的可能性,當然,在判斷實作來源時,也就更加複雜。

不動就會死的鯊魚?

Neal Ford在《The Productive Programmer》中談到:「電腦語言就像鯊魚,靜止不動就會死掉。」如果看著JDK6後沉寂不動的那四年多(也許還包括JDK7後的這些日子),似乎有點道理,這中間不知道製造出多少Java已死的文章,在一些不需要Java那麼多功能(與複雜度)的戰場,Java失去了一些開發者,也失去了鎂光燈,表面上看來,沒什麼人在討論Java了。

然而不動就會死的論調,似乎沒印證在出現於不對時間、地點,還取了個易被人誤解之名的JavaScript身上,雖然瀏覽器大戰幾乎毀了它,還好各家瀏覽器視其為食之無味、棄之可惜的雞肋,令其得以靜靜地等待到適當時間而鹹魚翻身,這段期間以來,JavaScript幾乎就是靜止不動的語言,可用語法基本上就是古老的ECMA-262規範,即便如此,鹹魚翻身之後,人就開始聚集,人多之後,就會發生很多化腐朽為神奇的事,人們先是為幾乎一無所有的JavaScript,在瀏覽器舞臺上建立龐大生態系,辦到了Java沒辦到之事,接著更多人聚集之後,倒是作了跟Java類似的事,將JavaScript從瀏覽器推向了伺服端……

人多的地方,也會把事情搞得很複雜,觀察幾乎靜止不動的JavaScript後來營造出的複雜生態,更可以看出問題不在語言,而在人們的需求累積。

迅速聚集的人們,將各技術生態圈中出現過的東西,迅速在JavaScript生態圈中實現,只是為了滿足這段期間累積而來的需求,像是惰性求值、流暢API、各式高階語義程式庫、非同步處理、Rails風格快速開發……這些都不是新的概念,只是在JavaScript中使用新形式實現,甚至取了個新名稱。

瞭解底層實作外更深入的探索

正因為人們的需求越來越多,曾經因關注的人不多而被拋棄已久的概念,也開始有了對應需求而重新獲得重視,因而重新納入開發考量之中,許多生態系多半就是重新吸收了這些概念而開始膨脹。

有時會發生這種事,開發者在閱讀API原始碼後,雖然能從程式碼實作瞭解工作原理,但仍不清楚這看似詭異的程式意義何在,直到有天接觸到對應的原始情境,才猛然意識到API真正應用場合,接下來接觸到原始情境衍生出來的其他特殊實現時,反而會讓開發者更瞭解到相同概念是如何隨著時間演進,建立起《學徒模式》中提到的知識心理結構(Mental structure),知道不同原始情境會對應不同需求,有能力適時地依原始情境瞭解並採用特定實現,不會被外在形式給蒙蔽,不致於被龐大的生態系給淹沒!

語言或技術日趨複雜,會是讓語言消失的主要原因嗎?在《Coders at work》中,Joshua Bloch給的答案是:「不會」,他認為:「這實際上是強迫人們只使用其中一個子集」,而選擇使用哪個子集的依據,就是問自己是否瞭解技術背後的原始情境,就Java而言,泛型、Lambda、Stream API該用到何種程度,就是如此,而在任何含有多重(Polyglot)概念的技術生態中,也是如此! 

專欄作者

熱門新聞

Advertisement