Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Structured format to describe a bounded context canvas #45

Open
martinnormark opened this issue Jun 16, 2023 · 5 comments
Open

Structured format to describe a bounded context canvas #45

martinnormark opened this issue Jun 16, 2023 · 5 comments

Comments

@martinnormark
Copy link

I'm looking for input before embarking in the journey to find or create a nice way to capture BC canvas information in a structured format.

The goal is to have an RFC like process to change BCs in a domain, where feedback can be gathered, changes suggested etc. Intention is for the process to be running on GitHub via PRs, which could use actions to render the structured format into an SVG or other visual format.

Questions

  • Knowledge of any "prior art"?
  • What would be a suitable file format? (YAML, JSON, something else)
  • Could also be a DSL inspired by Structurizr?
@NTCoding
Copy link
Member

This is a good idea, effectively a process for being more intentional about architecture changes and a way to have a history of architecture changes.

The first thing that comes to my mind is Contexture: https://github.com/trustbit/Contexture I know some of the people at Trustbit and I recommend them highly both professionally and personally.

I wonder if what you're proposing can be built into Contexture. That way you could get the benefits of everything they have already created for modeling and visualizing BCs. It could be worth reaching out to Trustbit and asking if they've have any experience or plans to build a similar feature.

@martinnormark
Copy link
Author

Contexture looks interesting. Could give even more visibility into how domains are modelled. I might open a discussion or issue in their repo, to see what they think.

However, a simple change process via GitHub could help validate our appetite for going further. We already have LeanIX and Backstage for cataloging our software, so keeping it minimal for now would be more compatible with our ways of working - especially an open RFC process fits in nicely with how we make bottom-up decisions.

I took a stab at defining a JSON schema with an example:

{
    "$schema": "../schemas/schema.json",
    "name": "Order Management",
    "purpose": "Handle customer orders from creation to delivery",
    "strategicClassification": {
        "importance": "core domain",
        "role": "revenue generator",
        "evolution": "product"
    },
    "domainRoles": [
        {
            "name": "Order Creation",
            "description": "Handles the initial creation of an order"
        },
        {
            "name": "Order Tracking",
            "description": "Tracks the progress of an order"
        }
    ],
    "inboundCommunication": {
        "messages": [
            {
                "type": "command",
                "content": "Create Order"
            }
        ],
        "collaborators": [
            {
                "type": "frontend",
                "relationship": "master"
            }
        ]
    },
    "outboundCommunication": {
        "messages": [
            {
                "type": "event",
                "content": "Order Created"
            }
        ],
        "collaborators": [
            {
                "type": "bounded context",
                "relationship": "slave"
            }
        ]
    },
    "ubiquitousLanguage": [
        {
            "name": "Order",
            "description": "A request from a customer for one or more products",
            "examples": [
                "Order #123",
                "Order for John Doe"
            ]
        },
        {
            "name": "Shipping",
            "description": "The process of sending an order to the customer",
            "examples": [
                "Shipping via UPS",
                "Shipping via Fedex"
            ]
        }
    ],
    "businessDecisions": [
        "Orders must be paid before they are shipped",
        "Orders can be cancelled before they are shipped"
    ],
    "assumptions": [
        "Payments are handled by another bounded context",
        "Shipping is handled by another bounded context"
    ],
    "verificationMetrics": [
        {
            "source": "CI/CD environments",
            "description": "Number of successful order creations"
        }
    ],
    "openQuestions": [
        "Do we need to handle back-orders?"
    ]
}

A generic schema is a good start, but you'd want to roll your own with a dictionary of domain events, bounded contexts and your opinionated verification metrics etc.

I'll probably write a minimal CLI to validate and generate visuals, and a GitHub action to use the CLI to check changes proposed in a PR and add visualisation as a comment.

An alternative to JSON, could be YAML. I found a minimal bounded context description in YAML:

contexts:
  - name: Cargo
    domainVisionStatement: To manage the routing of cargo through transportation legs
    paths:
    - CargoDemo
    terms:
    - name: Cargo
      definition: A unit of transportation that needs moving and delivery to its delivery location.
      examples:
        - Multiple Customers are involved with a Cargo, each playing a different role.
        - The Cargo delivery goal is specified.
    - name: Leg
      definition: The movement of a Cargo on a specific vessel from load location to unload location.
      examples:
        - Operations will need to contract handling work based on the expected times for each leg
        - For each leg we'd like to see the vessel voyage, the load and unload location, and time.
    - name: Policy
      definition: A set of rules that the routing service must follow when evaluating legs that confirm to the desired routing specification.
      examples:
        - We need to configure the set of policies that will apply for a specific customer.
    - name: LegMagnitudePolicy
      definition: A policy that helps the routing engine select the legs with the lowest magnitude.
      examples:
        - The leg magnitude policy is selecting the fastest leg, but we need it to select the cheapest leg.
  - name: Billing
    domainVisionStatement: Compute and levy charges for shipping
    paths:
    - BillingDemo
    terms:
    - name: Policy
      definition: A set of payment rules that defines when invoices are due, and actions to take when unpaid.
      examples:
        - The billing policy is to send to collections after 90 days in arrears.

@NTCoding
Copy link
Member

I agree, this is a good idea and I think your JSON example is a very good start. Maybe one thing missing is the ability to link messages and collaborators. It's not easy because it's kind of a many-to-many relationship.

I was also wondering: do you think we should follow OpenAPI spec conventions where possible?

@martinnormark
Copy link
Author

Yeah, I agree linking would be essential instead of free-typing names for collaborators and messages.

High level, I see these files in a repo structured by folders (better named in reality):

 - domain 01
   - sub-domain 01.01
     - bc 01.01.01.json
     - bc 01.01.02.json
 - domain 02
   - sub-domain 02.01
     - bc 02.01.01.json
     - bc 02.01.02.json
     - bc 02.01.03.json

Then collaborators could be defined by linking to other files:

"collaborators": [
    {
        "$ref": "../../domain 01/sub-domain 01.01/bc 01.01.02.json",
        "relationship": {...}
    }
]

Messages would be a little different, as another bounded context would likely publish multiple messages and you'd potentially only need a subset of them.

Outbound communication messages from a BC could be expressed so that it is linkable, for example:

{
  "outboundCommunication": {
    "orderCreated": { "type": "event", "name": "Order created" },
    "orderFulfilled": { "type": "event", "name": "Order fulfilled" },
    ...
  },
  ...
}

Then to link it as inbound, it would be like this:

"messages": [
    {
        "$ref": "../../domain 01/sub-domain 01.01/bc 01.01.02.json#/outboundCommunication/orderCreated"
    }
],

Re. OpenAPI conventions, are there any specifics you have in mind? I have relied a lot on tooling to generate an OpenAPI spec, so I don't know the conventions in the spec very well :neckbeard:

@NTCoding
Copy link
Member

NTCoding commented Jul 2, 2023

Looks good. I think it would be great to go ahead with this.

Regarding OpenAPI spec, I was envisioning creating a repository (or a folder inside this repository) with a similar structure: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants