文档章节

从架构师视角看是否该用Kotlin做服务端开发?

chentao106
 chentao106
发布于 02/14 00:52
字数 2862
阅读 2.4W
收藏 30

前言

自从Oracle收购Sun之后,对Java收费或加强控制的尝试从未间断,谷歌与Oracle围绕Java API的官司也跌宕起伏。虽然Oracle只是针对Oracle JDK8的升级收费,并释放了OpenJDK一直开源这份善意,但是如果没有各个大非Oracle的JVM、JDK和众多其它基于JVM的语言,Oracle这份善意能维持到什么时候可不好说。

大厂要从JVM和JDK的层面早做打算,而广大中小企业,就只能先从Java语言的层面,先找到Oracle以外的备胎。自从被谷歌钦定为Android开发首选语言之后,采用Apache2.0 License的Kotlin逐渐进入大众的视野。从领域语言到通用语言,基于JVM的语言选择众多,Kotlin能脱颖而出被谷歌相中,除了License的友好外,自然有其独到之处(个人觉得基于Python语法的Jython在当时也算是一个强强联合的选择,当然现在来看Kotlin的优势明显)。我们先从摘自网上的一个段子来感受下Kotlin的特点:

  • Scala:想解决Java表达能力不足的问题
  • Groovy:想解决Java语法过于冗长的问题
  • Clojure:想解决Java没有函数式编程的问题
  • Kotlin:想解决Java

当然,团队开发比个人开发要考虑的问题更多,本文从研发团队的视角,来审视在服务端开发项目中是否应该使用Kotlin。而关于Kotlin语言细节,详情请大家参移步Kotlin官方文档或搜索引擎去了解更多,本文就不详细展开。

选择Kotlin的理由

1. 与Java近乎完美的兼容

作为团队技术预研,我已小试牛刀使用Kotlin做了一小一中真实上线项目,包括CI\CD、Spring全家桶、MyBatis、RDMS、NoSQL、消息队列、微服务、RESTful接口、鉴权、计费等全面实践,除项目代码之外的也用Kotlin实现了爬虫、运维、测试工具等。这其中除了BenchMark性能测试因OpenJDK:jmh直接操作字节码而需要编译比java略复杂外,所有事件都能做到人(Java)无我(Kotlin)有,人(Java)有我(Kotlin)强,只身十天左右就能高质量从零完成一套AI SaaS服务的开发、测试。

我自身的实践可以说明,Kotlin使用Java的开源组件、类库、工具栈上与Java代码本身几乎(仅发现jmh有些许差别外)没有差别,这是其它基于JVM的语言无法比拟有优势。

2. 更易写出可靠的代码

2.1 强制非空校验

// 所有变量默认不能为空
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 默认参数与数据类

// 默认参数,大多数情况可以代替函数重载
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,再做决定。

© 著作权归作者所有

chentao106

chentao106

粉丝 7
博文 3
码字总数 7868
作品 0
深圳
私信 提问
加载中

评论(50)

