Hej, już kiedyś poruszałem ten wątek, ale chyba poszedłem nie w tą stronę.
Chciałem poprawnie za pomocą praktyk DDD zamodelować mecz szachowy. Idąc tropem agregatów DDD powiniem tak zamodelować agregat, aby zamknąć w nim niezmienniki.
Agregat powinien dostać ID wygranego gracza i wyliczyć ich nowy ranking. Wynika z tego, że powinien on przechowywać aktualne rankingi obu graczy. Na początku nie mogłem w ogóle dojść do tego jak za pomocą id tego agregatu wyciągnąć najnowsze rankingi z bazy. Zrozumiałem wreszcie, że agregat nie musi być przecież tabelką w DB. Zrobiłem zatem coś takiego:
data class Rank(val value: Int) {
fun apply(difference: Int) = Rank(value + difference)
}
data class MatchScoreId(val player1Id: String, val player2Id: String)
data class MatchScore(val id: MatchScoreId, private val player1Rank: Rank, private val player2Rank: Rank) {
fun applyResult(winPlayerId: String, calculateRankDifference: (Int, Int) -> Int): MatchScore {
val difference = calculateRankDifference(player1Rank.value, player2Rank.value)
return copy(
player1Rank = player1Rank.apply(difference),
player2Rank = player1Rank.apply(-difference)
)
}
}
Teraz po prostu dochodzi z frontu jakiś request z winPlayerId i losePlayerId. Pobieram to z repozytorium, wykonuję metodę applyResult
i zapisuję.
Jeśli chodzi o szczegół czyli DB to mam tam po prostu dużą tabelę Player z ich obecnymi rankingami i innymi danymi specyficznymi dla gracza. Agregat natomiast modeluje to co potrzebuje. Mecze nie muszę być zapisywane w DB - tak akurat wymyśliłem sobie biznes, że nie musi to być zapisywane jako fakt historyczny. Po prostu wysłanie requestu opisanego powyżej z idWin i idLose jest triggerem naliczenia nowych rankingów.
Czy to jest ok?
Nie muszę dzięki temu uderzać do innych serwisów po aktualne rankingi. Wszystko jest skrojone w agregacie pod wykonanie biznesu naliczenia nowych rankingów.