Temporal coupling and Immutability



This topic is partly covered in my Applying Functional Principles in C# Pluralsight course, Module 2. Here, I’d like to elaborate on how temporal coupling and immutability are related to each other.

Temporal coupling

Temporal coupling is coupling that occurs when there are two or more members of a class that need to be invoked in a particular order. A common example is the following:

var calculator = new PriceCalculator();

calculator.UpdateCurrencyRates(eur: 1.02, gbp: 1.25);

decimal price = calculator.CalculatePrice(myShoppingCart);

Here, currency rates are required to calculate the price of a shopping cart. Without it, the CalculatePrice method throws an exception. However, neither the signature of the method nor the constructor’s signature force you to supply the rates. You need to remember to do that yourself. As a result, these two methods – UpdateCurrencyRates and CalculatePrice – are coupled together with temporal coupling: they have to be invoked in this exact order to avoid runtime errors. At the same time, nothing in the class’s API gives you a hint about what that order might be. Such design heavily relies on the human factor and thus is quite error-prone.

The fix is simple in this case. We just need to make the currency rates mandatory:

var calculator = new PriceCalculator(eur: 1.02, gbp: 1.25);

decimal price = calculator.CalculatePrice(myShoppingCart);

Now there’s no need to remember anything, the constructor forces you to provide the required data.

Temporal coupling and Immutability

Immutability is a guideline saying that once created, a class instance should not be changed. Any modifications are handled by creating new instances rather than mutating existing ones.

There’s a deep relationship between these two concepts. To see it, let’s consider the following code sample:

public class CustomerService

{

    private Address _address;

    private Customer _customer;

 

    public void Process(string customerName, string addressString)

    {

        CreateAddress(addressString);

        CreateCustomer(customerName);

        SaveCustomer();

    }

 

    private void CreateAddress(string addressString)

    {

        _address = new Address(addressString);

    }

 

    private void CreateCustomer(string name)

    {

        _customer = new Customer(name, _address);

    }

 

    private void SaveCustomer()

    {

        var repository = new Repository();

        repository.Save(_customer);

    }

}

This class gets a name and an address string as input parameters and uses them to add a new customer to the database.

Just as the previous code sample, this one has a major drawback: the invocations in the Process method are coupled in the temporal dimension. For this code to work properly, we need to remember which method depends on what to always call them in the right order:

public void Process(string customerName, string addressString)

{

    CreateAddress(addressString); // Updates _address

    CreateCustomer(customerName); // Needs _address, updates _customer

    SaveCustomer(); // Needs _customer

}

If we mess up with that order, the code will fail at runtime. For example, if we put the second method call above the first one:

public void Process(string customerName, string addressString)

{

    CreateCustomer(customerName); // Needs _address

    CreateAddress(addressString);

    SaveCustomer();

}

then the method wouldn’t get the required dependency – address – and the resulting customer instance will become invalid.

Likewise, if we try to put the SaveCustomer method invocation before others, it will throw a null reference exception: at the time it tries to save a customer, the customer instance would still be null.

What we have here is essentially this:

Temporal coupling and Immutability: Temporal coupling through shared state

Temporal coupling through shared state

All three methods write to and read from the shared mutable state. And that is exactly what fosters the temporal coupling. In fact, without a shared state, temporal coupling becomes impossible! The solution to this problem boils down to getting rid of that state. Making things immutable, in other words.

Below is a new version of the same code:

public class CustomerService

{

    public void Process(string customerName, string addressString)

    {

        Address address = CreateAddress(addressString);

        Customer customer = CreateCustomer(customerName, address);

        SaveCustomer(customer);

    }

 

    private Address CreateAddress(string addressString)

    {

        return new Address(addressString);

    }

 

    private Customer CreateCustomer(string name, Address address)

    {

        return new Customer(name, address);

    }

 

    private void SaveCustomer(Customer customer)

    {

        var repository = new Repository();

        repository.Save(customer);

    }

}

Note how we’ve removed the private fields. Getting rid of the shared state automatically decoupled the three methods and made the workflow explicit. Without the shared state, the only way we can carry data around is by using the methods’ arguments and return values. And that is exactly what we did: all three members now explicitly state required inputs and possible outputs in their signatures.

This is the essence of functional programming. With honest method signatures, it’s extremely easy to reason about the code as we don’t need to keep in mind hidden relationships between its different parts. It’s also impossible to mess up with the invocation order. If we try, for example, to put the second line above the first one, the code simply wouldn’t compile:

public void Process(string customerName, string addressString)

{

    // Compilation error: address is not yet defined

    Customer customer = CreateCustomer(customerName, address);

    Address address = CreateAddress(addressString);

    SaveCustomer(customer);

}

The only piece of shared state left here is the database: the SaveCustomer method persists the customer at the end of the workflow. Which is basically fine because it’s impossible to get rid of all mutations in your code. Just try to adhere to the “sandwich” design pattern: push the work with shared state to the edges of your business operations (Mutable Shell) and keep the stuff in-between immutable (Functional Core). I wrote more about this kind of architecture in this post: Immutable architecture.

