Becoming a great Software Engineer

I’ve been thinking a lot about how to become worthy of the title of “software engineer.” In thinking about how to become great, I’ve had to try to quantify what makes a great engineer. Here’s what I’ve gathered (so far) as the steps to achieving greatness – starting from the beginning (for any up and coming programmers out there):

1. Learn a programming language (specifically, learn the fundamental constructs: variables, branching, looping, and functions)
2. Be fluent (able to read and write) in that language (or a couple of languages)
3. Be confident in your ability to solve any problem programmatically
4. Understand the implications of your algorithmic (i.e., solution’s) decisions on the rest of the software (and possibly hardware)
5. Be able to detect when you’ve over-engineered a solution

Number 5 is what I added to the list today. I had been so incredibly focused on point 4 for the past few months that I’ve completely forgotten that software complexity is actually a bad thing.

Any of us competent programmers can build a complex system. The better of the bunch will think about how the additional layers of complexity will bring stability and extensibility to the system. But why does the solution have to be complex? Can a simpler solution suffice? Do you really need all of that abstraction? Do you really foresee extending this solution at some point soon (if at all)?

If a programmer’s time is the biggest bottleneck in development, then it makes sense to cut corners. “Embrace the jank” as some would say. A great engineer knows when, where, and why to add complexity to a solution.

The problem is how do you know when you’re over-engineering a solution? And is there any way to know without hindsight/experience? This is the most challenging question that I’m struggling with. I can only look outside of the software realm for answers, but I just get more questions.

Does an athlete only succeed when they already know the best action to a particular situation? Or can their decision-making be shaped in a way to always take the best action? Is it that we simply look for isomorphisms (i.e., similar structures) in problems that we’ve already solved and find a mapping for that existing solution applied to our current problem? Is this not what experience really is?