Software design that lasts

Tim Meeuwissen
Jumbo Tech Campus

--

I’ve built a range of software applications from the ground up and every time I had to change functionality I bumped my head. Until I understood these core principles that I’m going to talk about in this article. Whether it was an ERP system, Order picking software, Advertising software, Logistical routing software, Search and refinement software, E-Commerce software, or even Network Infrastructure Design, it always came to the same basic principles.

Atomic correctness

The first 15 years of my career were centred around a big ERP system that I’ve programmed from the ground up. The bigger the system got, the harder it became to implement seemingly simple iterations of components.

This became a repeating theme in the years thereafter. Incoming requests that affected multiple parts of the systems that I’ve designed and developed, often required a complete overhaul of the underlying layers of software. Seemingly small changes could lead to an unpredictable amount of development time. Stressing the customer, me and my team even more.

These situations especially occur when you work on an application that organically grows. Even now, working at Jumbo, I recognise this pattern. And I see it as my responsibility to coach and mentor my team, developers and other colleagues to open their eyes for the factor I call Atomically Correctness.

An example:

Let’s say we have an e-commerce system, which is used to sell products per one item. Now let’s imagine that your business stakeholder has a request to be able to buy combinations of products. So for example, you can buy a giftbox as a group-item, but you want to (or need to) show all the individual items in there. And let’s say that the business stakeholder calculated the business case, and any development effort is justified.

The traditional approach

Nine times out of ten, the approach would be: what should we change in order to make this succeed? We need the order detail page, the checkout, the basket, the product detail page, the recipes page, and so forth. Then, we need to re-assess the code that does the calculation, and perhaps add stuff to the basket datamodel to support this.

What we’ll end up with is multiple teams that need to make this work and adjust their code to serve the same demand. The project soon grows out of proportion. Leading up to a multitude of stakeholders to have to align on the same project. To worsen the case, all kinds of interdependencies start to occur and project managers need to become involved, making the request practically impossible to execute upon. It hurts the trustworthiness of the solution as well. Rigidness often gets the ‘technical debt’ stamp which makes it sound that technology is impeding business opportunity while it’s actually the other way around. It’s more accurate to call it ‘product debt’, you can read about this in my blogpost “Help my product owner wants a broken car”.

The atomically correct approach

This approach might sound simple but it leads to a world of difference once adopted properly. It makes you think about the request in a slightly more abstract, and tremendously more curious way.

Let’s have a look at the example again. Which new facts can we derive from this request?

  • Apparently items can consist out of other items
  • There are different mutators on the display of a basket, these resemble properties of those items
  • Lists occur in many places, apparently there is a list of items, with those mutators applied to it. But it behaves differently in many occasions (orders, basket, checkout, they all represent the same list, but the mutability or operability of the orderlines might differ)

These are just some abstract thoughts of what it is that you could derive. You can only see these findings for what they are when you take a step back and see which assumptions have been made earlier which have now became invalidated.

Of course, you could ‘just make it work’ with the traditional approach, but the complexity of the code as well as project rises tremendously, up until a state where all of it needs to be rewritten because it’s impossible to comprehend or change what’s in front of a developer.

Looking at these new learnings as stated above, we might see a pattern. Instead of changing to the request, we implement the learnings and while doing so we create the new functionality. This will lead up to code that remains valid and logical, even when the desired outcome has to change.

Stay curious and learn from incoming requests which assumptions become invalidated.

When done as such, technology will evidently become an enabler for opportunities. As an example, since we’ve learnt and implemented relations between items in a basket, we can also add recipes! Or in example visualise that a bundle of 6 actually consists out of 6 individual items but with a reduced price. While not even having to rebuild all of the pages again.

The longer we apply this way of working, the more technology is shaped like the actual business model. This inherently stimulates the sense ownership and the value of the product.

A good rule of thumb

When you find yourself in a situation in which you think: this is so completely different, perhaps I should single this case out and condition it based on different logic. You’ll find yourself in the Atomically Correct versus Traditional Fixing spot.

An example: You have content management for all your pages, but the checkout page is so extremely complicated and delicate that you think you want to serve that config from file (Traditional Fixing).

With Traditional Fixing, this would lead to:

  • not understanding where the page comes from, or how to link to it.
  • content managers won’t understand why they can’t create a page with that name, or why that page “isn’t working and showing something different”
  • developers will soon find a new spot at which they will be asked to build heaps of exceptions in
  • developer will always be needed to explain and change the pages, even when it’s just text or some extra component that needs to be displayed, taking away their precious development time from new features.

Understanding that the situation for this page requires a different approach. But that doesn’t inherently invalidate the other rules that are already in-place. Instead, they can be amended to cater for the new knowledge we’ve gained. In example (Atomically Correct):

  • We need to be able to block certain pages from the content manager’s influence, but still enable them to understand that these pages exist and can be linked to.
  • Some configurations are too complex for content editing.
  • We need to have a mechanism that can import and export a configuration to a particular URL

When we implement it this way, even when demand changes, you’ll end up with:

  • a way to import and export configurations
  • a rudimentary way to do access control to pages in your CMS
  • a backup mechanism as a failover when the CMS is down, has corrupted or is being replaced.

Isolation

There are many coding principles that adhere to this Atomically Correct design. In an earlier blogpost I already wrote about a decent few of them.

  • Striving for a Service Oriented Architecture
  • Domain Driven Design
  • Component based development
  • Streaming Architecture
  • [insert the next way of working here]

Almost all of these design practices revolve around isolation. Making sure that the need for one functionality doesn’t bleed into the domain of some other functionality. With the ultimate goal to disentangle dependencies, and enabling complete ownership for a team and its product owner.

These technologies often seem super sensible when we look at them from an architectural level (how things are connected). But we tend to neglect the entire rationale, the reason why we do them, when we get to the level of software development itself. It all boils down to:

If the parts make sense when you look at them from solely the perspective of the part itself, the entire thing you build with it will make more sense as well

--

--

Tim Meeuwissen
Jumbo Tech Campus

Seriously passionate in understanding how stuff works