Giter Club home page Giter Club logo

adaptech / les Goto Github PK

View Code? Open in Web Editor NEW
51.0 5.0 13.0 43.09 MB

Go directly from an event storming to a working API: Event Markdown / Markup validation & NodeJS CQRS/ES application builder.

Home Page: https://docs.letseventsource.org

License: BSD 3-Clause "New" or "Revised" License

Go 94.15% Makefile 2.14% Shell 2.61% Dockerfile 1.10%
golang nodejs eventsourcing cqrs-es cqrs eventstorming emd eml apis eventstore swagger openapi docker docker-compose

les's Introduction

LES

Join the chat at https://gitter.im/Adaptech/les

"Let's Event Source"

Event sourcing and CQRS/ES based "microservices" are increasingly seen as a nice way to build cohesive, loosely coupled systems with good transactional integrity. There is a knack to building software that way, so although the resulting systems tend to be much simpler and easier to understand than traditional (e.g.) object oriented implementations, there is a bit of a learning curve.

LES attempts to address this in three ways:

  1. Fast microservice prototyping: Go directly from an event storming to a working event sourced API.

  2. "Architect in a box": les validate assesses whether a prototype will result in a "good" event sourced microservice - cohesive, loosely-coupled, transactionally consistent. Then les-node -b builds a deployment-ready NodeJS API with plenty of guide fences and best practices in place as developers go forward customizing it. If you have your own coding standards or don't like NodeJS, implement your own in a language of your choice.

  3. "Citizen IT Developer". One of the goals of the LES project is to enable "business coders", "power users" and entrepreneurs with little technical knowledge to build highly scalable event sourced microservices from scratch, basically "I've made this API for my startup - could you build me an app for that?"

LES is currently in alpha. We have started using 1. and 2. in Real Life projects. But no.3 (Citizen IT Developer) especially is still quite experimental, with a good number of features missing.

See also: LES FAQ

LESTER Pipeline

Getting Started

Prerequisites

Installation

Latest version from source:

git clone https://github.com/Adaptech/les.git
make install

... or ...

Instructions for Linux, Windows Mac & Docker

Hello World

Step 1:

Create an Event Markdown file. Event Markdown (EMD) is a simple language used to describe an event storming:

# TODO List
Add Item -> // description, dueDate
Todo Added // description, dueDate
TODO List* // todoId, description, dueDate

Save it to Eventstorming.emd.

Step 2:

les convert && les-node -b && cd api && npm install && docker-compose up -d --force-recreate

Or using Docker:

docker run -v $(pwd):/les les convert && docker run -v $(pwd):/les les-node -b && cd api && npm install && docker-compose up -d

(If you doing this in Linux and encounter "permission denied" errors, your USER or GROUP ID need to be specified. Say your USER ID is 1003, then add --user 1003 after each docker run in the above command.)

Step 3:

There is no step 3.

What next ...

IDE Integrations & Tools

Known UX Impacting Issues

The issues below have been known to mystify EMD users:

Sporadic Race condition when doing cd api && npm install && docker-compose up -d

API doesn't start because Eventstore isn't up yet. (Workaround: docker-compose restart api)

#11

Need to have at least one read model parameter which is not an aggregate ID

#10

Running The Tests

make test-all

Roadmap

Features & Fixes

les's People

Contributors

adymitruk avatar gitter-badger avatar markgukov avatar mohkami avatar nicdex avatar rgitzel avatar robertreppel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

les's Issues

<event> MustHaveHappened & <event> MustNotHaveHappened command preconditions

Preconditions must must be fulfilled in order for a command to be able to execute, otherwise a validation error occurs.

Example:

Solution: User Registration
Contexts:
- Name: User Registration
  Streams:
  - Stream: User
    Commands:
    - Command:
        Name: RegisterUser
        Parameters:
        - Name: email
          Type: string
          IsRequired: true
        Postconditions:
        - UserRegistered
    - Command:
        Name: Authenticate
        Parameters:
        - Name: email
          Type: string
          IsRequired: true
        Preconditions:
        - UserRegistered MustHaveHappened
        Postconditions:
        - UserAuthenticated
    Events:
    - Event:
        Name: UserRegistered
        Properties:
        - Name: "name"
          Type: string
          IsHashed: false
        - Name: "userId"
          Type: string
          IsHashed: false
    - Event:
        Name: UserAuthenticated
        Properties:
        - Name: "userId"
          Type: string
          IsHashed: false
  Readmodels: []
