Here are my notes from Emanuele DelBono's talk about Domain Driven Design in Ruby from RuPy 2013.
A Story of an Application
- Two kinds of users with application, but just a single domain model. Citizen. Devise, cancan, etc. added to the domain model code.
- Class defined from the point of view of the architect. Big ball of mud with logic from the point of view of the citizen user and the admin user. Good to begin with but becomes unmanageable.
- Can load Citizen, from there to address, there to citizens in that address. Using relations, whole object graph can be traversed.
- The project failed, main reason is the technology
- Technique invented by Eric Evans in 2004, also wrote the book.
- A way to do analysis in big projects. The book talks about how analysis should be made to get best information. It's also about design. Finally, it's a series of patterns for building application.
- In first meetings, it's important to define a vocabulary. You and the customer should agree on the meaning of words. User might be the user of the application, but for the customer it might have a different meaning. This is called the Ubiquitous Language. The name should be the same in code as in in discussion.
- Point of view of the customer should also be discussed: Different people in different departments might use the same concept in different ways. For this reason, it's important to define the Bounded Context in which a vocabulary.
- There was a problem where the bounded context was not defined. The same Citizen object was used, but in completely different ways. Lots of problems from that.
- In different contexts a Customer class might have two different representations. One with id, name, shipping address, orders, etc. Another with id name, VAT code, billing address, etc. Same customers, different models.
- Two different kinds of objects: Entities and Value Objects. Customer is an entity with an id. Address doesn't really have an id, it's defined by it's value.
- The definition of aggregates. A domain model should not be all interconnected, but should be organized in aggregates. Each aggregate has a root, which guarantees the consitency of the aggregate. Everything you do with the aggregate should be done through the aggregate root.
- Between aggregates communication happens with Domain Events.
- These patterns, if applied correctly, leads to a well-designed application. Key points: Bounded contexts and aggregate roots.
- Classical layerered architecture / "lasagna design": UI layer, application layer, domain models/business layer, data layer/orm, database.
- The problem with this layering is that there's no difference between reading and writing.
- When you read something, it's a simple operation. But when you write something, it should be validated, there's business logic behind it, lots of things going on before it's written to the database.
- Why should we then use same architecture for reading and writing?
- We should stop thinking in CRUD. The customer doesn't do that. When they create a contract or send an invoice, it doesn't mean that a contract is saved in a database, they don't care about that. What they care about that the contract is created and a new business process starts.
- Separating reading and writing leads us to CQRS - Command-Query Separation. Querying the database is different from executing a command.
- Writing happens with Commands, managed by handlers which operates the domain model and saves changes to the database. The main thing is that whatever happens, it comes in as a command.
Reading is much simpler. You just read the stuff from the database, there's no need for all the layers.
There can be two databases: A write DB and a read DB. In the write DB, storage is very simple.
In the read DB there are views designed just for reading the right kind of information from the database.
A normalization tool is needed to take data from the write database and puts it in the read database. The read database is denormalized and typically duplicates a lot of data.
- This kind of architecture leads us to another topic that's becoming popular: Event Sourcing.
- We can think of what happens in transitions instead of state.
- Each thing that happens is an event like "Item Added", "Item Removed", "Coupon Applied", "Shipping Address Set".
- The state can be formed by just executing the events. You can go back in time by just running the events to a certain point. You get the exact state as it was then.
- In event sourcing, don't store the state, but the deltas. The state can be rebuilt from events. Storing structures are simple, just a long queue of events.
- Sometimes you need to do snapshots because if you use an application for years, the event collection can be very large.
- This resolves the epic customer request: I want it for yesterday. You can re-execute the events with a new feature added to add a feature "in the past".
- Fully OOP, expressive, has metaprogramming, can build DSLs with ease, tons of gems, great community.
- Eric Evans' "blue book", Domain Driven Design, quite old but good and easy to read.
- New book: "Implementing Domain Driven Design". From the Java world, easy to understand.
Know Your AngularJS Inside Out
Build Your Own AngularJS helps you understand everything there is to understand about AngularJS (1.x). By creating your very own implementation of AngularJS piece by piece, you gain deep insight into what makes this framework tick. Say goodbye to fixing problems by trial and error and hello to reasoning your way through them