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