Errors: []

EMD->EML generation bug: Should not require additional readmodel property in EMD

In the current version there needs to be at least one read model parameter which is not an aggregate ID in order for the EMD->EML converter to be able to find the events a read model needs to subscribe to:

This is OK:

# test
Register -> userId, name
User Registration Happened // userId, name
Submit -> timesheetId
Timesheet Submitted // timesheetId
Timesheets* // timesheetId, userId, name

This should be OK, but isn't:

# test
Register -> userId, name
User Registration Happened // userId, name
Submit -> timesheetId
Timesheet Submitted // timesheetId
Timesheets* // timesheetId, userId

les validate results in:

EML Errors:
MissingReadmodelSubscribesToEvent: test-Timesheets: Missing Readmodel SubscribesTo Event(s)

There is no need for this limitation - EMD->EML should be able to find the "Timesheet Submitted" and "User Registration Happened" events based on the EMD supplied.

"Event Happened //" should not lead to validation errors

When running les validate with

# test
command->
Event Happened //

Results in:

EML Errors:
NoPropertyName: test-Event: EventHappened: Event property names cannot be blank.

InvalidEventPropertyName: test-Event: Invalid event property name '': Names must start with a character and contain no spaces.

There is no real reason why this shouldn't result in valid EML. The trailing "//" can be stripped when converting EMD to EML.

Trailing comma in "Event Happened // property," shouldn't lead to validation errors

When running les validate with

# test
command->
Event Happened // property,

Results in:

EML Errors:
NoPropertyName: test-Event: EventHappened: Event property names cannot be blank.

InvalidEventPropertyName: test-Event: Invalid event property name '': Names must start with a character and contain no spaces.

There is no real reason why this shouldn't result in valid EML. The trailing comma can be stripped when converting EMD to EML.

"docker-compose up" sporadic race condition

Sporadic Race condition when doing cd api && npm install && docker-compose up -d
API doesn't start because Eventstore isn't up yet. (Workaround: docker-compose restart api)

"command-> // parameter," should not lead to validation errors

When running les validate with

# test
command-> // parameter
Event Happened

this is OK.

However, adding a comma after the parameter fails:

# test
command-> // parameter,
Event Happened

Result:

EML Errors:
InvalidCommandParameterName: test-Event: Invalid command parameter name 'command': Names must start with an alpha character and contain no spaces.

There is no real reason why this shouldn't result in valid EML - The trailing comma can be stripped when when converting from EMD to EML.

The "DromedaryCase" bug: myaggregateId GOOD, myAggregateId BAD

CamelCase doesn't work; it assumes that the 'I' in "Id" at the end of aggregate/stream id parameters and properties is the only uppercase char. Fails without les validate error and results in broken les-node API code.

For example: inventoryitemId vs. inventoryItemId

This works:

Receive Product-> // productId, description
InventoryItem Stocked // inventoryitemId, sku, description, purchasePrice, quantityAvailable
InventoryitemLookup* // inventoryitemId, productId, description

This passes les validate but results in a broken les-node -b API:

Receive Product-> // productId, description
InventoryItem Stocked // inventoryItemId, sku, description, purchasePrice, quantityAvailable
InventoryitemLookup* // inventoryItemId, productId, description

only one hump

RFC: Proposed new features for the next version of EML (0.2-alpha)

Proposed new features:

  • Preconditions for commands, e.g. TimesheetCreated MustHaveHappened or TimesheetDeleted MustNotHaveHappened DONE
  • Selecting individual event properties in Readmodel SubscribesTo
  • Spreadsheet-like functionality for Readmodels, e.g. @SUM(TimesheetHoursLogged.hours).totalHours

Example:

