從架構師視角看是否該用Kotlin作服務端開發?

前言

自從Oracle收購Sun以後,對Java收費或增強控制的嘗試從未間斷,谷歌與Oracle圍繞Java API的官司也跌宕起伏。雖然Oracle只是針對Oracle JDK8的升級收費,並釋放了OpenJDK一直開源這份善意,可是若是沒有各個大非Oracle的JVM、JDK和衆多其它基於JVM的語言,Oracle這份善意能維持到何時可很差說。html

大廠要從JVM和JDK的層面早作打算,而廣大中小企業,就只能先從Java語言的層面,先找到Oracle之外的備胎。自從被谷歌欽定爲Android開發首選語言以後,採用Apache2.0 License的Kotlin逐漸進入大衆的視野。從領域語言到通用語言,基於JVM的語言選擇衆多,Kotlin能脫穎而出被谷歌相中,除了License的友好外,天然有其獨到之處(我的以爲基於Python語法的Jython在當時也算是一個強強聯合的選擇,固然如今來看Kotlin的優點明顯)。咱們先從摘自網上的一個段子來感覺下Kotlin的特色:java

  • Scala:想解決Java表達能力不足的問題
  • Groovy:想解決Java語法過於冗長的問題
  • Clojure:想解決Java沒有函數式編程的問題
  • Kotlin:想解決Java

固然,團隊開發比我的開發要考慮的問題更多,本文從研發團隊的視角,來審視在服務端開發項目中是否應該使用Kotlin。而關於Kotlin語言細節,詳情請你們參移動Kotlin官方文檔或搜索引擎去了解更多,本文就不詳細展開。git

選擇Kotlin的理由

1. 與Java近乎完美的兼容

做爲團隊技術預研,我已小試牛刀使用Kotlin作了一小一中真實上線項目,包括CI\CD、Spring全家桶、MyBatis、RDMS、NoSQL、消息隊列、微服務、RESTful接口、鑑權、計費等全面實踐,除項目代碼以外的也用Kotlin實現了爬蟲、運維、測試工具等。這其中除了BenchMark性能測試因OpenJDK:jmh直接操做字節碼而須要編譯比java略複雜外,全部事件都能作到人(Java)無我(Kotlin)有,人(Java)有我(Kotlin)強,隻身十天左右就能高質量從零完成一套AI SaaS服務的開發、測試。github

我自身的實踐能夠說明,Kotlin使用Java的開源組件、類庫、工具棧上與Java代碼自己幾乎(僅發現jmh有些許差異外)沒有差異,這是其它基於JVM的語言沒法比擬有優點。web

2. 更易寫出可靠的代碼

2.1 強制非空校驗shell

// 全部變量默認不能爲空
var a: String = "abc"
a = null //編譯錯誤
// 若是想要容許變量爲空,變量聲明中的類型以"?"結尾
var b: String? = null
// 非空類型的變量,能夠直接調用對象方法
println(a.length)
 // 可空類型的變量,能夠用"?."替換"."來進行徹底調用
println(b?.length) //若是b爲null,則b?.length返回null,而不會拋出NPE
// "?."鏈式調用更顯安全調用的威力
bob?.department?.head?.name //只要有一環爲null,則整個表達式返回null
// 空類型不能直接賦值給非空類型
a = b //編譯錯誤
// 可使用非空斷言"!!"來強制將b轉換爲其對應的非空類型
a = b!! //若是b爲null,則拋出NPE,不然賦值成功
// 更安全的作法是使用"?:"賦值
a = b?:"Default"
// "?:"還能夠接」throw「、"return"、"break"語句來提早結束函數或語句塊
a = b?: throw MyException("自定義異常")

能夠看到,Kotlin經過強制非空校驗機制,規避了Java最易犯的NPE問題,而且在不額外增長判空代碼的狀況下,很容易寫出空安全的代碼,固然也經過非空斷言保留了拋出NPE的途徑,具體請參考Kotlin官方文檔-空安全編程

2.2 只讀變量安全

