# Wow
**Repository Path**: tib/Wow
## Basic Information
- **Project Name**: Wow
- **Description**: 领域模型即服务 - 基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架
- **Primary Language**: Kotlin
- **License**: Apache-2.0
- **Default Branch**: main
- **Homepage**: https://github.com/Ahoo-Wang/Wow
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 87
- **Created**: 2023-12-25
- **Last Updated**: 2023-12-25
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Wow : 基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架
> [English Document](https://github.com/Ahoo-Wang/Wow/blob/main/README.md)
[](https://github.com/Ahoo-Wang/Wow/blob/mvp/LICENSE)
[](https://github.com/Ahoo-Wang/Wow/releases)
[](https://maven-badges.herokuapp.com/maven-central/me.ahoo.wow/wow-core)
[](https://app.codacy.com/gh/Ahoo-Wang/Wow/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[](https://codecov.io/gh/Ahoo-Wang/Wow)
[](https://github.com/Ahoo-Wang/Wow)
[](https://github.com/KotlinBy/awesome-kotlin)
**领域驱动** | **事件驱动** | **测试驱动** | **声明式设计** | **响应式编程** | **命令查询职责分离** | **事件溯源**
## 快速开始
使用[Wow 项目模板](https://gitee.com/AhooWang/wow-project-template)快速创建基于 Wow 框架的 DDD 项目。
## 特性概览
## 架构图
## 性能测试 (Example)
- 测试代码:[Example](./example)
- 测试场景:加入购物车、下单
- 命令发送等待模式(`WaitStrategy`):`SENT`、`PROCESSED`
### 部署
- [Redis](deploy/example/perf/redis.yaml)
- [MongoDB](deploy/example/perf/mongo.yaml)
- [Kafka](deploy/example/perf/kafka.yaml)
- [Application-Config](deploy/example/perf/config/mongo_kafka_redis.yaml)
- [Application-Deployment](deploy/example/perf/deployment.yaml)
### 测试报告
#### 加入购物车
- [请求](deploy/example/request/AddCartItem.http)
- [详细报告(PDF)-SENT](./document/example/perf/Example.Cart.Add@SENT.pdf)
- [详细报告(PDF)-PROCESSED](./document/example/perf/Example.Cart.Add@PROCESSED.pdf)
> 命令等待策略(`WaitStrategy`)为`SENT`模式,加入购物车命令(`AddCartItem`)写请求 API 经过 2 分钟的压测,平均 TPS 为 *59625*,峰值为 *82312*,平均响应时间为 *29* 毫秒。
> 命令等待策略(`WaitStrategy`)为`PROCESSED`模式,加入购物车命令(`AddCartItem`)写请求 API 经过 2 分钟的压测,平均 TPS 为 *18696*,峰值为 *24141*,平均响应时间为 *239* 毫秒。
#### 下单
- [请求](deploy/example/request/CreateOrder.http)
- [详细报告(PDF)-SENT](./document/example/perf/Example.Order.Create@SENT.pdf)
- [详细报告(PDF)-PROCESSED](./document/example/perf/Example.Order.Create@PROCESSED.pdf)
> 命令等待策略(`WaitStrategy`)为`SENT`模式,下单命令(`CreateOrder`)写请求 API 经过 2 分钟的压测,平均 TPS 为 *47838*,峰值为 *86200*,平均响应时间为 *217* 毫秒。
> 命令等待策略(`WaitStrategy`)为`PROCESSED`模式,下单命令(`CreateOrder`)写请求 API 经过 2 分钟的压测,平均 TPS 为 *18230*,峰值为 *25506*,平均响应时间为 *268* 毫秒。
## 事件源
## 可观测性
## OpenAPI (Spring WebFlux 集成)
> 自动注册 **命令** 路由处理函数(`HandlerFunction`) ,开发人员仅需编写领域模型,即可完成服务开发。
## 测试套件:80%+ 的测试覆盖率轻而易举
> Given -> When -> Expect .
## 前置条件
- 理解 **领域驱动设计**:《实现领域驱动设计》、《领域驱动设计:软件核心复杂性应对之道》
- 理解 **命令查询职责分离**(CQRS)
- 理解 **事件源架构**
- 理解 **响应式编程**
## Example
### 订单服务(Kotlin)
[Example-Order](./example)
### 银行转账(JAVA)
[Example-Transfer](./example/transfer)
## 单元测试套件
### 80%+ 的测试覆盖率轻而易举。

> Given -> When -> Expect .
### Aggregate Unit Test (`AggregateVerifier`)
[Aggregate Test](./example/example-domain/src/test/kotlin/me/ahoo/wow/example/domain/order/OrderTest.kt)
```kotlin
internal class OrderTest {
@Test
private fun createOrder() {
val tenantId = GlobalIdGenerator.generateAsString()
val customerId = GlobalIdGenerator.generateAsString()
val orderItem = OrderItem(
GlobalIdGenerator.generateAsString(),
GlobalIdGenerator.generateAsString(),
BigDecimal.valueOf(10),
10,
)
val orderItems = listOf(orderItem)
val inventoryService = object : InventoryService {
override fun getInventory(productId: String): Mono {
return orderItems.filter { it.productId == productId }.map { it.quantity }.first().toMono()
}
}
val pricingService = object : PricingService {
override fun getProductPrice(productId: String): Mono {
return orderItems.filter { it.productId == productId }.map { it.price }.first().toMono()
}
}
aggregateVerifier(tenantId = tenantId)
.inject(DefaultCreateOrderSpec(inventoryService, pricingService))
.given()
.`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS, false))
.expectEventCount(1)
.expectEventType(OrderCreated::class.java)
.expectStateAggregate {
assertThat(it.aggregateId.tenantId, equalTo(tenantId))
}
.expectState {
assertThat(it.id, notNullValue())
assertThat(it.customerId, equalTo(customerId))
assertThat(it.address, equalTo(SHIPPING_ADDRESS))
assertThat(it.items, equalTo(orderItems))
assertThat(it.status, equalTo(OrderStatus.CREATED))
}
.verify()
}
@Test
fun createOrderGivenEmptyItems() {
val customerId = GlobalIdGenerator.generateAsString()
aggregateVerifier()
.inject(mockk(), "createOrderSpec")
.given()
.`when`(CreateOrder(customerId, listOf(), SHIPPING_ADDRESS, false))
.expectErrorType(IllegalArgumentException::class.java)
.expectStateAggregate {
/*
* 该聚合对象处于未初始化状态,即该聚合未创建成功.
*/
assertThat(it.initialized, equalTo(false))
}.verify()
}
/**
* 创建订单-库存不足
*/
@Test
fun createOrderWhenInventoryShortage() {
val customerId = GlobalIdGenerator.generateAsString()
val orderItem = OrderItem(
GlobalIdGenerator.generateAsString(),
GlobalIdGenerator.generateAsString(),
BigDecimal.valueOf(10),
10,
)
val orderItems = listOf(orderItem)
val inventoryService = object : InventoryService {
override fun getInventory(productId: String): Mono {
return orderItems.filter { it.productId == productId }
/*
* 模拟库存不足
*/
.map { it.quantity - 1 }.first().toMono()
}
}
val pricingService = object : PricingService {
override fun getProductPrice(productId: String): Mono {
return orderItems.filter { it.productId == productId }.map { it.price }.first().toMono()
}
}
aggregateVerifier()
.inject(DefaultCreateOrderSpec(inventoryService, pricingService))
.given()
.`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS, false))
/*
* 期望:库存不足异常.
*/
.expectErrorType(InventoryShortageException::class.java)
.expectStateAggregate {
/*
* 该聚合对象处于未初始化状态,即该聚合未创建成功.
*/
assertThat(it.initialized, equalTo(false))
}.verify()
}
}
```
### Saga Unit Test (`SagaVerifier`)
[Saga Test](./example/example-domain/src/test/kotlin/me/ahoo/wow/example/domain/cart/CartSagaTest.kt)
```kotlin
class CartSagaTest {
@Test
fun onOrderCreated() {
val orderItem = OrderItem(
GlobalIdGenerator.generateAsString(),
GlobalIdGenerator.generateAsString(),
BigDecimal.valueOf(10),
10,
)
sagaVerifier()
.`when`(
mockk {
every {
customerId
} returns "customerId"
every {
items
} returns listOf(orderItem)
every {
fromCart
} returns true
},
)
.expectCommandBody {
assertThat(it.id, equalTo("customerId"))
assertThat(it.productIds, hasSize(1))
assertThat(it.productIds.first(), equalTo(orderItem.productId))
}
.verify()
}
}
```
## 设计
### 聚合建模
| **Single Class** | **Inheritance Pattern** | **Aggregation Pattern** |
|----------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------|
|  |  |  |
### 加载聚合
### 聚合状态流
### 发送命令
### 命令与事件流
## 事件补偿
### 用例图
### 执行时序图
### Dashboard