Ubiquitous Language, Tiny Types and Responsibility

As a consultant I have to log my hours in a timesheet application. This could be a test inside the timesheet app:

 [TestFixture]
    public class BillableTimeTest
    {
        [Test]
        public void ShouldhaveCorrectNumberOfWorkedHours()
        {
            var beerOClock = 17;
            var earlyInTheMorning = 9;
            var workDay = new BillableTime(earlyInTheMorning, beerOClock);
            Assert.That(workDay.Hours, Is.EqualTo(8));
        }

        [Test]
        public void ShouldRejectNonBusinessHours()
        {
            var afterHours = 23;
            var earlyInTheMorning = 9;
            Assert.Throws<ArgumentException>(() => new BillableTime(earlyInTheMorning, afterHours));
        }
    }

Given the test above it looks that in this system you can only log billable hours if they between 9a.m. and 5p.m. The implementation of the BillableTime object could be something like this:

    public class BillableTime
    {
        private readonly int _from;
        private readonly int _to;

        public BillableTime(int from, int to)
        {
            ValidateTimePeriod(from, to);
            _from = from;
            _to = to;
        }

        private void ValidateTimePeriod(int from, int to)
        {
            if (from < 9 || to > 17) throw new ArgumentException("BillableTime only accepts business hours (9am-5pm)");
        }

        public int Hours { get { return _to - _from; } }
    }

Let’s move on. If the BillableTime object is used to log only office hours we will probably have an object that represents overtime. Here is the test for our Overtime object:

    [TestFixture]
    public class OvertimeTest
    {
        [Test]
        public void ShouldhaveCorrectNumberOfWorkedHours()
        {
            var beerOClock = 17;
            var wayTooLate = 22;
            var workDay = new Overtime(beerOClock, wayTooLate);
            Assert.That(workDay.Hours, Is.EqualTo(5));
        }

        [Test]
        public void ShouldRejectIfNotInOVertimePeriod()
        {
            var afterHours = 23;
            var earlyInTheMorning = 9;
            Assert.Throws<ArgumentException>(() => new Overtime(earlyInTheMorning, afterHours));
        }
    }

You may have guessed that Overtime is implemented as something like this:

    public class Overtime
    {
        private readonly int _from;
        private readonly int _to;

        public Overtime(int from, int to)
        {
            ValidateTimePeriod(from, to);
            _from = from;
            _to = to;
        }

        private void ValidateTimePeriod(int from, int to)
        {
            if (from < 17 ) throw new ArgumentException("OvertimeTime only starts after 5pm");
        }

        public int Hours { get { return _to - _from; } }
    }

Code like the examples above is pretty common but there is a problem in there. Right now a BillableTime represents a period of time in which someone was working AND controls what constitutes “business hours”. The overtime object represents a period of time in which someone did some work after ours AND define what “after hours” means. When you can’t describe an object’s responsibilities without using and there is a chance that your model has something wrong in it.

In an Object-Oriented system it is generally a bad idea to have the implementation of a concept spread across multiple places. In a language like C# the best thing to do is often to have this implemented in its own class:

 [TestFixture]
    public class TimeIntervalTest
    {
        [Test]
        public void ShouldBeBusinessHoursIfBetween9AmAnd5Pm()
        {
            var beerOClock = 17;
            var earlyInTheMorning = 9;
            var businessHoursInterval = new TimeInterval(earlyInTheMorning, beerOClock);
            Assert.That(businessHoursInterval.Kind, Is.EqualTo(TimeInterval.Kinds.BusinessHours));
        }

        [Test]
        public void ShouldBeOvertimeIfAfter5Pm()
        {
            var beerOClock = 17;
            var wayTooLate = 22;
            var businessHoursInterval = new TimeInterval(beerOClock, wayTooLate);
            Assert.That(businessHoursInterval.Kind, Is.EqualTo(TimeInterval.Kinds.AfterHours));
        }

        [Test]
        public void ShouldHaveCorrectNumberofHours()
        {
            var startingTime = 9;
            var oneHourAfter = 10;
            var businessHoursInterval = new TimeInterval(startingTime, oneHourAfter);
            Assert.That(businessHoursInterval.Hours, Is.EqualTo(1));
        }

    }

    public class TimeInterval
    {
        private readonly int _from;
        private readonly int _to;
        private readonly Kinds _kind;

        public TimeInterval(int from, int to)
        {
            _from = from;
            _to = to;

            if (from >= 9 && to <= 17)
                _kind = Kinds.BusinessHours;
            else
            {
             _kind = Kinds.AfterHours;
            }
        }

        public enum Kinds { AfterHours, BusinessHours }

        public Kinds Kind
        {
            get { return _kind; }
        }

        public int Hours { get { return _to - _from; } }
    }

