添加快捷方式
分享
领略kotlin之美,手把手带你搭建一个牛逼轰轰的业务框架
输入“/”快速插入内容
领略kotlin之美,手把手带你搭建一个牛逼轰轰的业务框架
飞书用户9506
飞书用户262
2月18日修改
引
言
“21世纪最缺的是什么?人才!”,天下无贼里面的这句台词放在今天还是毫不落伍,
一个人的价值具体起来就是其拥有的知识以及创造新知识的能力,很多公司特别是在金融行业其最大的甚至是唯一的资产就是人才,那怎么储备人才,管理人才和利用人才则是公司事务的重中之重。具体点则映射为知识的管理(收集归纳,验证更新和衍生预测),通常以语音视频,文档,数据,约定以及规则制度等形式留存,随着时间的推移这些散落在各种文档,代码,流程,系统以及约定中的知识会变的越来越难以管理和维护。
一个特定领域的核心业务知识是该业务线的核心竞争力,如何抽离并能系统化的获得版本管理,自洽,交叉验证和实时应用则是工程化落地的重要考量,具体到软件工程一般要求有:
•
业务核心逻辑的开发实现上要求无框架,平台等技术性依赖
•
业务逻辑组件间依赖为0
•
时间上则要求成熟业务上线以日计,新业务上线以周计
具体实施时按分工通常拆分为如下3大块:
•
核心业务逻辑(Business/Domain)
公司的核心资产,健壮的业务逻辑完整性,独立演化,通常不关心非业务需求,要求100%的测试覆盖率,尽可能减少框架,特定库等技术依赖,通常以描述性语言如DSL乃至xml, yml, json等或者采用DDD, FP方式尽量以接近人类口语,思考的方式编写。
•
业务应用(Application)
连接平台和业务逻辑的桥梁,利用平台能力以一定方式(web, rpc)向外提供业务服务。
•
平台(Platform)
业务中立的运行基座,独立演化,专注于性能,运行时管理,配置部署,监控,错误处理,高可用(包括灾备)以及可复用生态组件和扩展接口等。
他山之石
接上篇Springboot, Vert.x等框架都能满足平台选型的要求,它们都有着极致的扩展性和通用性,应用场景广泛,在业界也很受欢迎。但回到某一个公司,某一个业务场景这种通用性则有可能成为了一种累赘,比如在金融领域前台业务侧,几乎所有的业务逻辑都是围绕着交易(Trade)及其相关的事件(Event)进行的,这种场景下传统的命令式编程(Procedure Programming),靠通过一系列确定的步骤就能完成一个功能的系统(Ordered System)则不太容易满足业务的需求,而运用响应式编程(Reactive Programming),通过事件驱动(Event Driven)的方式组成的异步系统(Disordered System)则更加契合,这样的系统需要的平台则天然需要把重心放在事件的处理上,包括但不限于事件的序列化,传输,持久化,分发,事务级消息控制,错误处理,回放,重发等功能,同时要尽量简化(甚至移除)业务应用侧的开发成本,那除了需要一个强化的依赖注入(DI)支持(bean + data)外,通常还需要有一定的元编程能力(Meta Programming),通过代码生成,字节码操纵等手段自动的生成相关胶水代码。
Kotlin or Java
语言只是工具其本身对设计影响微乎其微,在众多流行的语言(java, scala, golang, rust等)中选用kotlin来介绍是一种偏好和折中,它既可以复用庞大的java生态,同时有着强大的性能(coroutine, flow..),精练的语法(data class, context receiver..),最重要的是它的DSL支持,几乎可以模拟人类语言的方式来编写业务逻辑代码,让非专业技术人员也能快速上手业务代码的实现。
有了如上铺垫后,让我们开始进入正题,一步一步庖丁解牛般来打造这样一个业务平台框架吧!
庖丁解牛
在正式开始之前,让我们再回顾一下这只“牛”所在的场景,它有三大块组成,业务(Business),应用(Application)和平台(Platform),在我们搭建这个平台之前让我们想象一下它们应该是怎么交互的呢,利用上篇介绍的Residuality Theory, 初略设计过程如下图:
画板
如上图最终系统设计结合实际的业务要求可形成以下基本思路:
•
以抽象的Event Bus服务为中心解耦组件间依赖
•
DSL/注解声明式开发方式+代码生成解耦平台依赖
•
Event Sourcing+双时序等技术解耦时空依赖
•
消息体以及功能组件可重用可扩展等方式最大化减少上线周期
用例1 - 马戏团
在进入平台详细设计环节之前,首先让我们想象下用户一般怎么来实现业务核心逻辑的(上图中的绿色部分),这里以马戏里面的小丑和猴子的一场表演举例,开场后小丑这个角色负责扔3次香蕉,猴子接到香蕉后负责吃掉。
经典设计-注解方式
这里小丑和猴子分工很明确,所以一般会设计成两个领域模型,如下:
代码块
Kotlin
package clown
data class ShowStarted(val timestamp: Long)
data class Banana(val no: Int)
class Clown {
fun onShowStarted(event: ShowStarted) {
for (no in 1..3) {
_throw(Banana(no))
}
}
private fun _throw(banana: Banana) {
TODO()
}
}
代码块
Kotlin
package monkey
class Monkey {
fun onBananaThrown(banana: Banana) {
println("Banana#${banana.no} was eaten")
}
}