building and assembling

we software engineers build systems. Those can be small systems, big systems and anything in between. The most commonly associated activity that comes to mind when speaking about building systems is probably writing code. And debugging code, and testing code and deploying code. Of course, that's pretty much spot on - would be very pointless to learn all that coding stuff if you didn't need it. But I feel there's an important distinction to be made that we might not be doing often enough.

When building a system, I'm trying to be clear on what components I'm creating - that's the stuff I'm really building, and what part of the system comes to life by plugging things together. That can either be components that already exist, like a database or any other existing thing, or it can be something that has to be built specifically for the system that's, well, being built.

There's two hacks I'm aware of to actually build more, faster. The first is to be very critical of what to build in the first place - you'll create more value by focusing on what actually adds value, and not doing the rest. The second hack is to only build what actually, positively has to built. You don't get to software engineer faster by writing code faster, but by writing less code.

As a general rule of thumb, I try to avoid solving any problems coming my way by writing code. It's kind of a last resort. In order of preference, I usually like to first solve whatever problem hits me by using something that already exists. Need a fancy dashboard for business? Use metabase. Need a database? Postgres. Stream processing? Kafka. It's 2024, and quite frankly, the amount of good things that have been invented already is just staggering. Using great solutions is you standing on the shoulders of a giant.

My second approach is to reassemble whatever is in front of me. More often than never, existing systems already contain most, or all, capabilities needed, even if requirements change. This then comes down to reassembling existing components, repurposing logic or finding ways to extend functionality in surgical ways - without going full rewrite. Less code is still better than a lot of code.

If both approaches fail, writing new code is what needs to be done. But, like any software engineer, there's two people I think about a lot. That's me, and future me. And what that means is that I'm very mindful about making any new code easy to use, and reuse, in any current or future system. And that doesn't come down a lot to what programming language, technology or stack is being used, it's an exercise in interface design and coupling. What does that mean?

You want to create, and expose, interfaces that are as generic as possible without being overly abstract. Think of placing an order with some e-commerce service. A system for order placement should expose one method, one for placing an order, and not much else. And that's a good flight level for more than one reason. Firstly, everyone in the domain understands what that thing probably does. Secondly, you're making it easy to use, and reuse. Thirdly, there's low potential for leaking too many implementation details - and those leaks are making it really hard to use systems somewhere outside their first place of residence.

Having blocks like this make it really easy to design a system that is as much defined by what's written in code, specifically and inside of distinct units of functionality, as it is defined by how those units of functionality are wired together. Systems change, requirements change, and nothing is better than having a system that can almost be reconfigured to work with a changing environment.

This view of the world also makes me rather cautious of folks that output code like there's no tomorrow. Being able to write code, and potentially also fast, is of course not per se a bad thing - but you want to be selective on when to do that. Writing code that allows for seamless assembly is what you want, not just lines and lines of a cobbled together solution to a specific problem with little to no shape, thought or potential to grow. And probably that's why I don't call engineers coders.

I call them engineers.