Sunday, May 26, 2013

Accidental entities - you don't need that identity

An entity is identified by an identifier, while value objects are identified by their value.

If I make a living renting cars to tourists, I might not care the least about the identity of the colors the cars came in. I just care about their value; Rosso Corsa, Azurro Metallic... If I repaint the car, the color changes, and the previous color is abandoned as a whole.
However, if I were a car paint manufacturer, I would care a great deal about the identity of a color. My first action might be to make up a marketable name for the color, something that I can identify it with - a la Burnt Sienna or Iceberg Blue. The color might have a certain structure from the get-go, but I might experiment with the structure along the way, while I'm still referring to it as the same color.

Imagine that I'm implementing a tool to manage the car rental's fleet, and that the CEO told me that color is one of the specifications that seems to matter a lot to their customers. The list of available colors is rather limited though; black, dark gray, and blue. Yet the CEO insists on managing this collection by herself; this should avoid having to call in another expensive consultant a few years down the road.

Color as an entity

So we define a collection of colors that will be persisted by NHibernate. Since NHibernate, and our relational database don't play nice without a primary key, we add an identifier to the colors.

We end up with two classes; one entity that defines a color, and another entity that defines a car. A car references a color.
public class Car
{
    public Car(Color color) 
    {
        if (color == null)
            throw new ArgumentNullException("color");

        Color = color;
    }

    protected Car() { }

    public virtual int Id { get; protected set; }

    public virtual Color Color { get; protected set; }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        var car = obj as Car;

        if (car == null)
            return false;

        return car.Id == Id;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

public class Color
{
    public Color(string name, string hexadecimalNotation)
    {
        if (string.IsNullOrEmpty(name))
            throw new ArgumentNullException("name");
        if (string.IsNullOrEmpty(hexadecimalNotation))
            throw new ArgumentNullException("hexadecimalNotation");

        Name = name;
        HexadecimalNotation = hexadecimalNotation;
    }

    protected Color() { }

    public virtual int Id { get; protected set; }

    public virtual string Name { get; protected set; }

    public virtual string HexadecimalNotation { get; protected set; }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        var color = obj as Color;

        if (color == null)
            return false;

        return color.Id == Id;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

public class CarClassMap : ClassMap<Car>
{
    public CarClassMap()
    {
        Id(x => x.Id).GeneratedBy.HiLo("10");

        References(x => x.Color);          
    }
}

public class ColorClassMap : ClassMap<Color>
{
    public ColorClassMap()
    {
        Id(x => x.Id).GeneratedBy.HiLo("10");

        Map(x => x.Name).Length(30).Not.Nullable();

        Map(x => x.HexadecimalNotation).Length(7).Not.Nullable();
    }
}
The generated schema looks like this.



And while this looks innocent at first, accidentally creating an entity raises a bunch of new concerns and questions. What happens if a color is no longer available, and the CEO wants to remove it from the collection? Does that mean we should delete all models that came in this color? No, those colors still exist, we're not going to repaint all the vehicles; those colors just aren't available anymore. This hints towards a concept that might be missing.

Fighting symptoms

We see the CEO heading over to the cafeteria, so we jump up, and ask her whether it makes sense for her to mark those colors as unavailable, instead of deleting them. After a short delay she shrugs and replies: "Well, I could do that if that makes things easier for you." We go ahead and model our solution to reflect this new information. 
public class Color
{
    public Color(string name, string hexadecimalNotation)
    {
        if (string.IsNullOrEmpty(name))
            throw new ArgumentNullException("name");
        if (string.IsNullOrEmpty(hexadecimalNotation))
            throw new ArgumentNullException("hexadecimalNotation");

        Name = name;
        HexadecimalNotation = hexadecimalNotation;
        Available = true;
    }

    protected Color() { }

    public virtual int Id { get; protected set; }

    public virtual string Name { get; protected set; }

    public virtual string HexadecimalNotation { get; protected set; }
    
    public virtual bool Available { get; protected set; }
    
