Difference between revisions of "Event storming"

From CitconWiki
Jump to navigationJump to search
Line 5: Line 5:
 
I'm not able to edit the wiki pages still (there is some error when trying to confirm the email). So I'll post it here:
 
I'm not able to edit the wiki pages still (there is some error when trying to confirm the email). So I'll post it here:
  
<blockquote>
 
 
Notes: Schools of TDD: St. Pauli
 
Notes: Schools of TDD: St. Pauli
  
- 1957 - John von Neumann actually invented TDD
+
* 1957 - John von Neumann actually invented TDD
    - Punch cards were programs and data as well, together with the expectation of what result it will produce. Then they took the expected card and the output card and looked if all the holes were in the same place.
+
** Punch cards were programs and data as well, together with the expectation of what result it will produce. Then they took the expected card and the output card and looked if all the holes were in the same place.
- 1989 - Beck re-discovered TDD.
+
* 1989 - Beck re-discovered TDD.
- In these 30/60 years, different school styles happened.
+
* In these 30/60 years, different school styles happened.
- There are many styles (probably on the same scale as number of developers), but only a few are actually described:
+
* There are many styles (probably on the same scale as number of developers), but only a few are actually described:
    - Chicago/Detroit - Classicist style
+
** Chicago/Detroit - Classicist style
    - London - Mockist style
+
** London - Mockist style
    - The following were developed in the last 10 years
+
** The following were developed in the last 10 years
        - Munich
+
*** Munich
        - St. Pauli
+
*** St. Pauli
        - Portland (2 weeks old name of the school)
+
*** Portland (2 weeks old name of the school)
        - Hamburg
+
*** Hamburg
        - TDD as if You Meant it
+
*** TDD as if You Meant it
        - TCR: Test Commit Revert
+
*** TCR: Test Commit Revert
- Steven Collins lived in St. Pauli when he created the school
+
* Steven Collins lived in St. Pauli when he created the school
- St. Pauli TDD is outside-in direction, first test case is simple, mocks are avoided, and subproblems are solved with stubs first, and then are replaced with TDD process recursively.
+
* St. Pauli TDD is outside-in direction, first test case is simple, mocks are avoided, and subproblems are solved with stubs first, and then are replaced with TDD process recursively.
    - Start on API level
+
** Start on API level
    - Obvious implementation
+
** Obvious implementation
    - Fake it till you make it
+
** Fake it till you make it
    - Triangulate
+
** Triangulate
    - Validation tests
+
** Validation tests
    - Append-only tests
+
** Append-only tests
  
 
Diamond Kata example:
 
Diamond Kata example:
Line 215: Line 214:
  
 
Discussion: When there are interactions with other dependencies need to be involved, since we want to avoid any kind of test double, then we would have to approach it with “imperative shell, functional core”.
 
Discussion: When there are interactions with other dependencies need to be involved, since we want to avoid any kind of test double, then we would have to approach it with “imperative shell, functional core”.
</blockquote>
 

Revision as of 08:05, 14 October 2023

https://www.eventstorming.com/resources/

https://techbeacon.com/app-dev-testing/introduction-event-storming-easy-way-achieve-domain-driven-design

I'm not able to edit the wiki pages still (there is some error when trying to confirm the email). So I'll post it here:

Notes: Schools of TDD: St. Pauli

  • 1957 - John von Neumann actually invented TDD
    • Punch cards were programs and data as well, together with the expectation of what result it will produce. Then they took the expected card and the output card and looked if all the holes were in the same place.
  • 1989 - Beck re-discovered TDD.
  • In these 30/60 years, different school styles happened.
  • There are many styles (probably on the same scale as number of developers), but only a few are actually described:
    • Chicago/Detroit - Classicist style
    • London - Mockist style
    • The following were developed in the last 10 years
      • Munich
      • St. Pauli
      • Portland (2 weeks old name of the school)
      • Hamburg
      • TDD as if You Meant it
      • TCR: Test Commit Revert
  • Steven Collins lived in St. Pauli when he created the school
  • St. Pauli TDD is outside-in direction, first test case is simple, mocks are avoided, and subproblems are solved with stubs first, and then are replaced with TDD process recursively.
    • Start on API level
    • Obvious implementation
    • Fake it till you make it
    • Triangulate
    • Validation tests
    • Append-only tests

Diamond Kata example: 1. We start with the simplest example: start with an “A” case, instead of “C” case (like in case of a Munich school). it("should return A for A", () => {

expect(diamond("A")).toEqual("A");

});

