Skip to content

Commit a49c648

Browse files
📝 docs: README.md describing the project purpose (#10)
1 parent 108d206 commit a49c648

6 files changed

Lines changed: 157 additions & 0 deletions

README.md

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# Heroes of Domain-Driven Design (Java)
2+
Shows how to use Domain-Driven Design, Event Storming, Event Modeling and Event Sourcing in Heroes of Might & Magic III domain.
3+
4+
👉 See also implementations in: [Ruby](https://github.com/MateuszNaKodach/HeroesOfDomainDrivenDesign.EventSourcing.Ruby) | **Java + Spring + Axon**
5+
6+
👉 [Let's explore the Heroes of Domain-Driven Design blogpost series](https://dddheroes.com/)
7+
- There you will get familiar with the whole Software Development process: from knowledge crunching with domain experts, designing solution using Event Modeling, to implementation using DDD Building Blocks.
8+
9+
This project probably won't be fully-functional HOMM3 engine implementation, because it's done for educational purposes.
10+
If you'd like to talk with me about mentioned development practices fell free to contact on [linkedin.com/in/mateusznakodach/](https://www.linkedin.com/in/mateusznakodach).
11+
12+
I'm focused on domain modeling on the backend, but I'm going to implement UI like below in the future.
13+
14+
![Heroes3_CreatureRecruitment_ExampleGif](https://github.com/user-attachments/assets/0e503a1e-e5d2-4e4a-9150-1a224e603be8)
15+
16+
## 🚀 How to run the project locally?
17+
18+
0. Install Java 23 on your machine
19+
1. `./mvnw install -DskipTests`
20+
2. `docker compose up`
21+
3. `./mvnw spring-boot:run` or `./mvnw test`
22+
23+
## 🧱 Modules
24+
25+
Modules (mostly designed using Bounded Context heuristic) are designed and documented on EventModeling below.
26+
Each slice in a module is in certain color which shows the progress:
27+
- green -> completed
28+
- yellow -> implementation in progress
29+
- red -> to do
30+
- grey -> design in progress
31+
32+
List of modules you can see in package `com.dddheroes.heroesofddd`.
33+
```
34+
heroesofddd/
35+
├── armies
36+
├── astrologers
37+
├── calendar
38+
├── creature_recruitment
39+
```
40+
41+
Each domain-focused module follows Vertical-Slice Architecture of three possible types: write, read and automation following Event Modeling nomenclature.
42+
43+
### 👾 Creature Recruitment
44+
45+
![EventModeling_Module_CreatureRecruitment.png](docs/images/EventModeling_Module_CreatureRecruitment.png)
46+
47+
Slices:
48+
- Write: [BuildDwelling -> DwellingBuilt](src/main/java/com/dddheroes/heroesofddd/creaturerecruitment/write/builddwelling) | [test](src/test/java/com/dddheroes/heroesofddd/creaturerecruitment/write/builddwelling/BuildDwellingTest.java)
49+
- Write: [IncreaseAvailableCreatures -> AvailableCreaturesChanged](src/main/java/com/dddheroes/heroesofddd/creaturerecruitment/write/changeavailablecreatures) | [test](src/test/java/com/dddheroes/heroesofddd/creaturerecruitment/write/changeavailablecreatures/IncreaseAvailableCreaturesTest.java)
50+
- Write: [RecruitCreature -> CreatureRecruited](src/main/java/com/dddheroes/heroesofddd/creaturerecruitment/write/recruitcreature) | [test](src/test/java/com/dddheroes/heroesofddd/creaturerecruitment/write/recruitcreature)
51+
- Read: (DwellingBuilt, AvailableCreaturesChanged, CreatureRecruited) -> DwellingReadModel [projector](src/main/java/com/dddheroes/heroesofddd/creaturerecruitment/read/DwellingReadModelProjector.java)
52+
- GetDwellingById: [query](src/main/java/com/dddheroes/heroesofddd/creaturerecruitment/read/getdwellingbyid/GetDwellingByIdQueryHandler.java) | [test](src/test/java/com/dddheroes/heroesofddd/creaturerecruitment/read/getdwellingbyid/GetDwellingByIdTest.java)
53+
- GetAllDwellings: [query](src/main/java/com/dddheroes/heroesofddd/creaturerecruitment/read/getalldwellings/GetAllDwellingsQueryHandler.java)
54+
- Automation: [WhenCreatureRecruitedThenAddToArmy](src/main/java/com/dddheroes/heroesofddd/creaturerecruitment/automation/WhenCreatureRecruitedThenAddToArmyProcessor.java) | [test](src/test/java/com/dddheroes/heroesofddd/creaturerecruitment/automation/WhenCreatureRecruitedThenAddToArmyTest.java)
55+
56+
Aggregates:
57+
- [Dwelling](src/main/java/com/dddheroes/heroesofddd/creaturerecruitment/write/Dwelling.java)
58+
59+
### 🧙 Astrologers
60+
61+
![EventModeling_Module_Astrologers.png](docs/images/EventModeling_Module_Astrologers.png)
62+
63+
Slices:
64+
- Write: [ProclaimWeekSymbol -> WeekSymbolProclaimed](src/main/java/com/dddheroes/heroesofddd/astrologers/write/proclaimweeksymbol) | [test](src/test/java/com/dddheroes/heroesofddd/astrologers/write/proclaimweeksymbol/ProclaimWeekSymbolTest.java)
65+
- Automation: [DayStarted(where day==1) -> ProclaimWeekSymbol](src/main/java/com/dddheroes/heroesofddd/astrologers/automation/whenweekstartedthenproclaimweeksymbol/WhenWeekStartedThenProclaimWeekSymbolProcessor.java) | [test](src/test/java/com/dddheroes/heroesofddd/astrologers/automation/whenweekstartedthenproclaimweeksymbol/WhenWeekStartedThenProclaimWeekSymbolTest.java)
66+
- Automation: [(WeekSymbolProclaimed, all game dwellings derived from DwellingBuilt events) -> IncreaseAvailableCreatures for each dwelling in the game where creature == symbol](src/main/java/com/dddheroes/heroesofddd/astrologers/automation/whenweeksymbolproclaimedthenincreasedwellingavailablecreatures/WhenWeekSymbolProclaimedThenIncreaseDwellingAvailableCreaturesProcessor.java) | [test](src/test/java/com/dddheroes/heroesofddd/astrologers/automation/whenweeksymbolproclaimedthenincreasedwellingavailablecreatures/WhenWeekSymbolProclaimedThenIncreaseDwellingAvailableCreaturesTest.java)
67+
68+
Aggregates:
69+
- [Astrologers](src/main/java/com/dddheroes/heroesofddd/astrologers/write/Astrologers.java)
70+
71+
### 📅 Calendar
72+
73+
![EventModeling_Module_Calendar.png](docs/images/EventModeling_Module_CalendarSlices.png)
74+
75+
Slices:
76+
- Write: [StartDay -> DayStarted](src/main/java/com/dddheroes/heroesofddd/calendar/write/startday) | [test](src/test/java/com/dddheroes/heroesofddd/calendar/write/startday/StartDayTest.java)
77+
- Write: [FinishDay -> DayFinished](src/main/java/com/dddheroes/heroesofddd/calendar/write/finishday) | [test](src/test/java/com/dddheroes/heroesofddd/calendar/write/finishday/FinishDayTest.java)
78+
- Read: [DayStarted -> CurrentDateReadModel] -- todo
79+
80+
Aggregates:
81+
- [Calendar](src/main/java/com/dddheroes/heroesofddd/calendar/write/Calendar.java)
82+
83+
### 🎖️ Armies
84+
85+
Slices:
86+
- Write: [AddCreatureToArmy -> CreatureAddedToArmy](src/main/java/com/dddheroes/heroesofddd/armies/write/addcreature) | [test](src/test/java/com/dddheroes/heroesofddd/armies/write/addcreature/AddCreatureToArmyTest.java)
87+
- Write: [RemoveCreatureFromArmy -> CreatureRemovedFromArmy](src/main/java/com/dddheroes/heroesofddd/armies/write/removecreature) | [test](src/test/java/com/dddheroes/heroesofddd/armies/write/removecreature/RemoveCreatureFromArmyTest.java)
88+
89+
Aggregates:
90+
- [Army](src/main/java/com/dddheroes/heroesofddd/armies/write/Army.java)
91+
92+
93+
## 🏛️ Screaming Architecture
94+
95+
The project follows a Screaming Architecture pattern organized around vertical slices that mirror Event Modeling concepts.
96+
97+
![ScreamingArchitecture](docs/images/ScreamingArchitecture.png)
98+
99+
The package structure screams the capabilities of the system by making explicit: commands available to users, events that capture what happened, queries for retrieving information, business rules, and system automations.
100+
This architecture makes it immediately obvious what the system can do, what rules govern those actions, and how different parts of the system interact through events.
101+
102+
Each module is structured into three distinct types of slices:
103+
104+
### Write Slices
105+
Contains commands that represent user intentions, defines business rules through aggregates, produces domain events, and enforces invariants (e.g., RecruitCreature command → CreatureRecruited event, with RecruitCreaturesNotExceedAvailableCreatures rule).
106+
107+
### Read Slices
108+
Implements queries and read models optimized for specific use cases, with projectors that transform events into queryable state (e.g., GetDwellingById query → DwellingReadModel).
109+
110+
### Automation Slices
111+
Processes events to trigger subsequent actions, implementing system policies and workflows that connect different modules (e.g., WhenCreatureRecruitedThenAddToArmyProcessor).
112+
113+
## 🧪 Testing
114+
Tests using Real postgres Event Store, follows the approach:
115+
- write slice: given(events) -> when(command) -> then(events)
116+
- read slice: given(events) -> then(read model)
117+
- automation: when(event, state?) -> then(command)
118+
119+
Tests are focused on observable behavior which implicitly covers the DDD Aggregates, so the domain model can be refactored without changes in tests.
120+
121+
### Example: write slice
122+
123+
![EventModeling_GWT_TestCase_CreatureRecruitment.png](docs/images/EventModeling_GWT_TestCase_CreatureRecruitment.png)
124+
125+
```java
126+
@BeforeEach
127+
void setUp() { // Axon Framework Test Fixture
128+
fixture = new AggregateTestFixture<>(Dwelling.class);
129+
}
130+
131+
@Test
132+
void givenDwellingWith2Creatures_WhenRecruit2Creatures_ThenRecruited() {
133+
// given
134+
var givenEvents = List.of(
135+
dwellingBuilt(),
136+
availableCreaturesChanged(2)
137+
);
138+
139+
// when
140+
var whenCommand = recruitCreature(2);
141+
142+
// then
143+
var thenEvent = creatureRecruited(2);
144+
fixture.given(givenEvents)
145+
.when(whenCommand)
146+
.expectEvents(thenEvent);
147+
}
148+
```
149+
150+
151+
-------
152+
153+
### 💼 Hire me
154+
155+
If you'd like to hire me for Domain-Driven Design and/or Event Sourcing projects I'm available to work with:
156+
Kotlin, Java, C# .NET, Ruby and JavaScript/TypeScript (Node.js or React).
157+
Please reach me out on LinkedIn [linkedin.com/in/mateusznakodach/](https://www.linkedin.com/in/mateusznakodach/).
30.1 KB
Loading
202 KB
Loading
99.4 KB
Loading
448 KB
Loading
87.8 KB
Loading

0 commit comments

Comments
 (0)