    public virtual void MakeUnavailable() 
    {
        Available = false;
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        var color = obj as Color;

        if (color == null)
            return false;

        return color.Id == Id;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}
A few days later we show off what we came up with to the CEO. She looks content with what we built over the last few days, until we show her the user interface that manages the colors. "I'm rather busy so I often make mistakes when I take care of these administrative tasks, could you add a button to really delete a color from this list anyway?" This brings us back to square one. First thing we think about is soft deleting the colors. We could also only make it possible to remove a color if it hasn't been referenced yet. A voice in the back of our heads keeps telling us that we must be missing something though, and that this seems to be harder than it should be. A few hours later, driving home after a tough day, it becomes obvious that the CEO really thinks of a color as a value instead of an entity, so we should really be modeling it as such.

Color as a component

Luckily, NHibernate makes this pretty simple. The next day, we arrive early at the office, and change our mapping to use a component, so that instead of the car referencing a color, we store the value, and lose the id.
public class CarClassMap : ClassMap<Car>
{
    public CarClassMap()
    {
        Id(x => x.Id).GeneratedBy.HiLo("10");

        Component(
           x => x.Color,
           m =>
           {
               m.Map(x => x.Name).Column("ColorName").Length(30).Not.Nullable();
               m.Map(x => x.HexadecimalNotation).Column("ColorHex").Length(7).Not.Nullable();
           });
    }
}

The generated schema now looks like this; we're no longer referencing the Color table.



When we store a color now, it's an entity. But as soon as we put it on a car, it's a value object. When we pull the car back out of our persistence store, we have lost the identity. We should modify our code so that the color's behaviour reflects these changes. We modify the default constructor so that the object gets initialized with a default identifier. The default constructor will get used by NHibernate when it hydrates the object after getting it out the persistence store. We override the Equals and GetHashCode methods so that the identifiers are compared when there's an identity, but when the identifier isn't hydrated, the values are compared.
public class Color
{
    public Color(string name, string hexadecimalNotation)
    {
        if (string.IsNullOrEmpty(name))
            throw new ArgumentNullException("name");
        if (string.IsNullOrEmpty(hexadecimalNotation))
            throw new ArgumentNullException("hexadecimalNotation");

        Name = name;
        HexadecimalNotation = hexadecimalNotation;
    }

    protected Color() 
    {
        Id = -1;
    }

    public virtual int Id { get; protected set; }

    public virtual string Name { get; protected set; }

    public virtual string HexadecimalNotation { get; protected set; }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        var color = obj as Color;

        if (color == null)
            return false;

        if (Id != -1)
            return Id == color.Id;

        return Name == color.Name && HexadecimalNotation == color.HexadecimalNotation;
    }

    public override int GetHashCode()
    {
        if (Id != -1)
            return Id.GetHashCode();

        return Name.GetHashCode() & HexadecimalNotation.GetHashCode();
    }
}
This feels off though; using one concept in two different contexts makes things rather confusing. Is color an entity, or value object? Or does it depend?

Separate concepts

We extract two explicit concepts instead; a color as a value object, and an available color as an entity. 
public class AvailableColor 
{
    public AvailableColor(string name, string hexadecimalNotation)            
    {
        if (string.IsNullOrEmpty(name))
            throw new ArgumentNullException("name");
        if (string.IsNullOrEmpty(hexadecimalNotation))
            throw new ArgumentNullException("hexadecimalNotation");

        Name = name;
        HexadecimalNotation = hexadecimalNotation;
    }

    protected AvailableColor()
    {
    }

    public virtual int Id { get; protected set; }

    public virtual string Name { get; protected set; }

    public virtual string HexadecimalNotation { get; protected set; }

    public static explicit operator Color(AvailableColor value)
    {
        return new Color(value.Name, value.HexadecimalNotation);
    }  

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        var color = obj as AvailableColor;

        if (color == null)
            return false;

        return color.Id == Id;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

public class Color
{
    public Color(string name, string hexadecimalNotation)
    {
        if (string.IsNullOrEmpty(name))
            throw new ArgumentNullException("name");
        if (string.IsNullOrEmpty(hexadecimalNotation))
            throw new ArgumentNullException("hexadecimalNotation");

        Name = name;
        HexadecimalNotation = hexadecimalNotation;
    }

    protected Color()
    {
    }

    public virtual string Name { get; protected set; }

    public virtual string HexadecimalNotation { get; protected set; }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        var color = obj as Color;

        if (color == null)
            return false;

        return Name == color.Name && HexadecimalNotation == color.HexadecimalNotation;
    }