You can get fancy and create multiple types but this implementation is probably enough for this example. Now we have a class representing the time interval. Notice that this concept was present in our domain since the very beginning; we just didn’t have it explicitly.

But why would explicitly make anything better? Suppose that you are working on this code base and suddenly you need to change something. Say that your company decided that counting hours is not acceptable and that they want to track everything as minutes.

In the first example you would have to change both Overtime and BillableTime classes as they share the implementation of the concept. In the second example you would have to change only the class that actually represents the concept.

But even to realize which classes you would have to change it would take possibly hours in searching through the code base and tests to figure out all the places that implement time interval related logic. Something that for the business is very simple –as the business considers time interval to be a “strong concept”- would take ages to be implemented, possibly frustrating your stakeholders.

I like Eric Evans’ take on these situations. In his classical Domain Driven Design book he says:

[…]A deep model has power because it contains the central concepts and abstractions that can succinctly and flexibly express essential knowledge of the users’ activities, their problems, and their solutions. The first step is to somehow represent the essential concepts of the domain in the model. Refinement comes later, after successive iterations of knowledge crunching and refactoring. But this process really gets into gear when an important concept is recognized and made explicit in the model and design.
Many transformations of domain models and the corresponding code happen when developers recognize a concept that has been hinted at in discussion or present implicitly in the design, and they then represent it explicitly in the model with one or more objects or relationships.
Occasionally, this transformation of a formerly implicit concept into an explicit one is a breakthrough that leads to a deep model. More often, though, the breakthrough comes later, after a number of important concepts are explicit in the model; after successive refactorings have tweaked their responsibilities repeatedly, changed their relationships with other objects, and even changed their names a few times. Everything finally snaps into focus. But the process starts with recognizing the implied concepts in some form, however crude.
[…]
Listen to the language the domain experts use. Are there terms that succinctly state something complicated? Are they correcting your word choice (perhaps diplomatically)? Do the puzzled looks on their faces go away when you use a particular phrase? These are hints of a concept that might benefit the model.

The example was extremely simple but it’s not that different from real-world situations. What I’ve found in many projects is that people use things like metadata-based validators to hide business logic. Here is an example using NHibernate Validator:

 public class Contract
    {
        private int _lengthInYears;

        [Range(Min=1, Max = 3)]
        public int length
        {
            get { return _lengthInYears; }
            set { _lengthInYears = value; }
        }
    }

I think those validator frameworks can really help in many situations but when I look at the code above I can’t get some very important concepts. The method tells me it accepts an integer (and that means a lot of numbers, including negatives), but then it rejects most of them. In this case wouldn’t it be better if we explicitly say what we accept?

public class Contract
    {
        public Years length { get; set; }
    }

    public class Years
    {
        public int NumberOf { get; set; }

        public Years(int numberOf)
        {
            NumberOf = numberOf;
            if (numberOf < 1 || numberOf > 3)
                throw new ArgumentException();
        }
    }

It is quite clear that this also adds a lot of noise as you have to wrap and unwrap integers into Years. I am not saying that you must validate all your integers, strings and the like every time. What I am trying to say is that whenever you have this kind of logic in a validator or something else it is very likely that the use of metadata is actually hiding information about an important domain concept. I’d rather have it explicit in my code base than hidden in some metadata.

And this gets us into theTiny Types (or Micro Types) idea. I like the concept and I use it when it makes my domain more explicit. What really bugs me is when I see something like:

    public class User
    {
        Name name { get; set; }
        //other stuff
    }

    public class Name
    {
        public string Value { get; set; }

        public Name(string value)
        {
            Value = value;
        }
    }

