<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Wow微服務(wù)開發(fā)框架

          聯(lián)合創(chuàng)作 · 2023-09-28 04:41

          Wow 是基于 DDD、EventSourcing 的現(xiàn)代響應(yīng)式 CQRS 架構(gòu)微服務(wù)開發(fā)框架。

          領(lǐng)域驅(qū)動 | 事件驅(qū)動 | 測試驅(qū)動 | 聲明式設(shè)計(jì)  響應(yīng)式編程  命令查詢職責(zé)分離  事件源

          架構(gòu)圖

          Wow-Architecture

          事件源

          Wow-EventSourcing

          可觀測性

          Wow-Observability

          Spring WebFlux 集成

          自動注冊 命令 路由處理函數(shù)(HandlerFunction) ,開發(fā)人員僅需編寫領(lǐng)域模型,即可完成服務(wù)開發(fā)。

          Wow-OpenAPI-Swagger

          測試套件:80%+ 的測試覆蓋率輕而易舉

          Given -> When -> Expect .

          Wow-CI-Flow

          前置條件

          • 理解 領(lǐng)域驅(qū)動設(shè)計(jì):《實(shí)現(xiàn)領(lǐng)域驅(qū)動設(shè)計(jì)》、《領(lǐng)域驅(qū)動設(shè)計(jì):軟件核心復(fù)雜性應(yīng)對之道》
          • 理解 命令查詢職責(zé)分離(CQRS)
          • 理解 事件源架構(gòu)
          • 理解 響應(yīng)式編程

          特性

          •  Aggregate Modeling
            •  Single Class
            •  Inheritance Pattern
            •  Aggregation Pattern
          •  Saga Modeling
            •  StatelessSaga
          •  Test Suite
            •  兼容性測試規(guī)范(TCK)
            •  AggregateVerifier
            •  SagaVerifier
          •  EventSourcing
            • EventStore
              •  MongoDB (Recommend)
              •  R2dbc
                •  Database Sharding
                •  Table Sharding
              •  Redis
            • Snapshot
              •  MongoDB
              •  R2dbc
                •  Database Sharding
                •  Table Sharding
              •  ElasticSearch
              •  Redis (Recommend)
          •  CommandBus
            •  InMemoryCommandBus
            •  KafkaCommandBus (Recommend)
            •  RedisCommandBus
            •  LocalFirstCommandBus
          •  DomainEventBus
            •  InMemoryDomainEventBus
            •  KafkaDomainEventBus (Recommend)
            •  RedisDomainEventBus
            •  LocalFirstDomainEventBus
          •  StateEventBus
            •  InMemoryStateEventBus
            •  KafkaStateEventBus (Recommend)
            •  RedisStateEventBus
            •  LocalFirstStateEventBus
          •  Spring 集成
            •  Spring Boot Auto Configuration
            •  Automatically register CommandAggregate to RouterFunction
          •  可觀測性
            •  OpenTelemetry
          •  OpenApi
          •  WowMetadata Generator
            •  wow-compiler

          Example

          Example

          測試套件

          80%+ 的測試覆蓋率輕而易舉。

          Test Coverage

          Given -> When -> Expect .

          internal class OrderTest {
          
              companion object {
                  val SHIPPING_ADDRESS = ShippingAddress("China", "ShangHai", "ShangHai", "HuangPu", "001")
              }
          
              private fun mockCreateOrder(): VerifiedStage<OrderState> {
                  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<Int> {
                          return orderItems.toFlux().filter { it.productId == productId }.map { it.quantity }.last()
                      }
                  }
                  val pricingService = object : PricingService {
                      override fun getProductPrice(productId: String): Mono<BigDecimal> {
                          return orderItems.toFlux().filter { it.productId == productId }.map { it.price }.last()
                      }
                  }
                  return aggregateVerifier<Order, OrderState>(tenantId = tenantId)
                      .inject(DefaultCreateOrderSpec(inventoryService, pricingService))
                      .given()
                      .`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS))
                      .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()
              }
          
              /**
               * 創(chuàng)建訂單
               */
              @Test
              fun createOrder() {
                  mockCreateOrder()
              }
          
              /**
               * 創(chuàng)建訂單-庫存不足
               */
              @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<Int> {
                          return orderItems.toFlux().filter { it.productId == productId }
                              /*
                               * 模擬庫存不足
                               */
                              .map { it.quantity - 1 }.last()
                      }
                  }
                  val pricingService = object : PricingService {
                      override fun getProductPrice(productId: String): Mono<BigDecimal> {
                          return orderItems.toFlux().filter { it.productId == productId }.map { it.price }.last()
                      }
                  }
          
                  aggregateVerifier<Order, OrderState>()
                      .inject(DefaultCreateOrderSpec(inventoryService, pricingService))
                      .given()
                      .`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS))
                      /*
                       * 期望:庫存不足異常.
                       */
                      .expectErrorType(InventoryShortageException::class.java)
                      .expectStateAggregate {
                          /*
                           * 該聚合對象處于未初始化狀態(tài),即該聚合未創(chuàng)建成功.
                           */
                          assertThat(it.initialized, equalTo(false))
                      }.verify()
              }
          
              /**
               * 創(chuàng)建訂單-下單價(jià)格與當(dāng)前價(jià)格不一致
               */
              @Test
              fun createOrderWhenPriceInconsistency() {
                  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<Int> {
                          return orderItems.toFlux().filter { it.productId == productId }.map { it.quantity }.last()
                      }
                  }
                  val pricingService = object : PricingService {
                      override fun getProductPrice(productId: String): Mono<BigDecimal> {
                          return orderItems.toFlux().filter { it.productId == productId }
                              /*
                               * 模擬下單價(jià)格、商品定價(jià)不一致
                               */
                              .map { it.price.plus(BigDecimal.valueOf(1)) }.last()
                      }
                  }
                  aggregateVerifier<Order, OrderState>()
                      .inject(DefaultCreateOrderSpec(inventoryService, pricingService))
                      .given()
                      .`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS))
                      /*
                       * 期望:價(jià)格不一致異常.
                       */
                      .expectErrorType(PriceInconsistencyException::class.java).verify()
              }
          
              private fun mockPayOrder(): VerifiedStage<OrderState> {
                  val verifiedStageAfterCreateOrder = mockCreateOrder()
                  val previousState = verifiedStageAfterCreateOrder.stateRoot
                  val payOrder = PayOrder(
                      previousState.id,
                      GlobalIdGenerator.generateAsString(),
                      previousState.totalAmount
                  )
          
                  return verifiedStageAfterCreateOrder
                      .then()
                      .given()
                      /*
                       * 2. 當(dāng)接收到命令
                       */
                      .`when`(payOrder)
                      /*
                       * 3.1 期望將會產(chǎn)生1個(gè)事件
                       */
                      .expectEventCount(1)
                      /*
                       * 3.2 期望將會產(chǎn)生一個(gè) OrderPaid 事件 (3.1 可以不需要)
                       */
                      .expectEventType(OrderPaid::class.java)
                      /*
                       * 3.3 期望產(chǎn)生的事件狀態(tài)
                       */
                      .expectEventBody<OrderPaid> {
                          assertThat(it.amount, equalTo(payOrder.amount))
                      }
                      /*
                       * 4. 期望當(dāng)前聚合狀態(tài)
                       */
                      .expectState {
                          assertThat(it.address, equalTo(SHIPPING_ADDRESS))
                          assertThat(it.paidAmount, equalTo(payOrder.amount))
                          assertThat(it.status, equalTo(OrderStatus.PAID))
                      }
                      /*
                       * 完成測試編排后,驗(yàn)證期望.
                       */
                      .verify()
              }
          
              /**
               * 支付訂單
               */
              @Test
              fun payOrder() {
                  mockPayOrder()
              }
          
              /**
               * 支付訂單-超付
               */
              @Test
              fun payOrderWhenOverPay() {
                  val verifiedStageAfterCreateOrder = mockCreateOrder()
                  val previousState = verifiedStageAfterCreateOrder.stateRoot
                  val payOrder = PayOrder(
                      previousState.id,
                      GlobalIdGenerator.generateAsString(),
                      previousState.totalAmount.plus(
                          BigDecimal.valueOf(1)
                      )
                  )
                  verifiedStageAfterCreateOrder
                      .then()
                      .given()
                      /*
                       * 2. 處理 PayOrder 命令
                       */
                      .`when`(payOrder)
                      /*
                       * 3.1 期望將會產(chǎn)生倆個(gè)事件分別是: OrderPaid、OrderOverPaid
                       */
                      .expectEventType(OrderPaid::class.java, OrderOverPaid::class.java)
                      /*
                       * 3.2 期望產(chǎn)生的事件狀態(tài)
                       */
                      .expectEventStream {
                          val itr = it.iterator()
                          /*
                           * OrderPaid
                           */
                          val orderPaid = itr.next().body as OrderPaid
                          assertThat(orderPaid.paid, equalTo(true))
                          /*
                           * OrderOverPaid
                           */
                          val orderOverPaid = itr.next().body as OrderOverPaid
                          assertThat(
                              orderOverPaid.overPay,
                              equalTo(payOrder.amount.minus(previousState.totalAmount))
                          )
                      }
                      /*
                       * 4. 期望當(dāng)前聚合狀態(tài)
                       */
                      .expectState {
                          assertThat(it.paidAmount, equalTo(previousState.totalAmount))
                          assertThat(it.status, equalTo(OrderStatus.PAID))
                      }
                      .verify()
              }
          
              /**
               * 發(fā)貨
               */
              @Test
              fun ship() {
                  val verifiedStageAfterPayOrder = mockPayOrder()
                  val shipOrder = ShipOrder(verifiedStageAfterPayOrder.stateRoot.id)
                  verifiedStageAfterPayOrder
                      .then().given()
                      .`when`(shipOrder)
                      .expectEventType(OrderShipped::class.java)
                      /*
                       * 4. 期望當(dāng)前聚合狀態(tài)
                       */
                      .expectState {
                          assertThat(it.status, equalTo(OrderStatus.SHIPPED))
                      }
                      .verify()
              }
          
              @Test
              fun shipGivenUnpaid() {
                  val verifiedStageAfterCreateOrder = mockCreateOrder()
                  val shipOrder = ShipOrder(verifiedStageAfterCreateOrder.stateRoot.id)
                  verifiedStageAfterCreateOrder.then().given()
                      .`when`(shipOrder)
                      .expectErrorType(IllegalStateException::class.java)
                      .expectState {
                          /*
                           * 驗(yàn)證聚合狀態(tài)[未]發(fā)生變更.
                           */
                          assertThat(it.paidAmount, equalTo(BigDecimal.ZERO))
                          assertThat(it.status, equalTo(OrderStatus.CREATED))
                      }
                      .verify()
              }
          
              private fun mockDeleteOrder(): VerifiedStage<OrderState> {
                  val verifiedStageAfterCreateOrder = mockCreateOrder()
                  return verifiedStageAfterCreateOrder.then().given()
                      .`when`(DeleteAggregate)
                      .expectEventType(AggregateDeleted::class.java)
                      .expectStateAggregate {
                          assertThat(it.deleted, equalTo(true))
                      }
                      .verify()
              }
          
              @Test
              fun deleteOrder() {
                  mockDeleteOrder()
              }
          
              @Test
              fun deleteGivenDeleted() {
                  val verifiedStageAfterDelete = mockDeleteOrder()
                  verifiedStageAfterDelete.then().given()
                      .`when`(DeleteAggregate)
                      .expectErrorType(IllegalAccessDeletedAggregateException::class.java)
                      .expectError<IllegalAccessDeletedAggregateException> {
                          assertThat(it.aggregateId, equalTo(verifiedStageAfterDelete.stateAggregate.aggregateId))
                      }.expectStateAggregate {
                          assertThat(it.deleted, equalTo(true))
                      }
                      .verify()
              }
          }

          設(shè)計(jì)

          聚合建模

          Single Class Inheritance Pattern Aggregation Pattern
          Single Class - Modeling Inheritance Pattern- Modeling Aggregation Pattern- Modeling

          加載聚合

          Load Aggregate

          聚合狀態(tài)流

          Aggregate State Flow

          發(fā)送命令

          Send Command

          命令與事件流

          Command And Event Flow

          Saga - OrderProcessManager (Demo)

          OrderProcessManager

          瀏覽 27
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          編輯 分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          編輯 分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  爱搞搞,色 | 日韩又大又粗精品 | 波多野结衣在线观看一区二区 | 国产传媒一区二区 | 国产天堂视频 |