Kotlin是一門相對比較新的JVM語言,JetBrains自2011年以來一直在積極地開發。
多年來,該語言在Android社區受到的關注度越來越高,并在Google IO 2017大會之后成為Android開發領域最熱門的話題。這次大會宣布,Android正式支持Kotlin。
遺憾的是,雖然已經有許多關于Kotlin的文章,但并沒有多少客觀信息,許多開發人員仍然在苦思冥想,遷移到Kotlin是否是一條正確的道路。
在本文的剩余部分,我將嘗試提供一個在將Kotlin作為Java的替代項進行評估時需要考慮的更完善的事項清單。
Kotlin與Java的主觀比較“Kotlin比Java好”,“Kotlin可讀性比Java強”,“Kotlin開發速度比Java快”,類似這樣的陳述缺少相關準確數據的支持,所以都歸為主觀看法一類。
主觀看法是個體開發人員在對與Kotlin或Java相關的主題作出一個或多個主觀判斷時形成。
開發人員的主觀判斷存在如下問題:
沒有與主觀判斷相關聯的量化指標。主觀判斷存在很大的偏見。主觀判斷的偏見在開發人員之間存在很大的差異。由于沒有與主觀判斷相關聯的量化指標,建立在這些判斷基礎上的觀點只是反映出了開發人員之前就有的偏見。不同的開發人員可能有著截然不同的偏見,因此,有開發人員認為Kotlin是不錯(或糟糕)的Java替代者并不意味著其他開發人員也這么認為。
而且,由于沒有客觀指標,主觀分歧就無法客觀地消除,這經常會導致“口水戰”。
主觀判斷的謬誤為了說明主觀判斷可能導致的誤解,讓我們仔細審視一個非常常見的主觀看法:
Kotlin可讀性比Java強
——Web上無數的文章
理論上講,可以設法設計一個度量Kotlin和Java之間可讀性差異的實驗,但據我所知,沒有任何人真正地開展這樣一個實驗。因此,截至目前,這個看法沒有任何數據支撐。
Kotlin的語法是許多開發人員稱贊其可讀性的一個原因。他們的邏輯如下:
Kotlin有更好的語法,因此它的可讀性更強
——Web上無數的文章
在這句話中,“更好的語法”又是一個主觀判斷,本身就值得商榷,但為了避免爭論,我們假設Kotlin的語法確實更好。但是,這就能說明Kotlin的可讀性更強嗎?
為了觀察語法對可讀性的影響,請閱讀下這段“文本”:
開始的時候,這段“文本”很難理解,但慢慢地,讀起來會越來越容易。如果你再讀個兩三遍,那么你根本就不會再注意它是由非標準的字母組成的。準確地說,字母的替換不是句法變化,但這確實可以說明,對于熟練的讀者而言,外觀很少會成為可讀性的障礙。
我們也可以把這個例子擴展到自然語言。我了解三門截然不同的語言。雖然它們之間差別很大,但我發現,當我不理解文本中使用的單詞時,閱讀任何一種語言的文本都非常困難。一旦我認識構成文本的單詞并熟悉上下文——無論它使用了哪一種語言,我讀起來都不困難。
因此,對我而言,語言的選擇并不會影響可讀性,只要理解內容和上下文就可以了。
編程語言同樣如此。
當我們開始使用一門新語言,我們會有一段時間很難理解源代碼,需要認真領會每個句法結構。但是,隨著我們閱讀和編寫特定語言的代碼越來越多,我們逐漸就熟悉了那門語言的語法,到某個時候,我們就不會再注意句法結構了。
我自己在多門語言上有過這種體驗:Verilog、Bash、Perl、Tcl、Lisp、Java。
根據我使用上述語言的經驗,我可以告訴你:如果一個人適應了Lisp的代碼,并且不會再注意到小括號,那么跟Java比起來,Kotlin的語法完全不能對可讀性產生不可忽視的影響,即使它“更好”。
既然我們在討論這個話題,我就分享下自己對于影響源代碼可讀性因素的主觀判斷。
在讀過其他開發人員使用許多語言編寫的代碼后(上面只羅列了我在某個階段精通的語言;我用過的所有語言比這個多),我得出如下結論:如果開發人員使用某一門語言可以編寫出可讀性和可理解性都很好的代碼,那么他們通常也可以使用其他語言編寫出可讀性和可理解性都很好的代碼。
因此,我根據自己的經驗作出的主觀判斷是,源代碼的可讀性和選擇的語言無關,那取決于代碼編寫者的技能和讀者的技能(編寫者的技能更重要)。
如果你仍然認為主觀看法具有代表性,那么至少閱讀并思考下Robert “Uncle Bob” Martin在這篇博文中的觀點。
Kotlin與Java的客觀比較與主觀比較相反,客觀比較使用量化指標來度量或評估Kotlin比Java有優勢的地方。
用一套標準客觀地證明一門編程語言是否強過另一門,這種想法非常有吸引力,但是有個問題:據我所知,沒有與編程語言相關的通用客觀指標。
考慮到我們無法進行精確的直接比較,那我們能否客觀地比較Kotlin和Java呢?能!我們仍然能評估從Java切換到Kotlin所帶來的積極和消息影響的程度,然后比較結果,并討論它們的影響。
為了評估Kotlin所能帶來的最好結果,我們將做如下假設:
開發人員可以立即切換到Kotlin;切換到Kotlin后,開發人員不會損失任何技能(例如,有兩年Java開發經驗的開發人員可以神奇地獲得兩年的Kotlin開發經驗);Kotlin和Java一樣穩定;Kotlin工具和Java工具一樣成熟。事實上,上述假設沒有一個是合理的,但在開始的時候,有一個理想化的設定便于說明。然后,我們會拋開這些假設,討論真實世界的效應所帶來的影響。
Kotlin最佳結果估計遵循Steve McConnell在Code Complete一書中提出的模式,我們可以將軟件構建活動分解成三個子活動:詳細設計、編碼與調試、開發測試。
Kotlin對于詳細設計子活動沒什么影響(這項活動通常獨立于選用的特定的面向對象編程語言),因此,在這一部分,Kotlin和Java需要付出同樣的努力。
據我所知,對于開發測試子活動,Kotlin也沒有提出什么革命性的東西。因此,開發測試需要付出的努力也一樣。
就剩編碼與調試子活動了。
如果我們用Kotlin替換Java,那么我在編碼與調試活動中可以節省多少工作量?這個問題很難回答,不同程序員之間這一數值會有很大差異(有些程序員使用Java更高效)。不過,既然我們在評估最好的情況,我們不妨假設從Java切換到Kotlin可以將開發人員在編碼與調試階段的生產力平均提高10%。
10%的生產力提升是一個不現實到令人吃驚的數值。即使我們在文本編輯器中手工輸入所有代碼,那也是不現實的??紤]到現如今IDE的功能,這一數值更是不現實。考慮到有些開發人員使用Java更高效,這個數值就毫無道理了。
我不介意使用這樣一個既不現實又對Kotlin評估有利的數值,因為我知道,不管它對評估結果產生了怎樣不切實際的積極影響,一旦我們拋開其中部分“理想的假設”,由此帶來的負面影響會抵消掉那些積極影響。
那么,在編碼與調試方面提升了10%——我們把產品交付給客戶的速度快了多少?
下面這張圖片來自Code Complete一書,展示了軟件項目的各種活動所占的比例:
圖 小項目以構建活動為主。大點的項目需要更多架構、集成和系統測試工作來保證項目成功。這張圖沒有顯示需求,因為和其它活動不一樣,需求工作不是直接的程序功能。(Albrecht 1979; Glass 1982; Boehm, Gray, and Seewaldt 1984; Boddie 1987; Card 1987; McGarry, Waligora, and McDermott 1989; Brooks 1995; Jones 1998; Jones 2000; Boehm et al. 2000)
Code Complete,第二版
根據來自Code Complete的這張圖片,在一個較大的軟件項目中(多于10K行),編碼和調試只占項目總工作量的不足20%。
因此,在一個較大的軟件項目中,我們所假設的編碼和調試效率提升10%,只能將完成項目所需的總工作量縮減2%。
例如,一個需要5人年才可以完成的項目(這是相對比較大的Android項目),總工作量的2%為:
5人-年 * 12 * 4 * 5 * 0.02 = 24(人-天)如果我們真得能夠把項目工作量減少24人-天,這會是一個從Java切換到Kotlin的很好的理由。然而,我們應該還記得,上述積極評估是在理想情況下得出的,其基礎是不切實際的假設。
在真實世界里,切換到另外一門編程語言會產生不可避免的影響,我們將評估這種影響,并與上述理想化評估作個比較。
開發人員準備為了評估最好的情況,我們假設開發人員可以立即從Java切換到Kotlin。
實際上,雖然Kotlin和Java非常類似,但開發人員仍然需要花一些時間來學習,然后再花一些時間來調整開發實踐和工具。準備時間因人而異:有些開發人員可以三四天完成切換,其他人則需要10天甚至更多的時間。
讓我們樂觀一點,平均每個開發人員只要5天就可以從Java切換到Kotlin。
一個需要5人年才能完成的項目會有3到5名開發人員(最好的情況下)。平均每個開發人員的切換時間為5天,這樣,一個項目總計就需要15到25個人天的切換時間。
切換到Kotlin所節省的工作量(樂觀估計)與切換所需的總工作量似乎差不多。
開發人員技能損失使用一門特定的編程語言高效工作的能力是一項技能。
我們已經討論了這項技能的其中一個方面(代碼可讀性),但還有許多其他方面。當從一門語言切換到另一門時,與舊編程語言相關的部分技能可以運用到新語言上,但該技能的其他部分會損失掉。
為了評估編程語言技能損失對項目工作量的影響,我們將使用源自Cocomo2評估模型的“語言與工具體驗”因子:
語言與工具經驗(LTEX)
該指標用于衡量開發軟件系統或子系統的項目團隊使用編程語言和軟件工具的經驗。軟件開發包括借助工具完成需求、表現形式設計與分析、配置管理、文檔提取、庫管理、程序樣式與格式化、一致性檢查、計劃與控制等等。除了項目編程語言經驗外,項目支持工具集的經驗也會影響開發工作。經驗低于2個月會獲得一個很低的評級,有6個月或多年的經驗則會獲得一個很高的評級,見下表:
例如,假設我們有一個Java開發團隊,團隊成員平均有一年的經驗,我們想遷移到Kotlin。
由于Kotlin和Java非常像,與許多Java工具兼容。我們可以樂觀地假設,在經過初步的準備后,開發人員就可以歸為有6個月開發經驗這一類(而不是低于2個月)。根據這個假設,為了評估技能損失所導致的額外工作,項目的額定工作總量應該乘以1.09。
一個需要5人年完成的項目,配備了平均具有1年Java經驗的開發人員,切換到Kotlin所導致的額外工作達到了令人咂舌的108人天。
技能損失所導致的額外工作是切換到Kotlin所縮減的工作的四倍。
語言和工具的穩定性和成熟度有個普遍的說法,就是Kotlin是一門生產就緒的語言。這種說法也許是有道理的,因為Kotlin已經用在了若干項目里。
不過,與Java相比,Kotlin是一門并不穩定的年輕語言。
有些開發人員認為,Kotlin的不穩定性是個優勢——語言在演進,可以更快地提供新特性,更快地改進。在我看來,他們對于這件事的看法過于簡單。
下面是Kotlin 1.1.4發布說明里的第一句話(寫這篇文章時的最新版本):
修復IntelliJ IDEA的一項重大性能衰退
——Kotlin 1.1.4發布說明
我不知道這是什么樣的衰退,有多少項目受到了影響,但我的大腦自動將“重大性能衰退”這個搭配翻譯成了“浪費了許多小時的開發時間。”
此外,如果你讀一遍發布說明的評論,你就會注意到,許多人遇到了遷移問題。在1.1.2版本的評論里,甚至有人指出,這個“補丁”發布引入了破壞性(向后不兼容)的修改。
相比之下,如果你讀一遍Oracle JDK8的發布說明,你就會發現,它比較穩定。大多數修改都是安全改進方面的。
因此,與Java相比,Kotlin是一門不穩定且不成熟的語言——遷移到Kotlin會對項目產生怎樣的影響?為了回答這個問題,我將使用來自Cocomo 2評估模型的“平臺波動性”工作因子:
平臺波動性(PVOL)
這里使用“平臺”一詞指代軟件產品執行任務時調用的復雜硬件和軟件(OS、DBMS等)。如果開發的軟件是一個操作系統,那么平臺就是計算機硬件。如果開發的是數據庫管理系統,那么平臺就是硬件和操作系統。如果開發的是網絡文本瀏覽器,那么平臺就是網絡、計算機硬件、操作系統和分布式信息庫。平臺包括支撐軟件系統開發所需的編譯器或裝配器。如下表所示,如果平臺每12個月才有一次重大變更,則評級就會很低,如果每2周有一次重大變更,則評級就會很高:
Cocomo 2模型定義手冊你可能已經注意到,編程語言并沒有直接出現在該工作因子的描述里,但出現了編譯器和裝配器。在我看來,這段描述沒有顯式包含編程語言,是因為得出Cocomo 2模型的所有項目都使用了穩定的語言。
由于編譯器和裝配器屬于這個工作因子,所以我們也可以推斷出編程語言及相關工具。
根據平臺波動性的這種評級范圍,Java的評級應該是“very low”,而Kotlin的評級應該是“low”或更高。Kotlin的評級可能會更高,因為它內部依賴于其它工具,增加了出現兼容性問題的風險。
由于“very low”沒有提供工作因子,所以我們需要估計。
看下該因子從“very high”到“low”的評分遞減規律,我認為,我們可以放心的假設,“very low”的評分不高于0.82。
基于這些假設(有利于Kotlin),如果一個項目需要5人年的額定工作量,那么使用Kotlin,工作量就變成了1044人天,而使用Java的總工作量是984人天。
選擇使用Kotlin而不是Java實現這樣一個項目會使總工作量增加60人天。
語言和工具不穩定所導致的額外工作是切換到Kotlin所縮減的工作的2倍多。
綜合所有因素我當成例子來討論的項目需要5人年的額定工作量。
根據上述評估,如果該項目由平均具備1年Java開發經驗的開發人員使用Java實現,則總工作量為:
5 人-年 * LTEX(Java) * PVOL(Java) = 984 (人-天)如果同樣的項目由幾乎沒有Kotlin開發經驗的開發人員使用Kotlin實現,則總工作量為:
5 人-年 * LTEX(Kotlin) * PVOL(Kotlin) * 0.98 + T_ramp_up = 1115 + 5 * N_developers (人-天)據估計,選擇Kotlin替換Java所導致的額外工作量為131 + 5 * N_developers (人-天)。
評估注意事項在評估討論的過程中,我們得出了與Kotlin和Java相關的、便利的工作量單點值。
但實際上,單點值根本不是估計——它們只是猜測。真正的估計必須有一個相關聯的不確定性。換句話說,估計表示可能性的范圍,而不是單點值。
我們最終使用單點值代替了范圍,那是因為我從估算范圍里選擇了最有利于Kotlin的值,將所有的估計都轉換成了單點值。
例如,當討論Kotlin對編碼與調試活動的影響時,我從估計出的可能性范圍[-5%,10%]中選擇了最大的生產力提升值10%。在其他情況下,當我們討論開發人員切換到Kotlin的平均時間時,我從估計的可能性范圍[5天,21天]中選擇了最小的5天。
此外,我們使用了Cocomo 2估計模型專用的工作因子。這些因子并不是放之四海而皆準的真理,在最一般的情況下,應該也有相關聯的不確定性。我賦給Kotlin的評級高于我實際上認為它應得的評級,我希望通過這種方式消除這種不確定性。
不用說,我們獲得的單點值并不是百分百正確。為了得出更完整的估計,我們可以利用真正的估計進行Monte Carlo仿真。通過這項技術,我們可以觀察可能結果的分布,弄清楚哪種結果最可能出現。
請記住,由于我們將估計壓縮成了對Kotlin而言最為有利的單點值,所以其他可能的結果會顯示出更大的Kotlin切換開銷。因此,在所有可能的結果中,我們在上文描述的單點值是最有利于Kotlin的。
小結在文章開頭部分,我們展示了一些可能會對開發人員比較編程語言造成誤導的主觀判斷。
接下來,我們討論了客觀比較編程語言存在的困難,并進行了一系列的估計,以便弄清楚Kotlin棧與Java棧完成軟件項目所需的總工作量。在執行估計時,我們一直使用估計范圍里最有利于Kotlin的值。
通過我們的分析,從Java切換到Kotlin似乎會導致完成軟件項目所需的總工作量增加。
更多的工作意味著企業切換到Kotlin需要花更多的錢才能獲得同樣的功能,而用戶需要等待更長的時間才能獲得產品。
有些開發人員可能會吃驚,覺得這個結果不容易接受。
在考慮了所有的情況之后,谷歌最終決定支持Kotlin Anroid開發。對此,谷歌可能需要相當大的投入——谷歌云平臺團隊是不是沒有人可以做類似的分析,從而弄清楚切換到一門新語言所帶來的負面影響?
我認為,谷歌員工都是非常聰明的人,我相信他們在決定支持Kotlin之前已經進行了非常深入的分析。
在下一篇博文中,我們將討論谷歌為什么要支持Kotlin,即使是在通過簡單的分析就可以知道那不利于Android社區的情況下。
查看英文原文:Kotlin vs Java The Whole Story