Evolution of a Software Engineer

This is our story. For some of us, those with 10 or more years of experience in software, it might sound familiar. For the others, still in the early stages of their careers, there should be plenty of advice about what’s coming up next in your short-to-medium-term future.

The early stages

We are not entirely sure how, but it happens. A light sparkles and we just fall in love with programming, maybe after finishing building that university project or the other piece of software we built just for our own use. So much to learn, so much to experiment with. There’s this very short reward cycle in programming that increases our dopamine levels continuously and makes us addicted to it. We have been bitten by the programming bug, but don’t worry, it’s not a disease, it’s just brain chemistry.

We find our first place to work, and we feel very lucky to have been hired for the job. We start as incredibly self-motivated, we are ready and willing to learn everything about everything. We don’t mind picking up any of the tasks at hand. Ticking them off the to-do list gives us that reward our brain is looking for. We don’t really mind what projects or technologies we are working on either, as long as we get to learn and build new things.

At this stage in our career, though, we might just not be asking enough questions. Usually, we think it’s probably because people are just ashamed to ask, of admitting that they don’t know something. Depending on the personality this can definitely be the case, but sometimes, as engineers, we just prefer wasting hours on a problem and get to a solution ourselves rather than asking for help. This might go back to the reward system, it’s great for our brains to manage to fix the issue at hand, there’s no satisfaction in being given the answer to a particularly hard problem. If you can relate to this, make sure you do ask questions, there’s plenty of challenges ahead, you want to make sure you maximise the knowledge you gain from the time you spend on this planet and asking questions is a great way to do just that.

Absorbing the knowledge of someone that spent years learning from his mistakes in a fraction of the time is invaluable.

We also tend not to challenge our mentors too much, blindly following their advice. Don’t get me wrong, this is usually good practice, but we should also make sure we validate things from time to time, especially when they don’t feel right. At times mentors do tend to become a little overly pragmatic and might need a shake up. Take your time to build a showcase for what you think is an improvement so they can easily evaluate it, if it’s good they will embrace it, they should be experienced and smart engineers. If it won’t work, or it’s not an improvement, they will help you understand why, and these are all valuable lessons.

Another common mistake in our early days is going fast, and I mean, really fast. We want to demonstrate we are performant, we write tons of code, but sometimes we are not even sure whether we are actually building the right thing. This can be a massive waste of your time, so please, slow down, clarify the requirements again, take a long breath, and work on your tasks with a more focused plan.

The “fun” game of jumping ships

The first few months or years go by, we reach the point where we seem unable to step up our game. Our colleagues now look less knowledgeable than they did before, even our best mentors don’t look that special anymore. We’ve absorbed all the knowledge we could, so we start looking around in search of a place where our learning adventure can continue.

We also become a little stricter in our job search, we now want to work in a place where not only we can keep learning new things we know nothing about, but where we could also use our favourite technologies to build wonderful things.

During this period we might jump a lot of ships, companies look great on paper, but once inside it gets boring pretty quickly.
Eventually, with perseverance, we find a great place to work again, or at least one that suits our current needs, and we get back to work.

There is no such thing as over-engineering

We’ve evolved over time, and if we are unlucky enough, we have developed an OCD towards achieving perfection in our code. Refactor after refactor after refactor your code becomes more and more beautiful to your eyes and more and more obscure to the other members of the team.

A word of advice: try to write down how long it takes you to write down your new beautiful DSL, or super-generic uber-abstract future-proofed solution (that is only currently used in a couple of places in the codebase). And in addition, double check your “git diff”. Have you really improved your code after that refactor? It’s usually a good sign if you managed to remove a big chunk of code from the codebase, otherwise, you can always choose to reconsider and park it in a branch for the time being.

At this stage in our career, we always want to demonstrate how smart we are to the rest of the company, or the rest of the world. We need this in order to get that dopamine shot we need to get through our days at the office. Normal tasks do get repetitive, so this is our escape route. We start spending a lot of time innovating on what already works and not enough time writing code that is actually solving business problems.

Even if we know a way that works well and it’s battle-tested in production, we still seek for “new” ways or magical improvements. We tend to spend a lot of time trying to refine what’s already working quite well and is clearly understood by the engineering team.