There’s an important guideline that follows from the above. Look at the following code:

public void SomeMethod()

{

    Operation1();

    Operation2();

    Operation3();

    Operation4();

}

While it looks clean and simple, such design is almost never a good choice. The only use case where it’s applicable is when you have some background job firing once in a while and all operations in it are unrelated to each other. In all other cases what you’re actually doing here is hiding the relationships between these methods behind some shared state.

It’s better to write down those relationships explicitly, like so:

public void SomeMethod()

{

    var result1 = Operation1();

    var result2 = Operation2(result1);

    var result3 = Operation3(result1, result2);

    if (IsOperation4Required(result3))

    {

        Operation4();

    }

}

It’s more code and thus might feel less clean, but this way you will have much easier time tracking down what the method actually does. The previous version required the reader to examine each of its parts separately in order to see what pieces of shared state they use and modify. This version shows the workflow right away; there’s no need to step into any of the private methods. The code also doesn’t suffer from temporal coupling anymore: it’s impossible to mess up with the invocation order because the compiler keeps it in check. Getting rid of shared state and temporal coupling works wonders.

Private methods and signature honesty

I’d like to mention one important technique that is related to this topic. Look at the following class:

public class PriceCalculator

{

    private readonly CurrencyRates _currencyRates;

 

    public PriceCalculator(CurrencyRates rates)

    {

        _currencyRates = rates;

    }

 

    public Money CalculatePrice(Cart cart)

    {

        Money priceInDollars = CalculatePriceInDollars(cart.Items);

        Money finalPrice = ConvertCurrency(priceInDollars);

        return finalPrice;

    }

 

    private Money ConvertCurrency(Money priceInDollars)

    {

        /* Use _currencyRates to calculate the price */

    }

}

Its CalculatePrice method looks pretty good. The two private methods it uses explicitly define what they accept and return; the workflow is quite obvious here too. There’s one thing, though, we can still improve in this code. Note that the ConvertCurrency private method uses the currencyRates field to calculate the final price. Instead of referring to this field, the method can declare an additional argument, like so:

private Money CalculatePrice(Cart cart)

{

    Money priceInDollars = CalculatePriceInDollars(cart.Items);

    Money finalPrice = ConvertCurrency(priceInDollars, _currencyRates);

    return finalPrice;

}

 

private Money ConvertCurrency(Money priceInDollars, CurrencyRates rates)

{

    /* Use rates to calculate the price */

}

This way, we are converting it into a mathematical function. It doesn’t refer to the shared state anymore; its method signature is now completely honest about its inputs and outputs. Of course, it might be troublesome to do that with all private methods but sometimes it makes sense not to refer to the shared state even if that state is private. Mathematical functions have quite a few benefits in terms of readability, so this technique is worth considering.

Summary

  • Temporal coupling and immutability are inherently related to each other. Without shared state, it’s impossible to couple methods in the temporal dimension.
  • By bringing in immutability, you automatically get rid of temporal coupling.
  • Try to always define inputs and outputs of your methods explicitly, even if those methods are private.
  • Try not to refer to shared state, even if this state is private.

See also