// 經過val能夠方便聲明只讀變量,防止變量的誤修改,相似於java的final
val a = "Hello"
//...
a = "world" //編譯錯誤
// var用於聲明可讀寫變量
var b = 1 //若是下方沒有代碼對b進行修改,則編譯告警

聲明只讀變量的語法更簡潔,配合var未修改編譯告警,強制開發人員明白無誤地聲明變量服務器

3. 簡潔高效,代碼量可減小逾50%

3.1 默認參數與數據類session

// 默認參數,大多數狀況能夠代替函數重載
fun a(name: String, age: Int = 0) {
  //...
}

// data關鍵字會自動爲類型增長hashCode(),equals(),copy(),toString()方法
// val關鍵字會自動生成只讀成員變量及get方法
// var關鍵字會自動生成成員變量及get和set方法
data class Person(val id: Int, var name: String, var age: Int = 0)
//以上就是Person實體的完整聲明,它等價於十行以上的java代碼

默認參數、數據類、主構造函數的組合使用,讓咱們節省了90%以上的實體聲明代碼,且表達能力更清晰,可維護性更強

3.2 類型推斷

when(val u = request.session.getAttribute("user")){
  is String -> println(u.toUpperCase())
  is Map<*, *> -> println(u["name"])
  !is List<*> -> println(u)
}

在類型判斷代碼以後,變量會自動轉換爲須要的類型,省去變量聲明和類型轉換代碼。

除此以外Kotlin擁有着豐富的集合操做,以及類擴展、更簡潔的lambda、字符串模板、操做符重載、解構等等幾乎包含了如今語言的全部優良特徵,讓業務代碼節省50%以上,且表義能力更強。

4. Spring的加成

Spring-Boot已經將kotlin提高爲僅次於Java的推薦語言,足以見得Spring對Kotlin重視

4.1 構造函數注入

Spring構造函數注入配置kotlin的主構造函數語法,Spring+Kotlin天生就很搭

@Service
class SMSService(
  @Value("\${sms.appId}") private val appId: String,
  @Value("\${sms.appSecret}") private val appSecurity: String,
  private val webClient: WebClient
) {
  //...
}

4.2 針對Kotlin的擴展
Spring中還有部分專門針對Kotlin的擴展如: SpringApplicationExtension:

@SpringBootApplication
class SpringBootApplicationStarter

fun main(args: Array<String>) {
  //拉起Spring-Boot應用
  runApplication<SpringBootApplicationStarter>(*args)
}

4.3 針對Kotlin的示例代碼

Spring文檔專門爲Kotlin編寫了示例代碼,這但是Spring支持的老牌語言Groovy多年都沒享受到的待遇:

Kotlin天生對Spring的友好,以及Spring對Kotlin的重視和加成,能夠預見Kotlin將來在服務器開發領域的地位會愈來愈高。

選擇Kotlin須要考慮的問題

1. IDE&工具鏈

Kotlin首選開發工具非同屬jetbrain公司的IDEA莫屬
Eclipse+Kotlin Plugin也是不錯的選擇
兩者Kotlin的開發體驗都不輸於Java的開發體驗
不過Eclipse的Kotlin插件存在兩個問題:
1) Debug不能自動識別Kotlin的main方法,須要手工填入Class名;
2) Debug不支持Kotlin編譯的allopen選項,全部Bean和Configuration類型須顯示聲明爲open

@SpringBootApplication
open class SpringBootApplicationStarter

@Configuration
open class BeanConfig

@Service
open class TestService

@RestController
open class TestController

在IDE以外,Kotlin能完美地運行於Maven和Gradle之上,CI/CD工具Jenkins天然不在話下,JUnit、Swagger等Java原有工具鏈運行起來都沒有差異,在字節碼和jar包以外的各類工具可否運行,理論上並不取決於項目代碼是Kotlin仍是Java;可能最大的問題在於,原有的代碼檢查工具不能再繼承使用。

2. 編碼規範

Kotlin放開了不少限制如:

  • 能夠聲明全局變量和全局方法
  • 一個文件能夠有多個類
  • 能夠經過擴展來爲已有類增長新方法