One of the best pieces of advice I can give for these situations is the following: having code that works in production gives you more time to evaluate new methodologies, cutting-edge frameworks and experimental libraries during not particularly busy times. The stress that comes from new mysterious production issues is no fun. Make sure you experiment in less critical parts of the system or build a few well-tested side projects. This will make production adoption much easier as you will be able to share what you’ve achieved with your colleagues, get feedback, and eventually manage to have a smoother transition of your improvements into production.

Another common pitfall is trying to make everything work 100% of the time. We consider every possible minor edge case and write tons of complex code to handle it (which might actually make things worse), making the codebase harder and harder to maintain. You might think this is the only way, but it isn’t. Imperfect systems are sometimes fine from a business perspective, just ask the business for their opinion, they might prefer to use their resources and time to move on and build the next feature instead, and just send an email to a human to manually fix the problem if it occurs.

Why do we follow the buzz?

Another thing that happens naturally during our careers is this: we just put the world on pause and start learning something new. It can be a new language, a new framework, a new methodology, an entirely new area of development, or something different. But how do we choose?

Sometimes, something just attracts our attention because it seem to solve one of the problems we are currently facing. Sometimes we just do it because it feels like the whole world is moving in that direction. Sometimes it’s only for the sake of getting a better job.

The tricky part is how to learn how to distinguish temporary noise from actual industry-changing technologies. The only advice I have on how to approach this comes down to trying things out yourself, and I mean, really trying them out.

Spend some relevant time on it, don’t just read blog posts about it, dig deeper, come up with your own pros and cons list. Does it really solve the problems it is claiming to solve?

After endless time spent mastering frameworks and libraries, I’ve learnt that the most important thing is keeping them at the edges of my software systems. If they turn out to be heavily bugged, abandoned or superseded by new alternatives, they could be easily replaced.

Learning to cut through the noise will make you a much better engineer. New technologies are born every day, no one forces you to use them.

A very good step towards maturity in software engineering is to prioritise having working production code over new buzzwords to put on your CV. It can be tricky at times, and it does not sound cool saying this in an interview, but it should be far more valuable to a company to have working and maintainable software.

Please note: this does not mean we should stop being curious or not spend time on learning the next big thing. We should just try to balance things out while learning to keep having fun from the junior members of the team, but accept that you should get the job done sooner rather than later.

The road to greatness

During the transition into more senior positions, we tend to grow more and more pragmatic. This tends to make us look a little annoying and less competent to the junior members of the team or the engineers we are currently mentoring. We also tend not to code as much as before, some of us think trivial tasks are beneath us, which amplifies the problem, try instead to lead by example and close down those trivial or boring tasks yourself.

Having enthusiastic team members can help us remember that we should try to remain curious and keep learning. We should keep trying things out, our expertise will help you make a much more informed decision on which tech to pick up compared to a few years back in your career.

It’s not easy to generalise how a senior software engineer looks like after decades, though. We tend to evolve in different directions, but we still share the same potential issues.

We are much more likely to fall into the trap of under-engineering. Our experience now tells us that early abstractions are not going to work most of the time. Just remember, if your team doesn’t enjoy working on some parts of the codebase, it’s a sign that it might have been under-engineered and left behind. It might need improvements, so prioritise it whenever you have time to address tech debt.

Another likely danger is becoming a victim of our own cargo cults, the ones we’ve developed over the years. Make sure you challenge them from time to time.

A note on humility

Years of experience don’t directly translate to better-written code, keep asking for opinions and code reviews. Sometimes I ask my wife (she’s not a programmer) to proofread my code to see whether she can understand what it does.

You’ve probably heard this one before, but your experience should have taught you one critical thing: you can’t know everything. Anyone can still teach you something you don’t know anything about.

Don’t give up

We all have highs and lows in our software engineering careers. Some of us start prioritising money over job satisfaction, ending up in either contracting roles or highly paid boring jobs. Some might move into management in search of a bug-free life.

It can be intellectually challenging to have to deal with a continuous stream of problems, and in software, this is just how things are. It’s impossible not to experience those days where it’s just too much to take in, and think: “Why am I still doing this? Everything is broken".

If you feel like you need a change of career, take a break. It usually works quite well to just disconnect for a few days or even a few weeks. You won’t believe how much revitalised you will feel when you come back, actually craving for something to build, or a big mess to sort out.