Good & bad patterns in software design

Marcus • June 02, 2020

A drawing box with a brush.

Either through intention or incident, the architecture of your software typically reflects at least some patterns. After all, if your development team is reasonably committed to conform to at least some kind of internal standards, we can expect certain architecture patterns to emerge.

What differentiates a junior developer who has read a pattern book from a more experienced developer reading the same book?

Book smart vs. street smart

There are plenty of books on software architecture (some even by your favorite author!), along with even more online resources: articles, blogs, videos, free for everyone to consume. And while it is rather easy to pick up a copy of an architecture book, merely reading them arguably moves you further away from designing good software.

That’s a counterintuitive claim, to be sure. But with your now-gained knowledge of architecture patterns, aren’t you likely biased towards solving future challenges by trying to apply what you’ve learned?

I call it the law of the instrument, and it may be formulated as follows: Give a small boy a hammer, and he will find that everything he encounters needs pounding.

Abraham Kaplan, The Conduct of Inquiry: Methodology for Behavioral Science

If you try really hard, you can find hundreds of design patterns, all of which are used by some people in their code. But that’s other people’s code and other people’s patterns. They may work for them, but they are not universal.

What matters more than the patterns that you found and want to apply is the context you want to apply them in. Out of the patterns you know and love, which of those allow you to write better code, and in what ways?

Go write them down, I’ll wait.

A group of people sitting in front of a wall mosaic.

Even the term better code is incredibly vague: Shorter code can be better. Elegant code can be better. Code can often also express intent through comments or explicitness – a shortcut may achieve the same result but no longer conveys the original meaning. What better code is varies a lot even for different developers in the same company.

And so it is little wonder that, in trying to find patterns improving your code, you’re often found surveying the landscape within your company of what common goals you want to achieve. That leaves you with options to explore. There’s never just one way to build software, yet different paths lead to different outcomes.

And learning what works for the context you’re in is essential to gaining experience. The best way to learn is not by imitating others blindly, but by applying patterns alongside your own knowledge. If you think you’re on the wrong way, you need to have the confidence to turn back and analyze why it didn’t work out.

Optimizing for developer use

Every building block you provide for developers to use in their day-to-day work should be focused on solving actual business problems. Patterns can simplify common workflows that need solving dozens or hundreds of times by providing a common starting point.

Questions that I’ve seen commonly asked could include the following – all of which have been answered plenty of times in any existing project:

Yet all of these questions have merit on their own. With varying previous experience, you could estimate that each developer has a different idea of what is the most natural solution. Not that they’re wrong, of course: The only way to find out what works and what doesn’t is, essentially, experimenting and learning.

There’s enough variations to make solutions unique, but they don’t have to be. If 80% of your code revolves around the same 3-5 types of problems, then the solution to each of them should be as simple & straightforward as possible and require very little extra effort on the developer’s part on architectural concerns.

How flexible is your architecture, anyway?

The most obvious way to be introduced to ways of writing software is through the language you’re using & the basic frameworks you pick. You’ll have a hard time writing console applications that benefit vastly from the dependency injection model in Spring; just as it is unlikely that a MVVM approach found in WPF translates well to your REST API. It’s not impossible, but you’re often guided towards certain ways of writing software by the frameworks you pick.

Which only leaves you with the task of, well, finding a fitting solution. If you find one, it gives you a good headstart on gravitating towards common solutions. But how, oh how, can you decide between numerous choices? Do you…

Every kind of tooling that you use to develop software fulfills a number of functional and non-functional aspects, and each approach can lead to entirely different approaches of how code is written.

Opinionated frameworks can and often are, incidentally, providing you with very clear patterns on how to approach your architecture. You’re bound to implement things in certain ways, and in rare cases need to work around existing conventions. And they are great if they’re helping you getting to even 80% of how you want your software to look like.

Non-opinionated frameworks are a tad different: They can enable you to support your favorite patterns, but require you to know far more about the problem domains of both the business and the underlying technology in advance.

Questions which you could address include, but are not limited to:

Key Takeways

  1. Commonly found in statements like “This approach is bad, and while it solves your problem, please rewrite your code”.
  2. Just think of yourself in 3 years in the same company; or in 5 years in another company. Which parts of what you’ve learned will help you, and which parts are irrelevant?