Post

Procrastination, the Useful Kind: Delaying Decisions in Software Architecture

There are many key insights in Robert Martin’s Clean-Architecture: A Craftsman’s Guide to Software Structure and Design, and it’s well worth a read. It covers SOLID principles and how they apply on a larger scale to software architecture, not just code. For a summary in his own words, see Robert Martin’s blog post on the Clean Code blog.

Thoughtful Procrastination

To me, the most surprising insight was a theme that ran throughout the book:

Postpone architecture decisions for as long as possible.

This sounds very strange at first, but turns out to be very logical. This does not mean that you’re being lazy! In fact, it might mean the opposite - actually setting up a way to postpone your decision might mean some more work up front. You might actually have to plan to postpone, or at least build a framework that allows you to postpone decisions. You still have to think about what you want from your future architecture, it’s just that the implementation isn’t concrete. And the further out you push this concrete decision, the better. And from what I’ve seen in the software world, this makes a lot of sense: everything is always changing and things move fast. Once you have tied yourself to a specific framework / service / database, it might be really difficult to back out of it. And in a year’s time, you might seem like a dinosaur!

Interfaces

This aligns with another useful design principle:

Design using interfaces, not implementations.1

Having an interface abstracts away the implementation details and keeps you focused on the problem at hand. For example, if you’re writing a section of code that needs to print something, you could have an IPrinter interface that declares a Print() method. In the rest of your code, you can use this Print() method and simply trust - for now - that you’re document will be printed. You don’t need to worry about how your document will be printed until you are actually forced to make a decision. Now you can program a BrotherPrinter that implements IPrinter; but if you want, you could also have a CanonPrinter. This does require some setup - you now have an interface and an implementation - but the great thing about this is that you can easily change the printer you’re using (depending on your use case, maybe even at runtime). The extra benefit, of course, is that you can also swap out your printer for a MockPrinter to run unit tests against. The rest of your program does not care what kind of printer your using, since you’re sending commands to it through the interface - the implementation is hidden from the rest of your program. It’s a win-win situation!

  1. See, e.g., Freeman, Eric & Elisabeth Robson. 2021. Head First Design Patterns: Building Extensible & Maintainable Object-Oriented Software, 2nd Edition. O’Reilly. Page 11. 

This post is licensed under CC BY 4.0 by the author.