IO To the boundary

IO

Have you ever noticed that most software architecture guidance divides the code in at least 3 distinct parts?

That's because there is a generic guiding principle being conveyed by all of them, a principle I call 'IO to the boundary'.

Hexagonal Design, Clean Architecture, Imperative Shell and even Model View Controller all try to tell you to push IO operations to the beginning and end of an operation, while doing no IO in the middle of the operation.

Architecture guidance
High resolution

Pseudo Code

This implies that all this guidance should lead to the same top level code at any request entry point.

// first perform IO to load data

// then execute a core pattern which performs no IO

// finally perform IO to store data

Example MVC controller

As an examplen a top level entry point for a web request (using an MVC controller) likely should look something like this, regardless of the guidance you are following.

[HttpPost("{bookingId}")]
public async Task<IActionResult> Book([FromRoute] string bookingId, [FromBody] PlacePurchaseOrder command)
{
    // perform IO to load data
    var booking = await repository.Get(bookingId);

    // invoke functional core, no IO
    booking.PlacePurchaseOrder(command.PurchaseOrder, command.Name);

    // perform IO to store data
    await repository.Flush();

    return Ok();
}

Benefits

When you stick to this simple rule a lot of problems in your system (regarding productivity, maintenance, performance and testability) will simply disappear:

  • The overall code is easy to understand from a high level.
  • The business logic is encapsulated in a core pattern and is less likely to be spread out across the code base.
  • It's easy to test this business logic in isolation through unit testing.
  • Dependencies are enforced to be encapsulated and can be mocked for testing purposes.
  • Easier to ensure read or write performance as the respective operations are called from a well known location.
  • It's simpler to maintain atomicity of the operation, as any outbound IO is located at the end.

About the author

YVES GOELEVEN

I've been a software architect for over 20 years.

My main areas of expertise are large scale distributed systems, progressive web applications, event driven architecture, domain driven design, event sourcing, messaging, and the Microsoft Azure platform.

As I've transitioned into the second half of my career, I made it my personal goal to train the next generation of software architects.

Get in touch

Want to get better at software architecture?

Sign up to my newsletter and get regular advice to improve your architecture skills.

You can unsubscribe at any time by clicking the link in the footer of your emails. I use Mailchimp as my marketing platform. By clicking subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.