I was going to write this article about how software design shouldn't be a blueprint to be followed precicely, like a house blueprint is. How a house isn't supposed to change after it's built, but with software you'll be fixing bugs and adding features for as long as it lasts.
But then I read a three-part article by Hillel Wayne, based on interviews with "crossovers," people who have done both traditional and software engineering. It challenged parts of what I was going to say, reinforced other parts, and did it all much more eloquently than I would have.
Mainly it made me realize I should shut up because I've never designed a house.
Here are the articles, they're fantastic:
The part that most resonated with me was about spending more time on software design. Here's a quote from one of the people he talked to:
I’d like to see a lot more thought and planning go into stuff. I’m sure the Agile people are gonna freak out and be like, “You’re doing waterfall!” No, we’re not. We’re just thinking about what we want to build and why. -Matt (chemical)
And another quote from the third article:
First and foremost, there was not enough time between project conception and the first lines of implementation. Crossovers wanted more time to think about things before they did things. Just a couple of days of planning would make a big difference, regardless of how people used that time.
One thing I have done is designed software, so now this article is about my experience with that, with all the houses removed.
I help teams design apps. It's not all I do, but it's one of the satisfying parts of my job. It's both formulaic and organic... every project is different and I often don't know exactly how the design will look until we start thinking through the problem.
I love introducing a process that has worked for me, and for the other teams I've worked with. I love the moment when the design diagram comes together. There's a lot of variety when multiple people picture the same set of requirements, a diagram makes sure everyone is on the same page. I love putting thought and care into an app before starting to write code (of course I also love just starting, but usually not for production code).
I love the moment when the product manager says they have a better understanding of the work – lowering barriers between engineering, product, and design is a huge win.
I especially love the moment when I check in with teams months later and they're still using the design... and updating it. It's meant to be updated. It should be designed to be updated. New information is always coming in, your design should allow for it and welcome it.
There are a few rules for a good design, but my top two are:
1. Separation of concerns. If you're familiar with software, you're probably familiar with separation of concerns. Components/layers should each be responsible for one thing, communicating with each other through well-defined interfaces.
2. Design for change. I hear this less frequently but it goes hand-in-hand with separation of concerns... it's about expecting change and being able to adapt. It's about embracing new information rather than fearing it. It also takes a bit longer. It's faster to start implementation right away, but then every time new requirements come in and they don't fit, you have to slow down and refactor.
Design for change is the opposite – it takes more time upfront, but allows new requirements to be incorporated more easily. Go slow to go fast.
So how do you design for change? I'm going to sound like a broken record: well-defined boundaries and layers, and clear communication between parts of your system. When new requirements come in, there should be an obvious place to add them to the design (and they should be added to the design).
I don't know how much houses change once the blueprints are done, or if the blueprints change. I haven't done that. I have seen the pain of working in a fragile codebase, and the confidence (even joy!) of working with code that has a little extra care put into it.