颜文
颜文
kt和java混着用,对外暴露的接口服务用java,内部实现用kotlin
兮若
兮若
语言的红利而已,我会jsc++,java,scala,python,go,rust ,dart,看项目选择语言而已
c
cbk808
kotlin 现在有 google 这个干爹,应该说扶持的力度是挺大的,在有活跃的 community 以及大厂背书的情况下,况且语言本身的 feature 也不赖,开发者选择这个语言没什么问题,或者说没得选择,就像 OC 之于 swift, 新的 library 都是用 swfit,要想享受这些便利就只能切换到新的语言,这并不会有什么选择困难,一些有点经验的开发人员都有被大厂带跑偏的经历,对新技术有警惕心理,这也是正常的,但就目前来说,kotlin 底子不错,长期来看是有价值和地位的。
扫地农
扫地农
现在确实混着用
Erroooooor
Erroooooor
Kotlin最大的优势应该是代码即设计,省两行代码只是一个必然的结果,比如委托/单例 这些都通过和语法绑定了。
但是我最受不了的是,它把异常处理给吃了,对于JVM来说很多异常是有业务含义的,比如JDK自带了很多所见即所得的异常。
第二个受不了的是,fastjon对kotlin有特殊处理,https://github.com/alibaba/fastjson/issues/2532。当然这其实不关kotlin的事情。
目前我是java和kotlin混用
chentao106
chentao106 博主
能否分享下混用的目的和心得
chentao106
chentao106 博主
我Jackson+jackson-module-kotlin,没有体验到与java的差别。 两三年以前测试fastjson在某些场景下有Bug,并且实测性能在各种场景下与jackson各有千秋,所以一直没有选用fastjson
Erroooooor
Erroooooor
1. 首先会用java把框架搭建好,这里的框架一般都是接口/简单的pojo/异常类,pojo之前也是用kotlin的,因为var/val太好用了,但是遇到fastjson的坑之后就放弃了,使用java写的代码也会引入jsr305包,这样和kotlin的空指针检测无缝衔接 2. kotlin用于具体代码实现,特别是比较复杂的处理,kotlin至少可以省掉50%的工作量,人生苦短 3. kotlin目前编译相对于还是比较慢的,所以一个kotlin的类不能太多行了。 4. 也准备换jackson,但是和fastjon绑定太多,最后放弃了,但即便是使用jackson,pojo我也优先直接用java编写 只是个人经验,谈不上心得,kotlin的好东西。
Mark哥是我
Mark哥是我
不认同!java语法糖太少,很规范,但是也很守旧!现代化编程语言应该说都是简洁的,到java不是
chentao106
chentao106 博主
不认同什么?
Mark哥是我
Mark哥是我
歪楼了……回复那位的:一切的痛只是因为用的spring 开发。和java 没关系
Mark哥是我
Mark哥是我
我们是kt和java混编
chentao106
chentao106 博主
你们比较放飞自我😆,欢迎分享下混编中的欢乐
Tinian
Tinian
前年用的时候,Kotlin在IDEA上用着卡卡的,现在不知道怎么样了。还有公司项目我想用协程,队友不使用Kotlin,我一个人也没法上。
chentao106
chentao106 博主
机器配置要求这个问题确实没考虑到。去年我用最低配Macbook Air的时候,也没觉得卡,现在换新电脑更不会有感觉,不过这代表不了其它配置没问题。做Java开发固态硬盘很重要,内存是其次的
Mark哥是我
Mark哥是我
同等机器配置,kt的智能提示没java快,我i7-9700加三星固态能比较明显感觉到,idea对kt的智能提示还应该加强!
Tinian
Tinian
Air...可能用Air的人已经习惯卡了
chentao106
chentao106 博主
Air还好吧,就是内存不够双开,数据库等软件都直接Docker最少启动以节省内存;我现在Huawei顶配笔记本MateBook X Pro,也无非打开项目时快一点,可以多开,编码过程没有感到明显的区别
abcijkxyz
abcijkxyz
我学kotlin是想了解《领域特定语言》,架构师到一定程度要了解这个
abcijkxyz
abcijkxyz
技术预研的代码可以开源出来吗?谢谢~~
这样可以在你的基础上继续研究kotlin
chentao106
chentao106 博主
我做的是实际商业项目,不太方便开源,我准备在有时间的时候整理一个Kotin&机器学习SaaS服务的开源案例。最快的上手实际项目的方法,是从Spring Initalizr开始创建Kotlin Web项目,其次是Maven的artchetype插件,或者Kotlin官方文档
每个架构师都应该研究下康威定律

摘要:这篇文章的分享者杨波具有超过10年的互联网分布式系统研发和架构经验,曾先后就职于 eBay 中国研发中心(eBay CDC)、携程、唯品会(VIPShop)等。本文由攀爬的蜗牛以及田光整理。   ...

毛爷爷夸我帅
2016/02/15
204
0
每个架构师都应该研究下康威定律

  今天的分享主要来自我之前的工作经验以及平时的学习总结和思考。我之前的背景主要是做框架、系统和平台架构,之前工作过的公司 eBay、携程、唯品会都是平台型互联网公司,所以今天主要带...

moodlxs
2016/02/15
293
0
闲鱼架构如何一招提效30%?Flutter+Serverless 研发实践公开

阿里妹导读:Serverless(无服务架构)被誉为下一代云计算,自概念推出以来,因为能带来研发交付速度提升与成本的降低在业内异常火爆。闲鱼客户端基于Flutter进行架构演进与创新,通过Flutt...

阿里云云栖号
2019/12/31
0
0
初探Kotlin(一)

1: kotlin 特性 Kotlin首要目标是提供一种更简洁,更高效,更安全的替代Java的语言,并且适用于现今使用Java的所有环境, 使用Kotlin可以帮助开发者在实现目标的同时减少代码并避免麻烦. 常用场景...

YoungerDev
2017/10/04
0
0
Flutter+Serverless端到端研发架构实践

Serverless(无服务架构)被誉为下一代云计算,自概念推出以来,因为能带来研发交付速度提升与成本的降低在业内异常火爆。闲鱼客户端基于Flutter进行架构演进与创新,通过Flutter统一Android...

阿里云云栖号
2019/12/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周一乱弹 —— 提前接受社会的毒打教育

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @爱吃蛋挞的kk:分享Buddy Guy的单曲《I Need You Tonight》 《I Need You Tonight》- Buddy Guy 手机党少年们想听歌,请使劲儿戳(这里) 凌...

小小编辑
28分钟前
46
0
成都哪里可以开租赁费发票-成都新闻网

成都哪里可以开租赁费发票【1.3.2 - 2.9.3.0 - 0.5.6.8.】李生,adb的全称为Android Debug Bridge,是Android手机通用的一个USB端口。百度CarLife的部分车机采用了...

提供格
30分钟前
45
0
成都哪里可以开钢材发票-成都新闻网

成都哪里可以开钢材发票【1.3.2 - 2.9.3.0 - 0.5.6.8.】李生,adb的全称为Android Debug Bridge,是Android手机通用的一个USB端口。百度CarLife的部分车机采用了该...

多徐重
32分钟前
29
0
成都哪里可以开医疗器械发票-成都新闻网

成都哪里可以开医疗器械发票【1.3.2 - 2.9.3.0 - 0.5.6.8.】李生,adb的全称为Android Debug Bridge,是Android手机通用的一个USB端口。百度CarLife的部分车机采用...

识过人石
34分钟前
75
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部