Solution: Timesheets & Billing
EmlVersion: 0.2-alpha
Contexts:
- Name: Timesheets & Billing
  Streams:
  - Stream: User
    Commands:
    - Command:
        ID: RegisterUser
        Name: Register User
        Parameters:
        - Name: email
          Type: string
          Rules: []
        - Name: password
          Type: string
          Rules: []
        - Name: userId
          Type: string
          Rules:
          - IsRequired
        Postconditions:
        - UserRegistered
    Events:
    - Event:
        ID: UserRegistered
        Name: User Registered
        Properties:
        - Name: email
          Type: string
          IsHashed: false
        - Name: password
          Type: string
          IsHashed: true
        - Name: userId
          Type: string
          IsHashed: false
        Type: ""
  - Stream: Timesheet
    Commands:
    - Command:
        ID: CreateTimesheet
        Name: Create Timesheet
        Parameters:
        - Name: userId
          Type: string
          Rules:
          - MustExistIn UserLookup
        - Name: description
          Type: string
          Rules: []
        - Name: timesheetId
          Type: string
          Rules:
          - IsRequired
        Preconditions:
        - Not TimesheetCreated
        - LastEventIs Not TimesheetSubmitted
        Postconditions:
        - TimesheetCreated
    - Command:
        ID: SubmitTimesheet
        Name: Submit Timesheet
        Parameters:
        - Name: submissionDate
          Type: string
          Rules: []
        - Name: userId
          Type: string
          Rules:
          - MustExistIn UserLookup
        - Name: timesheetId
          Type: string
          Rules:
          - IsRequired
        Preconditioins:
        - Has TimesheetCreated
        - Not Has TimesheetSubmitted
        Postconditions:
        - TimesheetSubmitted
    Events:
    - Event:
        ID: TimesheetCreated
        Name: Timesheet Created
        Properties:
        - Name: userId
          Type: string
          IsHashed: false
        - Name: description
          Type: string
          IsHashed: false
        - Name: timesheetId
          Type: string
          IsHashed: false
        Type: ""
    - Event:
        ID: TimesheetSubmitted
        Name: Timesheet Submitted
        Properties:
        - Name: timesheetId
          Type: string
          IsHashed: false
        - Name: submissionDate
          Type: string
          IsHashed: false
        - Name: userId
          Type: string
          IsHashed: false
        Type: ""
  - Stream: TimesheetHours
    Commands:
    - Command:
        ID: LogHours
        Name: Log Hours
        Parameters:
        - Name: timesheethoursId
          Type: string
          Rules:
          - IsRequired
        - Name: timesheetId
          Type: string
          Rules:
          - MustExistIn TimesheetLookup
        - Name: date
          Type: string
          Rules: []
        - Name: hours
          Type: string
          Rules: []
        Postconditions:
        - TimesheetHoursLogged
    Events:
    - Event:
        ID: TimesheetHoursLogged
        Name: TimesheetHours Logged
        Properties:
        - Name: timesheethoursId
          Type: string
          IsHashed: false
        - Name: timesheetId
          Type: string
          IsHashed: false
        - Name: date
          Type: string
          IsHashed: false
        - Name: hours
          Type: string
          IsHashed: false
        Type: ""
  Readmodels:
  - Readmodel:
      ID: UserLookup
      Name: UserLookup
      Key: userId
      Columns:
      - UserRegistered.*
  - Readmodel:
      ID: TimesheetLookup
      Name: TimesheetLookup
      Key: timesheetId
      SubscribesTo:
      - TimesheetCreated.*
      - TimesheetSubmitted.submissionDate
      - @SUM(TimesheetHoursLogged.hours).totalHours
      - @MIN(TimesheetHoursLogged.date).fromDate
      - @MAX(TimesheetHoursLogged.date).toDate
      - @IF(@ISBLANK(TimesheetSubmitted.submissionDate),"","submitted on {{TimesheetSubmitted.submissionDate}}")
  - Readmodel:
      ID: TimesheetHoursLookup
      Name: TimesheetHoursLookup
      Key: timesheethoursId
      Columns:
      - TimesheetHoursLogged.*
Errors: []

command-> param, param2, param3 should be valid EMD.

  • TODO: 'command -> someParameter' should be valid EMD.

The current implementation is command -> // someParameter, but it's very common to forget entering the '//'. This is not good because les and webeventstorming.com fail silently (or sometimes confusingly). Suggest that it might be better to fall forward and make both the command-> // parameter and the command-> parameter syntax valid EMD.

Real-time EMD/EML to Swagger API builder: "les-openapi" command line tool

That would be a command line tool for a real-time EMD (or EML) to Swagger API converter.

"les-node -b" currently builds a Swagger API which is hosted off the Node API server.

If we had a stand-alone version which can update itself live in a browser whenever "les validate -f" has an "OK" result, people could edit EMD or EML and explore the resulting API in Swagger in real-time.

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.