Inside-Out and Outside-In are fairly rare terms, more often I have heard/read about Classic school and London school.
Inside-Out (Classic school, bottom-up): you begin at component/class level (inside) and add tests to requirements. As the code evolves (due to refactorings), new collaborators, interactions and other components appear. TDD guides the design completely.
Outside-In (London school, top-down or "mockist TDD" as Martin Fowler would call it): you know about the interactions and collaborators upfront (especially those at top levels) and start there (top level), mocking necessary dependencies. With every finished component, you move to the previously mocked collaborators and start with TDD again there, creating actual implementations (which, even though used, were not needed before thanks to abstractions). Note that outside-in approach goes well with YAGNI principle.
Neither of the approaches is the one and only; they both have their place depending on what you do. In large, enterprise solutions, where parts of the design come from architects (or exists upfront) one might start with "London style" approach. On the other hand, when you face a situation where you're not certain how your code should look (or how it should fit within other parts of your system), it might be easier to start with some low-end component and let it evolve as more tests, refactorings and requirements are introduced.
Whichever you use, more often than not it is situational.
For further reading, there's Google group post with rather interesting discussion on how this distinction (might have) originated and why London might not be the most appropriate name.
Are Domain Services merely an Interface which exist to provide a layer
of abstraction between the Infrastructure Layer and your Model? ie:
Repositories + HashingServices, etc.
Domain services responsibilities include several things. The most obvious is housing logic that doesn't fit into a single entity. For example, you may need to authorize a refund for a certain purchase, but to complete the operation you need data from the Purchase
entity, Customer
entity, CustomerMembership
entity.
Domain services also my provide operations needed by the domain to complete its functionality such as PasswordEncryptionService
, but the implementation of this service will reside in the infrastructure layer since it will mostly be a technical solution.
Infrastructure services are services which so an infrastructure operation such as opening a network connection, copy file from file system, talk to an external web service or talk to database.
Application services are the implementation of a use case in the application you are building. If you are cancelling a flight reservation you would:
- Query the database for the Reservation object.
- invoke Reservation->cancel.
- Save object to DB.
The application layer is the client of the domain. The domain has no idea what your use case is. It just exposes the functionality through its aggregates and domain services. The application layer however mirrors what you are trying to achieve by orchestrating the domain and infrastructure layers.
I mentioned having an Application Service which looks like this:
Access/Application/Services/UserService::CreateUser(string name,
string email, etc): User
The method signature accepts primitive data type arguments and returns
a new User Entity (not a DTO!).
PHP might not be the best place to start learning about DDD since many of the PHP frameworks out there (Laravel, Symfony, Zend,..etc) tend to promote RAD. They are focused more on CRUD and translating forms to entities. CRUD != DDD
Your presentation layer should be responsible for reading the form inputs from the request object and invoking the correct application service.
The application service will create the user and invoke the User repository to save the new user. You may optionally return a DTO of the user back to the presentation layer.
How should separate modules handle unidirectional relationships.
Should module A reference module B's application layer (as it's doing
now) or the infrastructure implementation (via separated interface)?
The word module in DDD lingo has a different meaning than what you are describing. A module should house related concepts. For example, an order module in the domain layer could house the Order aggregate, OrderItem entity, OrderRepositoryInterface and MaxOrderValidationService.
An Order module in the application layer could house the OrderApplicationServie, CreateOrderCommand and OrderDto.
If you are talking about layers then each layer should preferably depend on interfaces of other layers whenever possible. The presentation layer should depend on interfaces of the application layer. Application layer should reference interfaces of the repositories or domain services.
I personally don't create interfaces for entities and value objects coz I believe interfaces should be related to a behavior, but YMMV :)
Do Application Layer Services require a Separate Interface? If the
answer is yes then where should they be located?
It depends :)
for complex applications I build interfaces coz we apply rigorous unit, integration and acceptance testing. Loose coupling is key here and the interfaces are in the same layer (application layer).
For simple app I build against the app services directly.
Best Answer
Make sure you review Uncle Bob's recent comments about the role of design in TDD.
Udi Dahan: "God, how I hate layering." He spends some time discussing it in his talk CQRS - but Different (layering starts at 18m30s)
I would spell your sentence slightly differently; "DDD recognizes that there are a number of concerns common to most business applications and that the solutions to those concerns have different lifetimes".
For example domain concerns, as a rule, need to be flexible -- especially when you are customizing a solution for a particular business. After all, the domain concerns how the company does business, which is to say, how the company makes money and being able to deliver business improvements quickly is free revenue.
On the other hand, you probably don't need to change the persistence component often. The database solution that worked last release will probably also work this release.
The application concerns are somewhere in the middle; they tend to be stable so that the users don't need to learn a new app with every release.
Also, there can be multiple implementations to solve any given concern. For instance, the application may need only a snapshot of its current state -- simply saving a file to disk will suffice. And in your first few iterations, that may be all the domain needs too. But eventually comes a story that calls for ad-hoc query support, and you recognize that configuring a relational database will be a lot easier than implementing one from scratch. And then there's this one feature that would work better in a graph database.
Meanwhile, the CTO wants a version of the app that runs on his phone; the CEO just heard from a guy that publishing an API is the big thing.
Also, the sales team uses a different model, so give us the same app, with a different model. Oh, but we're travelling a lot, so our version needs to work when we are offline and sync up later...
In other words, you apply the tactical patterns from ddd not by implementing empty placeholders and assuming they will get filled in later, but instead by recognizing when you are crossing the streams "Hey, that's persistence code in my domain model, I must not be done refactoring yet."