Overview
Emlang is a YAML-based DSL for describing systems with Event Modeling patterns.
- An Emlang file must be a valid YAML file
- Each YAML document must contain a
slicestop-level key slicesmay be empty- A file may contain multiple YAML documents separated by
--- - The root object must not contain properties other than
slices
slices:
SliceName:
- t: Swimlane/TriggerName
- c: DoSomething
- e: SomethingDone
Elements
Emlang defines 5 element types, each with multiple prefix forms:
| Type | Short | Acronym | Long |
|---|---|---|---|
| Trigger | t: |
trg: |
trigger: |
| Command | c: |
cmd: |
command: |
| Event | e: |
evt: |
event: |
| Exception | x: |
err: |
exception: |
| View | v: |
— | view: |
- All prefix forms of a given type are semantically equivalent
- An element must contain exactly one type key
- An element may contain a
propskey - An element must not contain keys other than one type key and
props
# Valid
- c: RegisterUser
- e: UserRegistered
# Invalid: two type keys in the same item
- c: RegisterUser
e: UserRegistered
Naming
- Element names are free-form text
- Names must not be empty
- Names must not end with
/ - Names may contain spaces, accents, and special characters
Swimlanes
Swimlanes are optional. A swimlane is specified as a prefix separated by / before the element name.
- t: Customer/RegistrationForm # Swimlane: Customer
- e: User/UserRegistered # Swimlane: User
- c: RegisterUser # No swimlane
Properties
Properties are optional and defined under a props key. The structure of props is free-form — consuming tools decide how to interpret them.
- c: RegisterUser
props:
email: string
password: string
Slices
A slice is a named sequence of elements representing a business scenario. A slice may be empty.
Direct Form
The direct form is a list of elements. It should be used when a slice has no attached tests.
slices:
UserRegistration:
- t: Customer/RegistrationForm
- c: RegisterUser
- e: User/UserRegistered
- v: UserProfile
Extended Form
The extended form is an object with steps and optionally tests. Use it when a slice has tests.
stepsis required but may be emptytestsis optional and may be empty- The extended form must not contain properties other than
stepsandtests
slices:
UserRegistration:
steps:
- t: Customer/RegistrationForm
- c: RegisterUser
- e: User/UserRegistered
tests:
EmailMustBeUnique:
given:
- e: User/UserRegistered
props:
email: joe@example.com
when:
- c: RegisterUser
props:
email: joe@example.com
then:
- x: EmailAlreadyInUse
Multiple Slices
Multiple slices may be defined in the same document. Both direct and extended forms may coexist.
slices:
UserRegistration:
- t: Customer/RegistrationForm
- c: RegisterUser
- e: User/UserRegistered
UserLogin:
- t: Customer/LoginForm
- c: AuthenticateUser
- e: User/UserAuthenticated
- v: Dashboard
Tests
Tests are defined inside a slice using the extended form. Each test follows a Given-When-Then structure.
| Section | Required | Allowed element types |
|---|---|---|
given |
No | Events (e:), Views (v:) |
when |
No | Commands (c:) |
then |
No | Events (e:), Views (v:), Exceptions (x:) |
given,when, andthenare all optional and may be empty- A test may be empty
- A test must not contain properties other than
given,when, andthen - A slice may contain multiple named tests
tests:
EmailMustBeUnique:
given:
- e: User/UserRegistered
props:
email: joe@example.com
when:
- c: RegisterUser
props:
email: joe@example.com
then:
- x: EmailAlreadyInUse
PasswordMustBeStrong:
when:
- c: RegisterUser
props:
password: "123"
then:
- x: PasswordTooWeak
TodoCompleteRegistrationFlow:
Document Structure
A file may contain one or more YAML documents separated by ---. Each document must independently conform to this specification.
---
slices:
UserRegistration:
- t: Customer/RegistrationForm
- c: RegisterUser
- e: User/UserRegistered
---
slices:
UserDeletion:
steps:
- t: Admin/UserManagement
- c: DeleteUser
- e: User/UserDeleted
tests:
CannotDeleteActiveUser:
given:
- e: User/UserAuthenticated
when:
- c: DeleteUser
then:
- x: UserCurrentlyActive
Comments
Standard YAML comments (
#) may be used anywhere.slices: OrderPlacement: - t: Customer/ProductPage # User clicks "Buy Now" - c: PlaceOrder # Validates inventory - e: Order/OrderPlaced # Core domain event