Skip to content

Instantly share code, notes, and snippets.

JogoShugh / 07-Event-Sourced Domain
Last active April 24, 2024 13:45
Learning Domain-Driven Design book notes
  • Storing only "current state" completely loses all business value of "how things got this way over time" (time traveling lost)
  • Think about showing how event-sourced projections do the same level of work that is traditionally done by complicated SQL queries and graph building from disparate data sources -- but when combined with read-models they do them ahead of query time so as to optimize the retrieval of such data when it's used.


Learning curve

  • Different thinking
JogoShugh /
Last active September 13, 2022 11:18
Stateful vs Eventful

Calculating current state

When storing events to track the complete path of state transitions for an aggregate, it is always possible to also store a projection of the current state, but this is usually only necessary for aggregates that have large numbers of events. Since each SCA Transaction will not have a large number of events, that is probably overkill. Instead, a simple process of reading the list of past events and flowing them through a function that is capable of producing, or projecting, a model is rather straight forward. The most important part is to design this such that it only operates on the events, not on the original requests of "commands" since these often have side-effects like calling APIs, saving data, etc.

In Kotlin, this is easily achieved with a left fold over the set of events. For illustration purposes, consider the following simple illustration. You can run and edit the sample online here in the Kotlin Playground.

class Statef
JogoShugh / Create single
Created December 18, 2019 16:15
V1 Enterprise Bulk API



  "AssetType": "Story",
  "Scope": "Scope:0",
  "Name": "First Story"
JogoShugh /
Last active November 14, 2019 19:52
Api with next / prev links
JogoShugh /
Last active November 5, 2019 20:34
Auto generated docs from tests

Execute AssignMemberWithRole Operation upon a Scope for list of Members by OID Token

Demonstrates how to use a single command to assign multiple Members to a Scope along with Scope-specific roles each Member will have for the target Scope.


For the context of this example, the following request will setup the instance with the needed starting conditions:

POST http://host/instance/api/asset

JogoShugh /
Last active September 16, 2019 16:26
Bulk Error Handling

The following input payload specifies an array with 9 commands. These nine commands expand to 13 concrete actions for the backend API processor to execute. However, 12 of these actions are erroneous! Only one of them will succeed against the database running on the instance.

    "from": "Animal"
    "from": "Scope",
    "where": {
JogoShugh / hack.js
Last active April 29, 2019 19:41
Card aging with duration in each status stint
$(document).arrive('.story-card', function() {
const story = $(this);
const applyStatusAging = () => {
const number = story.find('.number').text().trim();
const title = story.find('.title');
const query = `
from: PrimaryWorkitem
Number: ${number}
$('.advisory').each((index, elm) => {
const el = $(elm);
const text = el.text().trim().replace(/\s+|\r|\n+/gmi, '');
const matches = text.match(/\d+/gi);
if (matches) {
if (matches.length>1) matches[1]+='c';
const aging = `<span title='${text}'>${matches.join(', ')}</span>`;
const story = el.parents('.story-card');
JogoShugh / 01 Specification and Automated API Test A.ts
Created January 9, 2019 05:36
VersionOne Bulk API automated test examples
import {test, assetApiPost} from '../../lib/asset-api-helper';
const types = ['yaml', 'json'];
for(const type of types) {
test(`Update Description LongText scalar Attribute on two Defects, replacing one exact match string with another by OIDToken (${type})`, async t => {
const setupCommand = `
AssetType: Scope
Name: Test - Update Description LongText scalar Attribute on two Defects with find and replace Scope
Parent: Scope:0
fun score rolls =
case rolls of
[] => 0
| n1::n2::n3::[] => n1 + n2 + n3
| n1::n2::n3::rest =>
if n1 = 10 then 10 + n2 + n3 + score (n2::n3::rest)
else if n1 < 10 andalso n1 + n2 = 10 then n1 + n2 + n3 + score (n3::rest)
else if n1 + n2 < 10 then n1 + n2 + score (n3::rest)
else score rest
| n1::rest => n1 + score rest