    public override int GetHashCode()
    {
        return Name.GetHashCode() & HexadecimalNotation.GetHashCode();
    }
}
This looks better. We now have two explicit concepts. An explicit conversion allows you to get a color out of an available color, losing the identifier.
var availableColorOrange = new AvailableColor("Orange", "#CC3232");
var car = new Car((Color)availableColorOrange);                    
                    
Console.WriteLine(car.Color.Equals(new Color("Orange", "#CC3232"))); // true
Conclusion

We meet up with the CEO one last time, and show her what we reworked. When we demo how she can manage the collection of available colors by just adding and deleting them - without caring whether one of the cars came in that color, a smile shows up on her face; "This is exactly what I needed, it really shouldn't be harder than this."

Tools often trick us into creating entities. These accidental entities then go on to introduce expensive coupling, introducing questions and problems that could easily be avoided by copying values around instead.

Does your codebase contain accidental entities?

Next week: but what about the UI?

Monday, May 20, 2013

Validating composite models with knockout validation

When you use knockout validation to extend observables with validation rules, it will add a few functions to these observables - the most important ones being; error and isValid. You can use these functions to verify if any of the validation rules were violated, and to extract an error message.

To extract all of the error messages out of a composite model, you can use a grouping function.
function BookingModel() {      
    var self = this;
   
    self.contact = new ContactModel();
    self.departure = new DepartureModel();
   
    self.isValid = function() {
        return self.contact.isValid() && self.departure.isValid();
    };
   
    self.validate = function() {                           
        if (!self.isValid()) {
            var errors = ko.validation.group(self);                           
            errors.showAllMessages();
        
            return false;          
        }

        return true;
    };                    
}

function DepartureModel() {
    this.street = ko.observable('').extend({ required: true });
    this.houseNumber = ko.observable('').extend({ required: true });
    this.city = ko.observable('').extend({ required: true });
    this.time = ko.observable('').extend({ required: true });            
    
    this.isValid = function() {
        return 
            this.street.isValid() &&
            this.houseNumber.isValid() &&
            this.city.isValid() &&
            this.time.isValid();                
    };
}

function ContactModel() {
    this.firstName = ko.observable('').extend({ required: true });
    this.lastName = ko.observable('').extend({ required: true });
    this.phoneNumber = this.firstName = ko.observable('').extend({ required: true });
    this.email = ko.observable('').extend({ required: true });   

    this.isValid = function() {
        return 
            this.firstName.isValid() &&
            this.lastName.isValid() &&
            this.phoneNumber.isValid() &&
            this.email.isValid();                
    };    
}

This is what my first attempt looked like. A little later I discovered that you can get rid of these boilerplate functions on the composite model by applying the validatedObservable function instead.
ko.applyBindings(ko.validatedObservable(new BookingModel()));

ko.validatedObservable = function (initialValue) {
    if (!exports.utils.isObject(initialValue)) { 
        return ko.observable(initialValue).extend({ validatable: true }); }

    var obsv = ko.observable(initialValue);
    obsv.errors = exports.group(initialValue);
    obsv.isValid = ko.computed(function () {
        return obsv.errors().length === 0;
    });

    return obsv;
};
The validatedObservable function will add an errors function to the composite model which traverses the object graph and validates each eligible property. The errors function also has a showAllMessages function that will display an error message next to each invalid element. The isValid function only asserts if there are any errors.
function BookingModel() {      
    var self = this;
    
    self.contact = new ContactModel();
    self.departure = new DepartureModel();

    self.validate = function() {                           
        if (!self.isValid()) {                                         
            self.errors.showAllMessages();
        
            return false;          
        }

        return true;
    };             
}   

function DepartureModel() {
    this.street = ko.observable('').extend({ required: true });
    this.houseNumber = ko.observable('').extend({ required: true });
    this.city = ko.observable('').extend({ required: true });
    this.time = ko.observable('').extend({ required: true });            
}

function ContactModel() {
    this.firstName = ko.observable('').extend({ required: true });
    this.lastName = ko.observable('').extend({ required: true });
    this.phoneNumber = this.firstName = ko.observable('').extend({ required: true });
    this.email = ko.observable('').extend({ required: true });        
}

Removing that cruft results in less bulky, cheaper models.

If you try this example, you will notice that the model appears to be valid even though the validation rules are clearly violated. It took me a few minutes of browsing the source to figure out why this was happening. When you use the group functions to validate your model, they will by default only look at first level properties. So if you have a composite model, you need to modify the grouping validation configuration, and set the deep property to true.
ko.validation.init({ grouping : { deep: true, observable: true } });

Sunday, May 12, 2013

IDDD Tour notes (2/2)

This is the second and last part of my notes I scribbled down attending the IDDD Tour. The first part was published last week.

A better model
Even if you come up with a better model, the fact that it has been the ubiquitous language of the domain for decades proves that it works for them.
This quote bothers me a bit. There definitely is truth to this, but modeling an existing process often presents such a great opportunity to revise and improve it. Naked models don't conceal deficiencies, inefficiencies and aberrations. Exploring alternative models free of habituation, politics and legacy is dirt cheap, while the outcome could considerably benefit all. It seems such a shame not to take advantage of this. As with most things, know when to pick your fights.

Elegance
Elegance is for dressing, not for delivering software.
This is one to remember; I'll be using this one next time someone uses elegance as an argument for gold plating.

Cultivating models
Models grow; you will never have the best model from the start. Improve them every time you pass by.
Your first attempt at it is hardly ever right. Don't beat yourself up over it. The best models are the result of multiple iterations.
In general I consider dwelling on one problem too long to be a waste of time. Settle for good enough, and allow the better solution to emerge by itself over time.
When I feel a design is mighty important, I might accelerate this process by iterating over it multiple times in just a few days; asking for constant feedback, carrying the problem with me everywhere I go, always challenging it, and molding it in different shapes until one sticks.

Reuse
Lots of people use a shared kernel just for reuse. It's often not worth it.
People are so obsessed with the DRY principle, and the dogma of avoiding duplication, it often does more harm than good. Nonexistent concepts are introduced just to spare a few duplicate lines of code, while they will hinder and complicate autonomous evolution.

REST and DDD
Don't expose your domain model over REST: expose use cases. 
You want to enable relentlessly evolving your domain model without breaking clients. In practice you would post intent-revealing command resources, while hypermedia guides you in navigating to subsequent commands.

Published language
How is the language agreed upon; over lunch or by a committee?
 A great question which reveals if a language should be really considered as published.

And that's the last of it. If you thought some of these were interesting, you should probably get the book. I finished Growing Object-Oriented Software Guided by Tests last week, so I finally get to read it myself after having it collect dust for two months.

Sunday, May 5, 2013

IDDD Tour notes (1/2)

Two weeks ago I got to spend four days attending the IDDD Tour by Vaughn Vernon. Although my book queue has only allowed me to shallowly browse the book, I had high hopes for this course. I anticipated a week of getting lectured on DDD with a few practical exercises, but was blown away by the openness and interaction promoted by Vaughn and his associate Alberto Brandolini. A passionate group, engaging workshops, long days and lots of sharing made these few days exceptionally satisfying and inspirational. I'm grateful to those who got this show on the road; it was more than worth your trouble.

Over these few days I scribbled down some things I thought were worth remembering or worth some more thought. Most of these are aimed at the strategic side of DDD and the softer side of software since that's where I acquired most new insights.

Complexity
If we really understood the complexity of a system, we would very often make different decisions from when designing new systems. 
Understanding the complexity of a new system is hard. Modeling can serve as the perfect tool to help you expose the hidden complexities as early as possible.
Often a system appears to be not much more than CRUD, to quickly evolve into something with a lot more behaviour than anticipated. Make sure you don't sabotage growing your design by picking an architecture or framework that doesn't allow you to.
I often start with just exposing commands and queries to my application, which encapsulate all domain logic. Behind these command- and queryhandlers is very little abstraction, just some basic building blocks; aggregates, entities and value objects. Later on I can relentlessly refactor everything behind these commands and queries without breaking application code: introduce domain services, events, separate the write- from the read model etc...

Change
How do you bring in DDD? Gather a small cluster of motivated silent people and work on a project that has lots of potential value.
This is my recipe for change as well. Find a few like-minded people that are confident drawing outside the lines set out by the status quo, work in the shades, working your way towards the light.

Brown
There is always brown, even when it's under the green. 
Every application has parts which are less pretty, even green fields; use proper encapsulation to contain them, and avoid them corrupting other parts of the system.

