We would like to share our experience regarding the way we design application and modelling domain. Let’s start from business of course. We try to understand what problems our customers have and how we can help. Understanding “why” is very important, so communication techniques like “impact mapping” can be very helpful. In this stage we always start to discover language of our customer… and that is extremely important as well.
Our sample application
Let’s say we are working with client in medical industry. After discussions, meetings and some planning session with customer we created backlog. Let’s say that we have to implement such user story which is very valuable for our customer:
As a receptionist in the clinic, I would like arrange a visit to a doctor without worrying about whether patient is insured so I should be able to view and check such information in the system instead of calling insurance company Presumptions and rules: - Patient who is not insured can not have free visits (except emergencies) - We can fetch information about insurance from national insurance database which is available for clinic
Illustrating using examples
Now we can illustrate our user story using examples. We can use gherkin format for that.
As you can see, we added context to user story using examples, and we prepared two scenarios which can be important from the customer point of view. We did it in the customer language, so he should understand our examples and should be able to verify our assumptions about his business. Using a common language with our clients highly improves our communication and common understanding with clients.
Modelling by Example
This is a great technique, we are already using it from some time.
We can use behat to build our model based on our examples.
Basically we just need install behat and run
to generate step code snippets in Context class.
We will start modelling from our “I am receptionist in the clinic” step.
In example we can see that we will need Clinic an Receptionist concepts in our application. We need to remember the big picture here as well. We suppose that not only Receptionists in Clinic will use the system. It is a good time to communicate with our customer. Let’s assume that Customer confirms that system should be used by all Clinic employees in the future, and we do not know yet how many employee types clinic can have - we just need some abstract Employee concept probably.
Ok so let’s start from Clinic concept. It can be something like
$clinic = new Clinic() right?
Wait a second… In our specific domain clinic cannot exists without information which are required by the law, like:
clinic name, clinic address, medical services provided by clinic, tax identification number and number from register of national economy.
How do we know? Again we fetch that knowledge from the Customer (or Domain expert).
We have all needed information, so we can start modelling by writing such code in our Context:
As you see, Clinic cannot be created without required information. We even want to create special classes for some of those information. We did it because of domain requirements we have - so for example Clinic should always have Address and this address should be valid.
We can pass address as string to Clinic object of course, but we need to add code to Clinic object constructor to make sure that address is valid. By providing new Address class we can be sure that invalid address will never exist in the system (cause Address class will care about it during creation in the constructor).
Ok, enough with theory.
We can run
vendor/bin/behat now… and we get such error:
PHP Fatal error: Class 'Cocoders\MedicalClinic\Clinic' not found in features/bootstrap/MedicalClinicContext.php on line 20
Detailed domain model specification by phpspec
Yeah we are having an error cause we just want use object in behat context which is not created yet.
This is an ideal time to start creating detailed specification for our Clinic object.
Most of the time we are using phpspec for that.
After installation of phpspec we can run
vendor/bin/phpspec desc “Cocoders\MedicalClinic\Clinic”.
It is a command which generates phpspec specification skeleton for our Clinic class.
Let’s modify that skeleton to be able to create instance of Clinic object.
After our changes, it should look like that:
vendor/bin/phpspec run generates production class draft for us.
Our job now is to make our code work according to the specification we just created.
Now we can run behat again and we see that we need to write pending definition for “I am receptionist in the clinic” step.
In this moment we can provide concept of Clinic Employee. We want to add any kind of employee to clinic, and we do not yet know how many sorts of employees clinic can have.
We can model it like that:
Again we will get an error when we run behat – hireEmployee method and Receptionist class do not exist.
Let’s create specification in
ClinicSpec.php for hireEmployee:
And production code created according to the specification in ‘Clinic.php`:
Of course now we can allow the Receptionist to be hired by Clinic using such code:
Such iterative modelling process works for us very well. There is a great everzet article about it as well if you haven’t read it yet, please do it now http://everzet.com/post/99045129766/introducing-modelling-by-example
If you want to see working examples please check our github repository
Such approach is very useful in our case when we are working with legacy code as well. It seems to be really helpful with discovering domain model in such projects. We can isolate some stuff from legacy code base by providing interfaces. We can rely on those interfaces in the new concept we are adding to existing project.