The tiny types in the example below not only are often not relevant to the Ubiquitous Language –I don’t think I ever worked in a system where name wasn’t a string… any string!- but also most languages (C#, Java, Ruby…) make it so bureaucratic to create and maintain those little types that in the end you waste a lot of effort doing something that is not relevant at all.

It is a wonderful thing to make your domain concepts explicit using types. Just make sure you don’t overdo it, it’s not worth the effort.

8 Responses to “Ubiquitous Language, Tiny Types and Responsibility”


  1. 1 Rafael Peixoto de Azevedo Aug 21st, 2009 at 9:13 pm

    Clear meaning and relevant behaviour are key factors for composing expressive types and deep models.

    Nice post. I like the way you show the need for careful design in order to avoid creating irrelevant types or breaking apart single (or tightly related) domain concepts.

    By the way, I prefer using the term “value object” over “tiny type”, because the latter represents to me a pure (and less relevant) focus on syntax. For the sake of “minimal integrity”, I would also explicitly add the requirement that “from” be less than “to”, since they are just integers.

    Thanks for another “well designed” post with clear thinking and simple examples about relevant design issues.

  2. 2 The Batman Aug 22nd, 2009 at 6:39 pm

    Nice post, homeboy.

    In you Contract example, you could reduce the noise you mention by adding implicit operators (for casting to/from int) to your Years class.

  3. 3 Rafael Noronha Aug 24th, 2009 at 2:50 am

    Tiny types looks like an interesting idea.
    The implementation sounds good.

    Something that also seems to bring expressiveness is the concept of code contracts, e.g. Spec#.

    Have you tried it?

  4. 4 Phillip Calçado Aug 24th, 2009 at 4:58 pm

    Hi,

    Rafael Peixoto,

    Tiny Types are different from Value Object. Although something “TinyType’d” is very likely to be a Value Object that is not a requirement. And Value Objects don’t have to be “tiny” in any sense.

    Batman,

    Your message got approved only because I recognised the IP address, please use your real name from now on ;)

    The thing about operators is probably true but I tend to not use language features that will introduce noise to readers coming from other languages.

    Rafael Noronha,

    I’ve done Design By Contract and even implemented my own libraries for that. I like the concept but I am still not convinced that it makes sense as part of the object model for languages like C# or Java.

    Cheers all

  5. 5 Alan Rubin Aug 25th, 2009 at 10:01 pm

    Nice post. I’m using Tiny Types now for some projects and it really makes the domain and the API explicity. Also it facilitates the reuse of concepts between parts of the project (methods such as .validate() for each type that can be easily used by UI layers for field validation for example).

    A question about your example: What would you do if you requirement is that it can be a TimeInterval that mixes the Business Hours and Overtime Period - in you example you consider it a kind overtime, but let’s say that we want to divide it in some hours for Business and some overtime ? How would you build your classes ?

    Thanks,
    Alan

  6. 6 Rafael Peixoto de Azevedo Aug 25th, 2009 at 10:33 pm

    Greetings, Phillip

    Value objects can be smaller or bigger and, if we stick to DDD, the same applies to entities, services etc… I just think it is better to categorise them after their essential responsibility in the design instead of after their accidental tininess.

    I totally agree that a wise design strategy is to make explicit all the relevant domain concepts, and only them. This leads to a simple and expressive design, that facilitates both software maintenance and collaboration with stakeholders.

    I think the key issue here is the discernment of what is relevant and what is not in the context of each project and domain. As usual, this is critical for healthily applying any design principle.

    Cheers,
    Rafael

  7. 7 Rodrigo Aug 27th, 2009 at 1:08 am

    Great post!

    Most systems I’ve seen have some kind of validation engine built-in. An anemic domain object is built and submitted for verification. As this engine checks the internals of other objects, isn’t that an encapsulation violation? Most people praise this as a flexible solution, as rules can be dynamically added and removed and the model object will remain the same. On the other hand, domain objects can be created in inconsistent states, leading to obscure bugs.

    What do you think about that? What is the best approach for validation in your opinion?

  8. 8 Phillip Calçado Aug 30th, 2009 at 4:35 pm

    Hi all,

    Allan,

    A question about your example: What would you do if you requirement is that it can be a TimeInterval that mixes the Business Hours and Overtime Period - in you example you consider it a kind overtime, but let’s say that we want to divide it in some hours for Business and some overtime ? How would you build your classes ?

    I’m no expert in this domain but if that was a requirement I’d say that there is a third Kind of TimeInterval that models that. But the best answer would be: ask your domain expert.

    Rodrigo,

    Most people praise this as a flexible solution, as rules can be dynamically added and removed and the model object will remain the same.

    For me this sentence clearly states that the system is not built using Domain-Driven Design. If it was then the “model objects” would have to model the business domain and that includes those rules.

    That said, DDD is not a requirement and there are cases where it’s not even the best solution. If the developers know that they are not following DDD and have a good reason in doing so then I can see no problem.

    Cheers all

Leave a Reply








Creative Commons License

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.