Share




  • toby hei

    I’ve often been bothered by code that exhibits temporal coupling but didn’t know what it was called until now. Useful post as always.

    I’m also a fan of trying to avoid using fields in private classes, I also like to mark them as static (thanks resharper!). It would be nice if C# could go one step further and had a way to mark a method as completely pure though.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Indeed, purity supported by the compiler and also “immutable” keyword for classes will make the life much easier.

  • Zdeno

    Great article, but now i don’t understand where to apply CQS. Shouldn’t createcustomer and createadress methods have void return type(commands)?
    Thanks.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      CreateAddress and CreateCustomer are actually queries in this context. They don’t leave side effects and return values. Only SaveCustomer and Process are commands here, and they do have void return type.

      • Zeo Damian

        So, the thing is, you’ve got a tad of CRUDmonia.
        You are not _creating_ an address, nor a customer – they already exist. What you probably want to do is _validate_ the input, make sure these can actually form a valid address and so on.

        Because we don’t wrap these string in classes just because it’s fun. There’s a purpose.

        var addressResult = Address.Get(addressInput);
        if (!addressResult.IsValid)
        ..handleError
        var customerResult = Customer.Get(nameInput, addressResult.Value);

        if(!customerResult.IsValid)
        .. handleError

        db.Save(customerResult.Value);

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          I agree. Create[…] methods are implemented this way solely for the simplicity sake, to avoid cluttering up the sample code and staying on topic. Your version is a “more correct” one.

  • https://github.com/aleksey-bykov Aleksey Bykov

    your summary is boggling, why did you conclude in #1 that temporal coupling is impossible without a shared state? if you look closer, your very example at

    public void SomeMethod()
    {
    var result1 = Operation1();
    var result2 = Operation2(result1);
    var result3 = Operation3(result1, result2);
    if (IsOperation4Required(result3))
    {
    Operation4();
    }
    }

    disproves it, doesn’t it?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      How so?

      • https://github.com/aleksey-bykov Aleksey Bykov

        well, if you do it this way, there is no shared state and yet temporal coupling is possible

      • https://github.com/aleksey-bykov Aleksey Bykov

        btw it’s called a functional dependency: https://www.google.com/search?q=functional+dependency

  • https://github.com/aleksey-bykov Aleksey Bykov

    it’s also funny how you invent new names/terms for old and very well known concepts: https://www.google.com/search?q=data+flow+functional+programming

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      It’s an established term, it’s not me who invented it.

      • https://github.com/aleksey-bykov Aleksey Bykov

        have you heard of “data flow”?

        • Hristo Yankov

          Temporal Coupling is a thing – blog.ploeh.dk/2011/05/24/DesignSmellTemporalCoupling

  • http://etienne.mermillod.net Mermich

    Well few points on temporal coupling: how do you deal with framwework like asp.mvc who needs an empty constructor for posted objects and mutable properties, same for ef ?

    On top of it in this article you described about temporal coupling inside of the repository but not on the object passed itself wich way more difficult to deal with.

    The more i dealwith asp.mvc/ef/c# the more I think functionnal is too hard to obtain within these technologuies.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      You won’t be able to get rid of all mutability/temporal coupling, partly because of the way the underlying framework works. Even if ASP.NET MVC or EF were to help you with it, you still need to keep mutable state somewhere. The trick is to push that state out of your domain logic to the edges of the system, so that you can keep the domain core as clean as possible.

      No need to keep *all* your code purely functional, just the most important parts of it.

  • mickdelaney

    In distributed systems temporal coupling is also an established thing.
    http://iansrobinson.com/2009/04/27/temporal-and-behavioural-coupling/

  • http://www.engineerspock.com EngineerSpock

    In the second example, passing the field to the ConvertCurrency you made the first method which passes the field dependent on the state. Curing the second method, you made the first one ill.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Not any piece of data is state from a FP perspective. It only counts as state when it changes over time. Currency rates is immutable here, so no dependency on state in the CalculatePrice method. The previous version didn’t have this problem either, the only thing the refactoring improved is it made the dependency on the field explicit.

  • Petteri Kamppuri

    (Somewhat on topic:) How do you feel about using immutable Entities?

    I mean, using functional programming style immutable objects as your Entities, even though the Entities can and will change state.

    Like for example a Customer. Customer’s address or phone number could change. Would you try to create code where Customer instances are immutable, and all modifications create new instances?

    I guess your posts seem to be talking about server systems for enterprise apps. In these systems there’s a request/command coming in (from a web front-end or mobile client via SDK, for example). The command is handled by instantiating all the objects needed, then doing what needs to be done, and then all objects go away. At least this is how I’ve interpreted things.

    In a world like this immutability doesn’t seem to be huge win. I mean, the benefit of immutability is that different parts of an application don’t interact unexpectedly with each other via shared state/data. But, if the app creates new instances to handle each command, there probably isn’t that much room for unexpected state sharing.

    It seems like you answered the question in comments for http://enterprisecraftsmanship.com/2016/05/12/immutable-architecture/ C# seemed to be the restricting factor. Have you reconsidered or found new, compelling reasons for immutable Entities? Also, if Entities aren’t immutable, what is the immutable core of an architecture?

    Any thoughts, comments, ideas?

    Oh, and thanks for the great blog! I think all of your posts are really good. Thank you very much!

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Thank you, glad you like what I have to say 🙂

      You are right, the answer mostly depends on what programming language you use. In languages like C#, where there are no immutability features available out of the box, I personally find the practice of making entities immutable tedious and not worth the effort. I usually make immutable only value objects and try to transfer as much domain logic to them as possible. They therefore become building blocks of the domain model. As for entities, I tend to encapsulate all moving parts in them and make sure they always reside in a valid state. I rarely make entities immutable.

      In a world like this immutability doesn’t seem to be huge win. I mean, the benefit of immutability is that different parts of an application don’t interact unexpectedly with each other via shared state/data.

      That’s not the only reason for introducing immutability. Along with protection against race conditions, the second, even more important reason, is to be able to reason about the code. It’s much easier to track the program flow when you have access to all intermediate states the program took along the way.

      Have you reconsidered or found new, compelling reasons for immutable Entities?

      I find it easier to make entities immutable when there’s no database and/or ORM involved. But it rarely happens in my projects.

      Also, if Entities aren’t immutable, what is the immutable core of an architecture?

      That’s a great question. Ideally, the immutable core == your domain model. But in real-world projects, with languages like C#, it’s often impossible to make the domain model fully immutable, so you need to make trade-offs. You still can take advantage of functional principles but complete purity is almost never achievable.

      • Petteri Kamppuri

        Ok, thanks! Always those pesky practical realities coming and ruining the perfect ideal 🙂 Trying to make value objects immutable and moving logic there sounds good.