Skip to content

FrOSCon - Unbreakable Domain Models

Mathias Varreas Mathias is helping teams escaping from survival mode. Cofounder of DDDBE Domain driven design Introduces me with a great upcomming term called "modelstorm". He also told me that a friend of him is writing on a paper about "modelstorm" so i'm looking forward to find more informations about that term on the web.

What Is This Talk About

  • Where to put business logic?
  • How to protect our code from abuse?
  • Where to put queries, and how test them?

Defining Terms

  • Domain is a problem space (let customers buy more)
  • Domain model is solution space

Domain Model

  • contains data model - the models state
  • protect your invariants (example: a customer must always have a email address)
    • create unittest with something like assertTrue($customer->hasValidEmail())
  • a less to abuse model is harder to break
    • like adding it to the constructor
  • use objects as consistency boundaries
    • "if i give you this object, you don't have to take care if it is valid and contains consistence data"
  • make the implicit the explicit
    • "a user must have a valid email address"
    • keep in mind, if you can add an "and" to describe a method, the method is doing to much
  • do not violate single responsibility principle
    • for the example, create email class
  • try to encapsulate state and behavior with (simple) value objects

Customer business process is: "A customer orders products and pays for them.".

  • try to encapsulate operations

  • use objects as consistency boundaries
    • "if i give you this object, you don't have to take care if it is valid and contains consistence data"
  • make the implicit the explicit
    • "a user must have a valid email address"
    • keep in mind, if you can add an "and" to describe a method, the method is doing to much
  • do not violate single responsibility principle
    • for the example, create email class
  • try to encapsulate state and behavior with (simple) value objects
  • Customer business process is: "A customer orders products and pays for them.".

    • try to encapsulate operations

    Customer business process is: "Order three times to become a premium member.".

    • try to create specification

      !php CustomerIsPremium::public function isSatisfiedBy(Customer $customer)

    Customer business process is: "Different rules apply for different tenants.".

    • use specifications to encapsulate rules about object selection

    Customer business process is: "Get a list of all premium customers.".

    • for big collections, try to duplicate the logic in the database (even if it breaks the single response philosophy)
    • test it by comparing (different implementation) object model code with database logic code in the unittest

    How To Persit A Model

    • implemented by a storage manager
    • special or generic storage manager has a save/add and delete/remove method

    Modelstorm

    The idea behind modelstorm (if i get it correctly) can be told as "a room of people, a bunch of magic markers, an area where you can write on". Prepare a wall with white papers. Each person can have an own marker with its own color. Each person is allowed to write on the paper. Then you start writing/creating the models. Add lines with actions to display process that handles different domain stages.

    tool.bazzline.net - the long road to a php data mapper - part 1

    I am working on the private project "tool.bazzline.net" to get away from social services and have a tool that fits perfectly to my own requirement. Private projects always (should ;-)) have the benefit of "no time preasure" that leads to "implement some cool features". The first thing on this feature list is a data mapper.

    Why a datamapper? Well, won't you like to work with domain models and don't give a s*** about how and where the data is stored? There is a wonderfull and short article created by Martin Fowler and i just have to recomend this one. I found two datamapper projects for php on the web, pdodatamapper and phpdatamapper. To keep things short, a data mapper removes the logic of "how and where" to store the model data. Both projects are still under heavy development and are not in a final state right now. I will not use them (but always take a look on how they have things done).

    So what should my data mapper do? All in all, it should hide all the database tables from the developer - even the orm if used. I just want to create a domain model and use it to store and get data from a persistent storage. My data mapper must be smart enough to figure out which rowset on which storage/database table he has to update (or create). The data mapper should have a lazy loading/storing mechanism, this should be done by a propertieset that knows which propertie is stored on which storage/database table. My data mapper should support a very simple/limited filter mechanism that prevents me to blow up my data mapper class with to many "loadModelWhenItFitsToTheFollowingCircumstances"-methods. This data mapper should also support to create a domain model by the upper called filter mechanism.

    I decided that the general data mapper methods "insert()", "update" and "delete" are not perfect in the matter of sense to fit on my requirements. Thats why this data mapper will have the methods "load($model, $filters)", "save($model)" and "delete($model)". You can adapt each data mapper by adding own load methods with pre defined filters.

    Filter what? All this filtering leads to a filter class. This is a simple and straight forward one with the properties "criteria", "name" and "value". The filter class has to be independent from the real storage implementation, thats why i will use an aditional filterMapper class. This filterMapper is used from the data mapper and prevents to write doublicated storage dependent code. He is responsible to transform the general filterset to the a storage dependant model - means you throw the filter and the storage model inside and get the storage model with added storageFilter back. That filter and filterMapper can communicate with each other by using a criteria class. The criteria class will define what "like" or "greater then" is so that the filterMapper can map this to the storage model.

    After the trip to the filtering adventure, we are back to the data mapper itself. The real domainModelDataMapper will use a general propertieSet class. This propertieSet class is the only real connection between the domainModelProperties and the (maybe more the one) storage models - so the theorie currently ;-). I must admit, i have made no decision if the real domainModelDataMapper is a decorator of the dataMapper, or if the dataMapper class is implemented as abstract class. Since the whole project is a "learning by doing", i will figure out what will work - final in the phase of implementation (have i remarked that i never ever have worked with a data mapper for real? ;-) ). Lets see what is next.