這帶來了諸多便利,如同一領域的實體能夠聲明在一個文件中:

//WebResponses.kt
open class WebResponse(var errorCode: Int = 0, var errorMsg: String? = null)

open class DataResponse<T>(var data: T?) : WebResponse()

open class MapResponse<K, V>(map: Map<K, V>) : DataResponse<Map<K, V>>(map) {
    constructor(vararg pairs: Pair<K, V>) : this(mutableMapOf(*pairs))
}

能夠很方便地擴展已有類庫

// StringExtensions.kt
val REGEX_Digits = Regex("\\\d+")
fun String.isDigits(): Boolean {
    return this.matches(REGEX_Digits)
}
// ACLInterceptor
val appId = request.getParameter("appId")
if (!appId.isNullOrBlank() && appId.isDigits()) {
//...
}

可是若是不加限制,很難保證開發人員不爲所欲爲。因此應該針對Kotlin項目制定一些編碼規範(能夠與Android項目共用),如:

  • 只有數據實體能夠定義在同一個文件中
  • 類型擴展應以」Extensions「後綴結尾,如"StringExtensions"
  • 業務邏輯不該出如今全局方法中,應按照一類一文件的方式組織
  • 業務邏輯的擴展,不該使用Kotlin類型擴展機制,而應使用接口、抽象類、子類

3. 人員技能

對Java開發人員來講,學習Kotlin並非什麼困難的事情,以我我的的經驗,直接以一個小項目開始的狀況下,一週以內編碼效率就會明顯超過Java。

固然,語言工具不是項目成敗的決定性因素,使用工具的人才是,不妨先讓項目組中的核心成員去了解下Kotlin,再作決定。

快速上手建議從Koans開始,想要更深刻地掌握,仍是要閱讀Kotlin官方文檔

4. 依賴大小

在Spring項目中使用Kotlin會使依賴增長4.18MB左右

這在Spring-Boot興起以前,對我來講確實是個問題,6年前一個war包也就3~5MB大小,還要爲Tomcat能部署多個服務而不會代碼空間溢出,把war包進一步瘦身——把公共jar包都放入Tomcat/lib之下。

而如今Spring-Boot項目動則30MB起步的大小,讓我已經再也不考慮服務器資源的問題,而更享受各類組件和工具帶來的開發效率提高。

固然這個問題,因項目實際狀況而異,須要交給做爲架構師的你本身去決策。

5. BenchMark

具體細節本不是此文的討論目標,且對Kotlin作BenchMark性能測試不是那麼困難,可是Kotlin的BenchMark資料也很少,這裏我附送一個簡明教程:

  • 步驟1:使用maven生成Kotlin benchmark工程
mvn archetype:generate \
          -DinteractiveMode=false \
          -DarchetypeGroupId=org.openjdk.jmh \
          -DarchetypeArtifactId=jmh-kotlin-benchmark-archetype \
          -DgroupId=org.sample \
          -DartifactId=test \
          -Dversion=1.0
  • 步驟2:編寫測試代碼
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
open class MyBenchmark {
	@Benchmark
	fun testMethod1() {
		//...
	}

	@Benchmark
	fun testMethod2() {
		//...
	}
}
  • 步驟3:編譯&運行
mvn clean package
java -jar target/benchmarks.jar

更多性能測試詳情,可參考

哪些項目類型適合使用Kotlin

  1. 現有Java項目,不推薦;
  2. 小型或驗證型項目,強烈推薦;
  3. 微服務項目,推薦先局部試點,逐步完善編碼規範和人員技能;
  4. 大型單體項目,有較強較穩定的核心團隊時推薦,人員主靠招聘時不推薦;
  5. 公共組件,不推薦,除專門用於Kotlin的組件外。

結語

無論怎麼說,語言工具不是項目成敗的決定性因素,使用工具的人才是,不妨先讓項目組中的核心成員去了解下Kotlin,再作決定。

相關文章
相關標籤/搜索