Case study of implementing DDD

Introduction

Following is a brief description of the lessons learned when rewriting one single player online game using DDD. Team who did this work was: Kirill, Jaanus, Erik and I. I think that this is the first implementation of Domain Model or DDD in Aqris.

Background

This application was a web based game consisting of Flash client and Java server. They communicated with each other using simple proprietary protocol built upon HTTP. Some generic services like user balance and game state management were provided by game platform which was accessed from game server using plain Java API.

In old version of this game all logic was implemented in 2 huge classes. Game flow was implemented in a procedural style directly accessing game state and configuration from any place where it was needed. Customer wanted us to add support for more advanced game logic so we decided that we will rewrite the whole server using DDD. One reason why we chose DDD was that traditional controller-service-dao style architecture simply didn't offer any scaffolding for this type of application.

General architecture

In final result it was possible to differentiate following logical layers:

  • presentation
  • application
  • domain
  • persistence

Presentation layer

For each user action we implemented one Action class which converted request parameters to types suitable for domain and then forwarded call to the Play class in application layer. When receiving response from application layer Actions converted it into simple key value pairs to be returned to client. These Action classes were quite similar to controllers in Spring MVC but compared to typical web application they didn't contain any domain logic (see Fat Controller).

Application layer

This layer was implemented using single Play class which managed all game flow. For each action it had a separate method which returned either some entity from domain model or composite of multiple entities when needed. For example it had methods like startGame, play, finishGame etc. Primary responsibilities of Play were coordinating different domain entities and retrieving/storing them using Repositories.

When we started implementing this game we had much of the application flow decisions made in presentation layer so our design was more close to "exposed domain model". However when we progressed we decided to hide that from Action classes hence making the responsibilities of Play and Actions more clearly separated. In order to avoid ending up in having another god class like in legacy we tried to push all business rules into the domain model. Actually I have to admit that while we were implementing this game we didn't quite define Play to be a Facade in application layer. Instead it was sort of domain Entity with some additional responsibilities. This unclarity didn't of course benefit system understandability.

Domain model

This layer contained Entity classes like User, Life, WinResult, Level, Reel etc and some Value Objects like ReelNumber. These classes were not just data structures but also contained all logic related to their state. In addition we had some Specification classes which contained all configuration related to some type of Entities. For example StakeSpecification contained configurable rules about max allowed stakes.

Persistence

Usually it is said that it's not possible to implement DDD application without some ORM tool. In our case we used game platform API for accessing game state. Compared to real ORM frameworks this API was quite basic as it was only possible to save/retrieve key value pairs. Fortunately memory footprint of this game state was very small so we didn't have much need for advanced ORM features. We decided to hide all access to platform state management API behind Repositories. In most cases these Repositories returned domain Entities but we made some exceptions when we just had to return string values from DB to the presentation layer. Although lazy initialization wasn't needed in most cases there were some situations were it would have been handy. We decided not to make any Entity depend on Repository but instead initialized Entities with enough data needed for given use case.

Conclusion

  • if team is new to concepts of DDD then implementing takes more time than using more common styles. We had to do several design reviews and refactor our initial solutions a lot before we achieved satisfiable solution
  • everybody in the team should be familiarized with DDD concepts at least during the project. DDD hides some complexity by introducing additional abstractions without understanding these ideas system will look even more complex (see About complexity)
  • when you start designing your system concentrate on Entities. Ignore things like Factories, Repositories etc or you will easily loose focus. Also don't get stuck with trying to differentiate Value Objects and Entities
  • as system evolves try to classify all your classes under some of the stereotypes offered by DDD. This simplifies following guidelines of what is allowed and what not for any class

Finally two good reasons why you should use DDD:

  • it scales well when adding new requirements. We initially implemented simple version of the game and later added support for more advanced version. We managed to do latter quite easily without any bigger disruptions
  • four developers were able to work on this project in parallel without having to spend too much time on resolving CVS conflicts. This is quite interesting considering that this game logic was quite cohesive unlike typical data entry applications where each form or report is quite independent.

Labels

ddd ddd Delete
domainmodel domainmodel Delete
domain domain Delete
design design Delete
casestudy casestudy Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.