January 2, 2010 DDD 6 comments
January 2, 2010 DDD 6 comments
Lets start with the following question: Where is a car on the left or on the right?
You would probably say that Car is on the Right, and you are correct. But hold on. What is the difference between them? Difference is that Car is not just a huge collection of parts. Car is not even a collection of parts which need to fit together, but a car is much more than that. A good Car starts with vision and carefully written specifications, and it continues with design and with testing. The design is modified based on the testing results. Only after that each part could be assembled together.
Software development is similar, we cannot just sit down and type code.
What is Domain-Driven Design?
We all want to develop our applications, but business requirements nowadays are huge, and we dive in that complexity. And we can get stuck will all of that, because the whole complexity is in the Domain. For example banking system. Do you as a software developer want to know how does it work? Probably no, but you still need to develop your system. The guy from bank stands near you and and he wants you to develop application for him. What is your starting point? Is it table in database or is it Model?
Domain-Driven Design (DDD) is is an approach to the design of software, based on the two premises:
* that complex domain designs should be based on a model, and
* that for most software projects, the primary focus should be on the domain and domain logic (as opposed to the particular technology used to implement the system).
In other words the heart of the DDD is Model and you start developing your application with drawing your model. Model and design you create should shape each other. Model should represent knowledge to the business and it is language your team speak.
To be able effectively design you should build your Model and implementation together in the same time, cultivating a language based on the Model. You should represent knowledge in your Model and continuously distill it. You could do refactoring to it doing brainstorming and experimenting.
Ubiquitous Language
So, imagine that guy from bank, say Domain Expert, stands near you and you start talking. How does that conversion look like? It could be fractured and this creates serious problems to your project. Domain Experts have their own jargon and the development team has its own. After that daily discussions are disconnected from the terminology embedded into code. So effect of need to translate what you are talking about into code appears, plus misunderstandings possibilities. This all could lead to not good results.
Need for some common language shows up. Eric Evans calls this language as Ubiquitous Language. Your language is your model, this means that both Domain Experts and Developers should talk the same language which is build on the model. And changes to the Ubiquitous Language means changes to the Model. If Experts start using new terms this should be represented in your model, in your code, diagrams and speech.
How could it look?
* Speech (This means daily conversations between team members.)
* Diagrams (Often these are quick diagrams on the whiteboard, which you created with your Experts.)
* Writing (This could be NOT long documents, describing the Model.)
* UML (But there is no place for cumbersome one.)
Let us move to the way you will build your application.
Layered Architecture
I hope that everybody heard about the Layered Architecture. For the DDD it is very important since we explicitly separate Domain Level, which lives between our Infrastructure and Application layers, like on picture. Note, that isolating of your Domain Level is very important.
User Interface (Presentation Layer)
Responsible for presenting information to the user and interpreting user commands.
Application Layer
This is a thin layer which coordinates the application activity. It does not contain business logic. It does not hold the state of the business objects, but it can hold the state of an application task progress.
Domain Layer
This layer contains information about the domain. This is the heart of the business software. The state of business objects is held here. Persistence of the business objects and possibly their state is delegated to the infrastructure layer.
Infrastructure Layer
This layer acts as a supporting library for all the other layers. It provides communication between layers, implements persistence for business objects, contains supporting libraries for the user interface layer, etc.
For example, a typical, the interaction of the application, domain and infrastructure could look like this. The user wants to book a flights route, and asks an application service in the application layer to do so. The application tier fetches the relevant domain objects from the infrastructure and invokes relevant methods on them, e g to check security margins to other already booked flights. Once the domain objects have made all checks and updated their status to “decided”, the application service persists the objects to the infrastructure.
The Smart UI “Anti-Pattern”
All this sounds good but simplicity of just calling infrastructure lead into temptation, and after that you see that code generated on button press actually executes hard-coded SQL, less terrible it could be when that is masked under some “helper” classes. But that all is manifestation of the the Smart UI “Anti-Pattern”. Could be surprising to you, but it has its advantages/disadvantages. Why not. It will not be a “Anti-Pattern” if it has no advantages.
Advantages:
Looks like a lot of advantages, but let see what are disadvantages. Hope this will convince you to do not use this “Anti-Pattern”.
Disadvantages:
So, don’t lose your mind, if you build your application with layers, do it correctly!
Building blocks of Domain-Driven Design
Eric Evans introduces terminology to the Domain-Driven Design. Accordingly to him there are such building blocks of the DDD: Associations, Entities, Value Objects, Services, Modules (which are parts of the Model) and Aggregates, Repositories, Factories (which deal with Life Cycle of a Domain Object).We will talk about each of the elements.
Associations
If your Car has four tires this is association of the model of your Car. This is relation between business elements you work with.
Entities
If we were to implement the concept of a Person using a software program, we would probably create a Person class with a series of attributes: name, date of birth, place of birth, etc. For example if you create Patient entity in code it will be represented like Patient class. It is required that for medical system to identify if the patient is the same. Is the patient “Andriy Buday” physician deals with, the same as “Andriy Buday” nurse has a scheduled procedure? So basically Entity is object that has Attributes and Identity.
Value Objects
Value Object are similar to the Entities expect that they do not need Identity, which is required for Entity. For example “Ukraine, Lviv” which is Address is Value object since we do not need identity for it. We could have 300 patients in Lviv (Entities) who could share the same address. This (sharing) could even be done thought the code using Flyweight design pattern to reduce memory needs. But Address is not always Value Object. This depends on “Who is asking?”. For the post system Address could be an Entity.
Services
Consider that your Model has nouns and verbs (they are used in Ubiquitous Language). You could imagine that nouns are Entities and Value Objects. Your verbs are Services. If you have action or operation related to the Domain concept, but is not natural part of any of your Entity or Value Object you could move it into separate item, which is called Service. Interface of your Service should operate with terms of of the domain model. And the operations it does are stateless.
Modules
For a large and complex application, the model tends to grow bigger and bigger. The model reaches a point where it is hard to talk about as a whole, and understanding the relationships and interactions between different parts becomes difficult. For that reason, it is necessary to organize the model into modules. Modules are used as a method of organizing related concepts and tasks in order to reduce complexity. In code this could be packages or namespaces or even simple folders. The advantage of this is that when you place some classes together in a Module, you are telling the next developer who looks at your design to think about them together.
Aggregates
An Aggregate is a group of associated objects which are considered as one unit with regard to data changes. The Aggregate is demarcated by a boundary which separates the objects inside from those outside. Each Aggregate has one Root. The Root is an Entity, and it is the only object accessible from outside.
The picture shows that your Customer code could access Tire only though the Car instance and there is no other way to do that, since Car is Aggregate to Tire. But could be that part of Car need identity. This could be Engine of your Car, since it has its number and you need to form you taxes. In this case Engine is Entity which lives outside of your Aggregate.
We need to deal with Aggregates since they has direct relation to the Life Cycle of Domain Object.
Factories
Creation of an object can be a major operation in itself, but complex assembly operations do not fit the responsibility of the created objects. This operations could be accomplished with Factories. But not always it should be separate object. In scope of DDD Factory could even be a simple constructor. Two major requirements to the Factory are: Atomicity – this means that operation of creating an Entity should also create whole Aggregate associated with it. Abstracted to the type desired – this means that Factories should return you types rater than concrete classes. (i.e. Interfaces).
Repositories
Repository is an object which provide you CRUD operations to your Aggregates.
Repositories have many advantages, including the following:
To be more clear how the Client code, Repository and Factory are interacting between each other. Lets take a look on the next sequence diagram:
I hope that diagram is self-descriptive.
Refactoring Toward Deeper Insight
Since the business and its rules are very complicated you are not able to see whole picture at once. If there are some incomes to your Ubiquitous Language you should represent this into your Model. You do this with refactoring of existing code in way that brings key concepts into light.
There are three ways to bring concepts into light:
Your development process should always be in continuous refactoring. Any changes to the matter you talk with your Experts should be immediately represented in code. If you see that some term starts occur too often just create an Entity or Service for it – bring it to the Light.
Preserving Model Integrity
Imagine a big enterprise project. Could you imagine it with one model which is understandable for whole team, say 200 people? Most commonly such big projects are divided to smaller teams and which of them works on own model. So whole project consists of couple of models and some of them are intersected with other models, some of them uses other models and all of this is the Integrity of your Models.
Bounded Context
Each model has a context. When we deal with single model, the context is implicit. There is no need to define it. When we create an application which is supposed to interact with other software, for example a legacy application, it is clear that old application has its own model and context, and they are separated from the legacy model and its context. They cannot be combined, mixed or confused. When we work on enterprise project we need define the context of each model, we create. Also a model should be small enough to be assigned to one team. Only this way we could keep knowledge up to date and integrated into system.
Whole project should be assembled continuously using Continuous Integration.
Iterations between different contexts
You could probably say that you cannot have 100 models in your project without intersections between them. And you are right. Eric Evans sees few variants of such intersections.
Shared Kernel
The purpose of shared kernel is to reduce duplication, but still keep two separate contexts. Designate some subset of the domain model that the two teams agree to share. Of course this includes, along with this subset of the model, the subset of code or of the database design associated with that part of the model. This explicitly shared stuff has special status, and shouldn’t be changed without consultation with the other team.
Customer-Supplier
There are times when two subsystems have a special relationship: one depends a lot on the other. You could imagine core functionality system and reporting system. Probably reporting system depends on the core one. In such case it is very and very important that team which works on core will be supplying reporting team. That is simply needed.
Conformist
This is much like the Shared Kernel, but there is an important difference. The customer team cannot make changes to the kernel. They can only use it as part of their model, and they can build on the existing code provided.
Anticorruption Layer
We should build an Anticorruption Layer which stands between our client model and the external one. This layer works as a two way translator between two domains and languages. This layer could be needed when we deal with legacy/external model and have no ability to do changes to it.
Open Host Service
The solution is to see the external subsystem as a provider of services. If we can wrap a set of Services around it, then all the other subsystems will access these Services, and we won’t need any translation layer. The difficulty is that each subsystem may need to interact in a specific way with the external subsystem, and to create a coherent set of Services may be problematic.
Infrastructure
Persistence Ignorance
One of the key requirements to your Infrastructure to be able deal with DDD is Persistence Ignorance. This means that once you have your Infrastructure setuped you no longer need to care about how your data goes to database and how it is saved there. Also it is commonly used with Unit Of Work Pattern. This could be accomplished with some of the ORM frameworks like Hibernate.
How do we classify ORMs? We look on the ways how it solves different problems which occur when you map you object-oriented data to relational database, but yea.. there are ORMs which map to the Object databases. But the most common variant is when you have Relational database. So wee take a look how ORM resolves Inheritance issues, what is the querying language of it, does it support all common databases operations like aggregating, ordering, grouping, etc.
Basically all ORMs has Identity Map and Cache strategy they allow us work using Unit Of Work pattern and they could provide Lazy Load to do not hit database often.
NHibernate is the ORM which all the features required to quickly build an advanced persistence layer in your code.
Patterns and practices compatible with Domain-Driven Design
Nowadays Agile is a way to develop software and DDD is very comfortable with it and with technics of the Agile like TDD.
TDD
Test-Driven Design is very good thing to use with DDD. Why? Because writing test before means that your are describing your model just like it was described on the meeting with your Experts. There are even enthusiasts who wants to rename TDD to BDD (Behavioral-Driven Design).
Advantages for design
Other advantages
Disadvantages
Designing architecture
While designing your architecture with DDD you often uses such patterns or approaches like:
SOA (Service-oriented architecture)
Generally speaking, SOA is a flexible set of design principles used during the phases of systems development and integration. It provides set of Services with which you are working.
AOP (Aspect-oriented programming)
In computing, aspect-oriented programming (AOP) is a programming paradigm in which secondary or supporting functions are isolated from the main program’s business logic. It aims to increase modularity by allowing the separation of cross-cutting concerns, forming a basis for aspect-oriented software development.
IoC (Inversion of Control and Dependency Injection)
Inversion of Control is principle with which you could easily resolve your dependencies in code delegating setup to some other part like IoC framework (StructureMap for example).
For the end I want to mention that my story is based on books by the link below.
http://domaindrivendesign.org/books
I read all of them (except of duplicated ones :) ) and recommend you to read them also. This will bring a lot of interested stuff to your mind. For example I could state that now I understand better the design of subsystem with which I work on enterprise project. Future is for Domain-Driven Design.
P.S. I hope that you enjoyed my story. Do not hesitate to leave your comments.
January 2, 2010 Book Reviews No comments
January 1, 2010 Success, YearPlanReport 3 comments
Right now is the first time in this year when I opened google reader and found one interesting post Where Do You Want to Be In a Year? by Tim Barcz. When I read it I realized that I had read book The 7 Habits of Highly Effective People also.
In general all books on Success says that you need to “Begin with the end in mind“, this means that you must have your plan.
At first you need to find out you goal for whole life. That is your target and main thing you need to get. Then you need to do breakdown of tasks you need to accomplish in your life, having them in few levels of term scope like 10 years term, 5 years term and 1 year term… and so on. So question:
My answer:
By the end of 2010 I want:
1. Get Microsoft Certification:
* MCTS (Exams: 70-536 and 70-505)
* MCPD 70-563 and 70-565 (this one is big fish, but I need such!)
2. Read at least 24 books.
3. Become known employee in my company, sharing knowledge and doing presentations, so will have much more authority among co-workers.
4. Familiarize with Java and contribute research and development work to Kohonen Maps world.
5. to be Senior Developer and continue growing…
6. Improve my English skills to have at least upper-intermediate strong level (according to my company graduating)
7. Gather good capital and looking for investments of money.
Write down your answer in comments or give me link to your blog!
December 29, 2009 UnitTesting No comments
Few days ago I did refactoring and as I’m quite sure that we have good coverage I checked-in my code after all tests passed.
But today QA from my team stated that he/she cannot save new Customer. I dived into log files and found that exception occured on SaveCustomer method.
Ok, I moved to the appropriate UT. (Note: it passes ok.) Which looked like:
//now we fetch customer from database requesting with the ID of just saved customer
fetchedCustomer = CustomerRepository.FetchCustomer(savedCustomer.ID);
//if fetched customer is not null we are ok!
Assert.That( fetchedCustomer, Is.Not.Null );
}
catch
{
//do nothing here….
}
finally
{
if ( fetchedCustomer != null )
{
//we want to leave our database clear after test run
CustomerRepository.Delete( fetchedCustomer );
}
}
}
This Unit Test will be succeded anyway, because
Assert.That(fetchedCustomer, Is.Not.Null) and similar asserts generates AssertionException.
Honestly I’m not aware why there was that catch{} piece, but anyway you could put there two catch blocks if it is really needed – one specific for the AssertionException and another for all cases of our life.
When you write your Unit Test you need to see it in both states – first
in failure and then in success. After that you can allow yourself
commit that code.
Main idea is:
December 27, 2009 SVN No comments
December 23, 2009 NHibernate No comments
Next SQL, which verifies if customer row exists in database:
Will be generated with next NHibernate Query:
return result.HasValue;
}
Please note, that you could use not only primary key, but any other property in your where condition.
December 22, 2009 .NET, Regex No comments
This is just another quick example of Regex pattern.
Next pattern matches “at least one symbol which is letter or digit at the begging and then exactly one delimiter ‘|’ and then at least one symbol which is letter or digit in the end“:
Valid is:
Not valid are:
and so on…
Links I’ve used:
Verify your Regex:
http://www.pagecolumn.com/tool/regtest.htm
Cheat Sheet:
http://www.addedbytes.com/download/regular-expressions-cheat-sheet-v2/pdf/
December 22, 2009 CodeReview 2 comments
Sometimes it is hard to convince that catch(…) is not so good!
Today I provided code review to one of my colleague and he was totally sure the he need try{/*code*/}catch(){} in few places.
First looked like:
I rewrote code to:
Then I spent few minutes to convince him that this code is ok and that this is not good to have catch for everything.
Another code looked like:
Now I tried to explain that FirstOrDefault() returns us either first element of collection OR null, so if we got null we just need to do some another stuff,
but if some exception will occur we should allow it fly out OR write some specific catch for exceptions that could be thrown. Code which I propose looks like:
After conversation we decided that try(/*code*/)catch() is not so good.
December 21, 2009 UnitTesting No comments
Have you ever faced with UT that failed once and then you always see it succeeded?
One of such tests could be test where you verify that date properties of some newly created entity are equal if they take DateTime.Now for that.
Today Hudson showed me that some test failed in project I worked near half a year ago, so test looked like:
Test failed because time difference between dates was greater than few milliseconds. This could occur when processor is too occupied.
So I changed assert call to more realistic:
December 9, 2009 NHibernate 4 comments
Sometime ago I faced with NHibernate issue and spent much time on figuring out how to resolve it. Issue was with saving complicated entity.
Error:
With NHibernate Profiler I found that this fails on the next SQL:
With better look you will see that there two times RESOURCE_ID mentioned so this looks like wrong mapping. But I was sure that everything is ok there.
This two References are wrong.
At first glance do you see why? At that moment I was not able also.
References(x => x.ResourceRole)
.Access.AsCamelCaseField(Prefix.Underscore)
.WithColumns(“RESOURCE_ROLE_ID”, “RESOURCE_ID”)
.FetchType.Join();
Here Resource has key (RESOURCE_ID).
ResourceRole has composite key (ROLE_ID and RESOURCE_ID).
After long searching and many tries I found why mapping is not correct. Even have my explanation for it.
When we reference ResourceRole we already use RESOURCE_ID field, so when we setup Resource and say “Hey, there is one more RESOURCE_ID“, then NHibernate cannot find out how to update all this correctly.
Solution:
insert=”false” update=”false” attributes for one of references solves the issue.
In Fluent NHibernate it looks like: