So You Want to Be a More Senior Engineer?
“Engineer” really is a very silly term for people that make software. Engineering is supposed to be a predictable application of science toward predictable results. Software development is really anything but that. The biggest problem in our profession is and always has been getting predictable results.
The key difference between a junior engineer and those that are more senior is that the more senior engineer realizes the inherent unpredictability of delivering working software and constantly works toward making that delivery more predictable.
The junior, on the other hand, approaches the work with two key hinderances:
- Being too intellectually challenged (or enamoured) with the details of programming in the small to be able to see the larger picture
- Having little experience with complex systems (and often not even understanding that they’re working in one)
As a result the more junior engineer will generally pursue solutions that risk predictability, frequently without realizing it. What’s worse is that often these solutions will be faster/better/cheaper, further reinforcing the approach. Failures with risky approaches are often written off as fluke mistakes, technicalities, or the nebulous “human error” without reconsidering the methodology. Often they’re written off like this even when the cost of the failures vastly outweighs the riskiness of the approach.
In software development, the details can seomtimes be really difficult. This never really goes away with experience, but the Junior Engineer hasn’t yet been faced with that enough times to know it. And when the details are difficult, the junior engineer focuses primarily on the details, often to the detriment of the big picture — predictability. It’s a pretty understandable choice; our brains are limited in how much they can consider at once, and for some reason engineers have a tendency to default to concentrating on the technical details.
Conversely, the more senior engineer will be less encumbered by the technical details and will have been bitten a number of times by the nature of complex systems. If that engineer has taken the opportunity to learn from those mishaps, there’s a chance for a much higher level of engineering (and predictability).
With that in mind, here are a bunch of examples that I think show the differences more plainly:
Junior: Finds a solution.
Senior: Finds the simplest solution.
Junior: Finds a solution for right now.
Senior: Considers the longer term implications when finding a solution.
Junior: Defaults to adding complexity/code with every requirements change.
Senior: Knows that changes often indicate a unifying concept and an opportunity to remove complexity/code.
Junior: Finds ways to manage complexity
Senior: Finds ways to remove complexity (because complexity management techniques are another form of complexity!)
Junior: Predicts results
Senior: Embraces unpredictability and manages it
Junior: Assumes that lack of evidence of problems is evidence of lack of problems.
Senior: Is aware that unknown unknowns almost always exist.
Junior: Can explain why their grand plan is flawless.
Senior: Ships as early and often as possible and judges solutions empirically.
Junior: Believes that it’s sufficient to achieve quality at the edges.
Senior: Knows that often you have to ensure quality of internal components separately to achieve quality at the edges.
Junior: Believes that once the pieces are verified, the system is verified.
Senior: Knows there’s still work to verify the system as a whole.
Junior: Will call “done” when the happy-path works, or the code is committed, or the code passes testing, or the code is in staging.
Senior: Realizes there are so many technicalities involved in actually solving real problems that one shouldn’t call “done” until the user has used it and agrees.
Junior: Believes that once you get the software to work, it will work in perpetuity with no extra effort.
Senior: Realizes that maintenance always takes considerable time and effort.
Junior: Optimizes code that seems slow.
Senior: Measures for performance issues and optimizes only the bottleneck.
Junior: Writes code for the computer to understand.
Senior: Writes code for the computer and humans to understand.
Junior: Focuses entirely on the technical aspects of the role.
Senior: Realizes the entire complex system is a socio-technical one that also necessarily involves people. Constantly tries to also take the humans (managers, stakeholders, users, teammates, etc) into consideration.
Junior: Works tirelessly and continuously to solve a critical and time-sensitive problem.
Senior: Understands that communication during critical times is also crucial, and that “I have no update” is still a highly valued update.
Junior: Can explain why a solution is good.
Senior: Can explain why a solution is better than the others for a given criteria.
Junior: Is learning to be critical of software designs choices.
Senior: Is always trying to understand the tradeoffs in software design choices and can see the good in imperfect solutions.
Junior: Is learning new technology, design patterns, and practices and trying to apply them.
Senior: Judges technology solely on the basis of its ability to solve actual problems and skillfully avoids cargo-cult programming.
Anyway… these are just examples and certainly don’t form an exhaustive list. I’m not at the end of learning from experience either, so I couldn’t even write an exhaustive list if I wanted to.
One more example of the meta-variety:
Junior: Is starting to realize that predictability is valuable and is
learning how to achieve it.
Senior: Realizes that different predictability approaches have different costs in different scenarios and makes choices accordingly after cost/benefit analysis.