Skip to content

Latest commit

 

History

History
201 lines (125 loc) · 7.8 KB

File metadata and controls

201 lines (125 loc) · 7.8 KB

< back to 03 Roles, Commands and Event Mapping

Modeling and Development

Now, you have the whole story, bounded context and just-enough aggregates, commands, and events. It's time to develop domain model to proof crunched model is correct or not.

Design & Develop model iteratively and incrementally is recommended, never to run this workshop in a waterfall style, that's spent lots of time but encounter uncontrollable surprise at last-minute.

Specification by Example

Feature: Order Americano in seat

  Scenario: Drink Americano, stay in
    Given customer wants to order coffee with the following detail
      | coffee    | quantity | price |
      | Americano | 2        | 80    |
    When the order is confirmed
    Then the total fee should be 160l

Want to have concrete requirements scenario? The only way is to talk about an example.

A living doucment help team to collaborate in the same understanding by example.

Try to read the feature and scenario as above, all of the stakeholders could read and understand it, there is no technical term explained there, which is a good way to talk with stakeholder.

Team should co-work on these documents, once the examples confirmed, developers could leverage it to generate a unit test code skeleton, and implement it accordingly.

TDD within Unit Test environment

In this workshop, cucumber-java is in used to run the example.

package cucumber;


import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
@CucumberOptions(
        plugin = "json:target/cucumber-report.json",
        glue = "cucumber",
        features = "src/test/resources/")
public class RunCucumberTest {
}

Generate unit test code skeleton

By running the cucumber-java steps, Java compiler complained that there are no implementation methods regarding Feature: Order_Americao.

Cucumber complained that all of these scenario were not implemented, you are encourged to imeplement this methods.

You can implement missing steps with the snippets below:

Given("customer wants to order coffee with the following detail", (io.cucumber.datatable.DataTable dataTable) -> {
    // Write code here that turns the phrase above into concrete actions
    // For automatic transformation, change DataTable to one of
    // E, List<E>, List<List<E>>, List<Map<K,V>>, Map<K,V> or
    // Map<K, List<V>>. E,K,V must be a String, Integer, Float,
    // Double, Byte, Short, Long, BigInteger or BigDecimal.
    //
    // For other transformations you can register a DataTableType.
    throw new cucumber.api.PendingException();
});

When("the order is confirmed", () -> {
    // Write code here that turns the phrase above into concrete actions
    throw new cucumber.api.PendingException();
});

Then("the total fee should be {int}l", (Integer int1) -> {
    // Write code here that turns the phrase above into concrete actions
    throw new cucumber.api.PendingException();
});


Process finished with exit code 0

Implement Domain Model from code Skeleton

It's a TDD style approach, way to fulfill Feature: Order_Americano steps.

package cucumber;

import io.cucumber.java8.En;
import solid.humank.coffeeshop.order.commands.CreateOrder;
import solid.humank.coffeeshop.order.models.Order;
import solid.humank.coffeeshop.order.models.OrderId;
import solid.humank.coffeeshop.order.models.OrderItem;
import solid.humank.coffeeshop.order.models.OrderStatus;

import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class OrderAmericanoSteps implements En {

    CreateOrder cmd;
    Order createdOrder;

    public OrderAmericanoSteps() {

        Given("customer wants to order coffee with the following detail", (io.cucumber.datatable.DataTable dataTable) -> {
            List<Map<String, String>> testData = dataTable.asMaps(String.class, String.class);
            Map<String, String> sample = testData.get(0);

            String productId = sample.get("coffee");
            int qty = Integer.valueOf(sample.get("quantity"));
            BigDecimal price = new BigDecimal(sample.get("price"));

            List<OrderItem> items = new ArrayList<>();
            items.add(new OrderItem(productId, qty, price));
            cmd = new CreateOrder(new OrderId(1, OffsetDateTime.now()), "0", OrderStatus.INITIAL, items);

        });

        When("the order is confirmed", () -> createdOrder = Order.create(cmd));

        Then("the total fee should be {int}l", (Integer int1) -> {
            assertEquals(createdOrder.totalFee().longValue(), int1.longValue());
        });
    }
}

Design each Microservices in Port-adapter concept

image

The famous Port-Adapter pattern is the best suite for developing microservices. Focus on core domain problem, and switch any infrastructure or communication tools as you need.

image

For this workshop demo, design a order domain object, and leverage AWS services to do persistent, http request accept and handler, and event propagation.

Using Amazon EventBridge Event as the integration Event

You can easily export a lambda function to accept the incomg command, and do some stuff. If cross boundary event did occured in current domain, never call other domain service directly, just publish a cross-domain-event. On AWS, the most appropriate one is using EventBridge Event, it's a near-real-time event, high performance and scalable.

Using DynamoDB as the Write Model/ Read Model persistent Repository

Once capture Model with Domain Experts, you can design Write Model first, and create Query usage Read Model.

Further Information

Special Thanks For

Jenson Lee , plays the role as coffee shop owner

Eason Kuo, Core team member from Domain Driven Design Taiwan Community

Arthur Chang , collaborate design & run the workshop, Co-founder from Domain Driven Design Taiwan Community

Kenny Baas-Schwegler , discuss the aggregate definition and ES workshop running experience sharing

Next: 05 Deploy Applications by AWS CDK >