Code Monkey home page Code Monkey logo

stochastic's People

Contributors

ryan-mars avatar sam-goodwin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

sam-goodwin

stochastic's Issues

Bounded Context

  • Emits public events via EventBridge #28
  • Publish schemas for public events to EventBridge schema registry #15
  • Can subscribe to events from another bounded context #20
  • Has an event store, forwarder, and topic #29
  • Has a unique name (don't allow two bounded contexts in the same AWS account with the same name)
  • Tags all resources associated with it #67
  • Cross account event bridge #66

Bounded Context

Organisations don’t usually have consistent languages to describe their domain. Silos actively fragment knowledge into locally consistent bubbles, but end-to-end language consistency is usually a myth. The larger the organization, the more specialized jargons thrive around a specific function.
A Bounded Context is a unit of language consistency, a portion of the model that guarantees that every term has one and only one meaning, greatly improving our modeling precision.

A few clues about how to effectively partition a system:

  • We’ll see where people tend to be, and usually different people tend to have different specific needs
  • We’ll see boundaries, between different phases and swimlanes, often pointing to different needs.

Screen Shot 2021-05-04 at 12 56 47 PM

Credit: Alberto Brandolini

Policy

  • subscription filter for events #27
  • has an event handler lambda function
  • Handler can invoke commands #26

Policy

Software Model

Illustrations ©️ Avanscoperta

External Service

Easily represent arbitrary code (e.g. npm module or REST API) as a "External System" with a simple pattern for registering Commands and Events. This is not to be confused with sending/receiving commands/events from other Bounded Contexts implemented with Stochastic.

Store (Aggregate)

  • Aggregate.Client fetches event history #24
  • Aggregate reducer/monoid produces current state from events #23
  • Rename Aggregate to Store #49
  • Aggregate versioning #50

Maybe later:

  • Convenience functions on Aggregate class for declaring Commands and Events that "operate on" the aggregate

“The Aggregate”

I kept the name ‘aggregate’ mostly for historical reasons, EventStorming was born around Domain-Driven Design and Aggregates, so it makes little sense to look for another name. Aggregates are unit of transactional consistency within a software system. More interestingly they are little state machines that expose consistent behaviour.
— Alberto Brandolini

Aggregate

Illustration ©️ Avanscoperta

Command & Handler

  • Command Handler accepts a Command shape (message) and returns an array of events
  • Can get the current state of the aggregate #23 #24
  • Command stores events returned by handler #25
  • Returns errors as part of command response #41

Refactor Policy and ReadModel to use base class EventHandler

ReadModel (projections) and Policy are the only "event handler" components we have right now. It is conceivable that developers will want to respond to events in ways we have not yet conceived. It would be nice if there was a base class EventHandler they could use or extend to suit their needs.

Shapes

  • Convert Shapes from super-struct to Sam's Shapes. #38
  • Shape fields that are optional or defaulted are not reflected as optional in the constructor. #37
  • Shapes JSON schema #61
  • Shapes DynamoDB #62

Optional aggregate for commands

Some folks will not want to use an aggregate. In that case commands should just generate events that are saved/emitted irrespective of a specific aggregate.

Events: Simplify event DX

Simplify the specification of Event and event shapes as well as and runtime creation of events with data. Potentially use mixin pattern or superstruct's create function.

Epic: Event #4

Pan Am Airline example app

  • clean up in Miro
  • make Miro board publicly readable
  • complete event storming process
  • Event storm -> Code
  • Flight cancellation scenario #58
  • Loyalty points award scenario #57
  • End to end cucumber test #51
  • UI and polish #56

Docs

Devs need docs

  • Rough initial set of docs #71
  • API docs
  • Nice dev site with tutorial / getting started
  • Explanations for people new to CQRS, event sourcing, or domain driven design

BoundedContext: Can subscribe to events from another bounded context

Some events will be emitted outside of the bounded context for others to react. We need a component that will aid the developer in describing this behavior.

Related #15, #7

// operations/src/service.ts
import { scheduling } from "scheduling/lib/index";

const SchedulingBoundedContext = new ExternalBoundedContext({
  boundedContext: scheduling,
});

const {
  ScheduledFlightAddedEvent,
  FlightCreatedEvent,
} = SchedulingBoundedContext.events;

export const FlightManagementPolicy = new Policy(
  {
    __filename,
    events: [ScheduledFlightAddedEvent, FlightCreatedEvent],
    commands: [AddFlight],
  },
  async (event, commands) => {
    // ...
  }
);

export const operations = new EventStorm({
  handler: "operations",
  name: "Operations",
  components: {
    SchedulingBoundedContext,
    FlightManagementPolicy,
    AddFlight,
  },
});

Event: runtime discriminator

We need a way to discriminate events at runtime either with data, or when serializing/deserializing JSON.

Sam recommended __typename.

Epic: Event #4

IAM policies should implement principle of least privilege

🤔 Since we know the set of domain events a command should produce we could use IAM policy conditions for fine grained (write) access control to the event store...

I'm sure there are many similar instances where we could follow "principle of least privilege".

Query

  • has a query handler function
  • handler takes a query message (ex. graphql query), the read model client, executes the query and returns the result to the caller
  • example queries

Event Storm Visualization

  • Define a business process #55
  • Visualize an Event Storm #70
  • "Process Model" resolution level
  • "Software Model" resolution level
  • Infrastructure (all of the above + AWS resources)

Ideally you'd be able to produce this visualization from a CDK app using the stochastic module, that has not been synthesized or deployed. Perhaps at minimum we could require synthesis of the CDK app. Feedback requested.

Read Model & Projection

Read Models

Read models are an interesting twist in modelling style: they provide the information needed in order to take a given decision.
... the design of Read Models is driven by the needs of a consequential decision.

Software Model

Illustration ©️ Avanscoperta

  • has a projection function for each of the events it subscribes to
  • projection function arguments: client for the read model store (or perhaps an identifier such as an ARN), and the event
  • subscribes to the appropriate events
  • has r/w permissions on the read model store
  • helper implementations of DynamDBReadModel and ElastiCacheReadModel
  • Sample code for read models and projections

Aggregate: Reducer/monoid

Aggregate reducer produces current state from events.

Aggregate component should take a reducer function or some kind of monoid.

Epic: Aggregate #11

Resource location at runtime

Wondering if there's a straight forward way that we could provide resource identifiers (ARN, table name, etc...) to any closure where the component is in scope. This could provide a useful escape hatch for developers doing weird stuff.

Imagine I had an edge case where I needed to interact with the database for a Read Model from within a command handler. Ignore all the reasons why this could be done with a proper Query, or whether we're violating CQRS. If each component provides getResourceLocator: () => Promise<string> it could be used at runtime to fetch the ARN or other useful identifier for use with the AWS SDK (et.al.). If we stored these identifiers in SSM then the only runtime binding becomes a string key on the component uniquely identifying it.

const userNames = new ReadModel({
   ...
})

const createUser = new Command({
    ...
    handler: async (command, aggregate) => {
        const tableName = await userNames.getResourceLocator() // in this case we know it's a DynamoDB table
        // ... do ugly stuff with the DynamoDB Client 
    }
})

Event

  • has a shape / is an ADT (provided by superstruct)
  • can be validated at runtime from JSON (provided by superstruct)
  • is strongly typed (provided by superstruct)
  • Simplify Event DX #22
  • Event runtime discriminator #21
  • Event needs source and source_id fields #35
  • Re-visit the payload boiler-plate in DomainEvent #34

Event replay

  • time range #52
  • event type #53
  • filter recipients #54

Should this be done by cdk-triggers during deploy or should we allow this to be initiated ad-hoc via some sort of API?

Tracking Issue for 1.0

Overview

The following issues track discussion and implementation of key features of Stochastic for Event Storm -> Code.

  • Event #4

  • Policy #10

  • Command & Handler #8

  • Aggregate #11

  • Bounded Context #7

  • Read Model & Projection #6

  • Query a Read Model #5

  • External Service #2

  • AWS Serverless & CDK Infrastructure #12

  • Event replay #9

  • Event storm visualization #3

  • Pan Am Airline example app #13

  • event storm is decoupled from runtime architecture and infrastructure provider

  • fluent interface matching event storming output

Event Storming

Process Modeling

Illustration ©️ Avanscoperta

Sample use case

The utility of stochastic would be best demonstrated through a useful example app. We'll resurrect Pan-Am airlines for this.

The story goes roughly like this:

  • Scheduler adds flights to schedule
  • I book a ticket
  • I select dates, origin, destination
  • I select my seat (contention around resources)
  • I pay
  • I cancel my ticket
  • Seat is released
  • Cancellation policy does different stuff depending on your status level
  • Refund
  • Credit
  • I check in (traveler)
  • I board (gate agent)
  • Dispatcher does out, up, on, in
  • Loyalty policy awards points
  • Dispatcher cancels flight
  • Deplane
  • Manifest is cleared
  • Rebooking policy rebooks according to status

Big Picture

Big Picture Event Storm

Process Model

Process Model Event Storm

Software model

Software Model

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.