1 - Design my entities, ie (in python):
class Account: def __init__(name, author): self.name = name self.email = email
2 - Design my repositories: (as interface)
class AccountRepository: def add(self, account): """ @type account Account """ pass def find_by_name(self, name): pass def find_by_email(self, email): pass # remove, and others...
Now, I can go two ways:
A: Design and implement my domain services:
class SignUpService: def __init__(self, account_repository): """ @type account_repository AccountRepository """ self._account_repository = account_repository def create_account(self, username, email): account = Account(username, email) self._account_repository.add(account) # other methods that uses the account_repository
B: Implement my Repositories Strategies:
class MongodbAccountRepository(AccountRepository): def __init__(self, mongodb_database): self._mongodb_database = mongodb_database def add(self, account): account_data = account.__dict__ self._mongodb_database.accounts.insert(account_data) # and the other methods
Which is the correct order? and why? 1, 2, A, B or 1, 2, B, A?
Thank you so much!
Firstly I'd start off with the UI, thinking about the tasks/commands users need to perform and the data involved in each task/command. This is known as a Task-Based UI approach.
These tasks will form a 1-1 mapping with methods provided by the Application Services (different to a Domain Service).
Then I'd design my aggregates based on these tasks & data - an optimal design would be for one task/transaction (Application Service call) only involving one aggregate. To me, this is what designing aggregates based on behavior is all about.
I only implement Domain Services where a transaction needs to change state on more than one aggregate. These Domain Services abstract any logic away from the Application Service (who's job is only to orchestrate).
Storage would come last - you can only implement storage once you know exactly what you're storing?
So my full order is:
Application Service (I call it a command service)
FYI I tend to follow the principals of CQRS so querying is also another 'layer' I need to consider, but I've just given the order in terms of DDD and designing aggregates.
On the subject of designing aggregates, I recommend the these articles by Vaughn Vernon
I also wrote a blog regarding designing aggregates based on behavior.
On one level you've answered your own question. Your
SignUpService is using an
AccountRepository, so you'll need at least some repo implementation just to basic testing. On a practical level, though, you're likely to see more churn in your services as you come to grips with your domain, so that's where you'll probably need to spend more time.
So if you're looking for a rule of thumb, I'd say to first get a working repository implementation. It doesn't have to be your "production" version, but it should be able to drive the system. Then get your services and the rest of the domain correct. The domain model - not the storage layer - is where the value in DDD comes from, so get that right and let that inform your choice of storage backend, not the other way around.
My personal opinion is that one should start where the business logic is located and that is the domain. Even though you would implement one user story at the time, one should start from the domain and operations in the domain. One should also apply the same languange (ubiquitous language) in the domain.
After that is implemented and tested, rest comes naturally. You implement infrastructure concerns, application services, ui.