 Another brick in the wall
Break down that paper wall between domain experts and developers. Learn the favorite coffee of the domain expert.
Lots of organizations still build this paper wall between domain experts and developers. But paper doesn't answer to questions, nor does it carry nuances very well. Communicating on a more personal level is key to tearing down that wall. Breaking the ice can be as easy as treating your domain expert to coffee.

One language
Which language do you use when naming things in code? Yours. 
I don't think native English speakers understand just how awkward it is to write code in something other than English. Keywords, API's, documentation... it's all in English. I feel that putting these together with your own language results in a cacophony of words.
In my current project the business is bilingual; they use Dutch and French names for the same concept interchangeably. We tried to find middle ground by introducing English names, and have a map between these languages. Ideally there would only be one language though.
Someone mentioned that they use English for all globally unambiguous concepts such as account number, name... but use their mother tongue in scenarios where nuances would be lost in translation. This seems to be an attractive compromise.

Defining a bounded context
A bounded context is where one ubiquitous language is consistent.
This is by far the simplest definition of a bounded context.

Bounded context relations
You say please, so I am upstream.
The relationship between bounded contexts is expressed by saying one is upstream or downstream. I thought of the quote above to be a creative expression that can aid in explaining these two concepts.

Rewrites
When you rewrite an application, you have to look at the existing forces in an organization; chances are the previous team wasn't terrible either.
Tons of factors influence the outcome of a project; it's not just about teams and their skillset. Some forces in an organization can make it close to impossible to ship good software; fear of change, lack of vision, bone-dry information streams... So don't assume your rewrite will fix everything.

Surprise
Adding surprise value is often not that valuable.
This seems to be related to the mantra of 'good enough'. Sometimes we - with the best intentions - invest more time and money in solving a problem in the best possible way, than it will ever return.

These were some notes I wrote down the first two days. I'll try to go through the other half over these next few days. I hope you found some of them valuable too.