1. The implementation is simple:

function diamond(input: string) {

return "A";

}

1. Next simplest test would be the “B” diamond, the next smallest increment

it("should return B Diamond for B", () => {
 expect(diamond("B")).toEqual(

`.A. B.B .A.`

 );
});

1. St. Pauli uses a very simple approach of fake it till you make it to make it pass:

function diamond(input: string) {

if (input === "A") {
 return "A";
} else {
 return `.A.

B.B .A.`;

}

}

Comment: “In London school, you would do the same thing and the same process in this Kata” Response: “In London school, you would already start thinking about what happens below that”

Discussion: Diamond Kata may or may not be too simple for comparison of different TDD schools, because not every implementation will even require multiple interactions or mocks between objects or functions. Also, when teaching this school to not very experienced TDD practitioners, a more complex Kata may confuse them even more.

1. We proceed with the next test, for “C”:

it("should return C Diamond for C", () => {
 expect(diamond("C")).toEqual(

`..A.. .B.B. C...C .B.B. ..A..`

 );
});

1. At this point we can see some pattern, or not. Let’s say that we don’t, so we make another fake implementation:

function diamond(input: string) {

switch (input) {
 case "A":
  return "A";
 case "B":
  return `.A.

B.B .A.`;

 case "C":
  return `..A..

.B.B. C...C .B.B. ..A..`;

}

}

1. As we start spotting some patterns, we can start performing refactoring. For example, the end lines can be improved:

function diamond(input: string) {

switch (input) {
 case "A":
  return “A”;
 case "B":
  return [".A.", "B.B", ".A."].join("\n");;
 case "C":
  return ["..A..", ".B.B.", "C...C", ".B.B.", "..A.."].join("\n");
}

}

1. Another pattern that we observe is that every diamond has a “middle line”. So we can extract a function that does it. We implement it first via recursive TDD process:

describe("middleLine", () => {

it("should return middle line for B", () => {
 expect(middleLine("B")).toEqual("B.B");
});

});

1. And, of course, we implement it simply:

function middleLine(input: string) {

return "B.B";

}

1. Another test for C middle line:

it("should return middle line for C", () => {

expect(middleLine("C")).toEqual("C...C");

});

1. Implementation

function middleLine(input: string) {

switch (input) {
 case "B":
  return "B.B";
 case "C":
  return "C...C";
}

}

1. Replace the middle lines in the original function

function diamond(input: string) {

switch (input) {
 case "A":
  return ["A"].join("\n");
 case "B":
  return [".A.", middleLine("B"), ".A."].join("\n");
  ;
 case "C":
  return ["..A..", ".B.B.", middleLine("C"), ".B.B.", "..A.."].join("\n");
}

}

1. Extract the concept of “letter” in all functionality

function diamond(letter: string) {

switch (letter) {
 case "A":
  return ["A"].join("\n");
 case "B":
  return [".A.", middleLine(letter), ".A."].join("\n");
  ;
 case "C":
  return ["..A..", ".B.B.", middleLine(letter), ".B.B.", "..A.."].join("\n");
}

}

function middleLine(letter: string) {

switch (letter) {
 case "B":
  return ${letter}.${letter};
 case "C":
  return ${letter}...${letter};
}

}

1. Another pattern we can observe is number of dots generated in the middle line. Here, the function is so simple, that we can use obvious implementation pattern and testing:

describe("dots", () => {

it("should generate the number of dots", () => {
 expect(dots(0)).toEqual("");
 expect(dots(1)).toEqual(".");
 expect(dots(2)).toEqual("..");
 expect(dots(3)).toEqual("...");
});

});

function dots(number: number) {

return ".".repeat(number);

}

1. Replace the number of dots accordingly:

function middleLine(letter: string) {

switch (letter) {
 case "B":
  return ${letter}${dots(1)}${letter};
 case "C":
  return ${letter}${dots(3)}${letter};
}

}

1. You keep finding the patterns and refactoring them, in multiple iterations.

1. At the end, when you believe that you’re done, you add a validation test (you do this at every level of abstraction, going upwards.

Discussion: This is a way that allows to go with very very tiny steps (that can be used for complex problems where the trade-off is positive of going slower, with the smallest steps).

Discussion: When there are interactions with other dependencies need to be involved, since we want to avoid any kind of test double, then we would have to approach it with “imperative shell, functional core”.