I create software for fun and money.

5 years in software engineering

Fri, May 30 2025

It occurred to me a couple of weeks ago that I've crossed a somewhat significant career milestone: five years in software engineering.

The past half a decade has been full of learning opportunities—both fun and stressful. Software engineering has given me an intellectually engaging career, a decent salary and I get to play around with computers all day.

It has allowed me to spend my working days with like-minded geeks, who often love to code and get a kick out solving complex technical problems.

For that, I am eternally grateful.

Here's a summary of what I learned so far, plus some advice for beginners.


Technology


Learning one programming language deeply and a couple of others more superficially seems like a good strategy.

You don’t need to be an expert in every programming language, especially early in your career.

I remember myself trying to learn a new language every other week—jumping from Python to Java, from Java to C and from C back to Python. This is not how you acquire valuable skills.

Early in your programming career, focus on learning one language well.


Once you know one language well, try another that follows a different paradigm from the one you know.

This is the stuff that expands your mind, broadens your horizons, and gives you new mental models you can apply when programming in your primary language.

For example, if your main language is Python, learn a bit of Java, which is more strictly object-oriented. Or try Rust, for its strong type system and memory safety without a garbage collector. Or explore Haskell, for the purity of its functional paradigm (and its type system, too).


Over the next five years, these five languages should have you covered for back-end development:

Java, Python, C#, JavaScript/TypeScript, maaaaybeee even PHP.

Two should be enough. Often, one will be enough.


Make sure to learn the basics of databases. Especially relational ones.

I’ve been in this field for five years and still haven’t had to write a triple-nested SQL SELECT statement.

But it helps to know JOINs, aliases, how and why we use indexes—and maybe a thing or two about transactions and isolation levels.


Learn system design and understand what can go wrong in distributed systems.

Even a high-level overview can set you apart from other developers. Stuff like concurrency, database isolation levels, race conditions, and leader-follower replication—along with their potential pitfalls.

Personally, I don't know all of this by heart, but I know these concepts exist and that I should be mindful of them when working on a complex, distributed system.


Learning Unix command-line is a must.

Since terminal emulators are ubiquitous in the programming world, it's safe to assume you'll work with command-line daily. Therefore, learning basic-to-advanced Unix commands is a necessity.

Using command-line, you can install programs quickly, get system/network information or you can poke around in kernel settings. You can use it to navigate your way around directories, check your program logs, or connect to remote servers.

The uses are many, and even though I do enjoy using a nice UI app that can do the same thing, learning the underlying commands is often necessary for increased productivity.


Learn Git.

Sure, your IDE might give you a simplified interface on top of Git, but there’s no substitute for learning the basic to advanced Git commands.

I’d recommend learning at least merging, branching, reverting, stashing, and conflict resolution.

If you want to take it further, learn about rebasing and its pitfalls, interactive rebasing (and the options it gives you), and patching.


Having at least some idea of how to get around cloud/DevOps stuff will be tremendously helpful.

Familiarity with Azure or AWS seems to be the standard job requirement these days.

Besides that, if you don’t like programming that much, there’s some big bucks to be made in the cloud world–whether you're helping companies with day-to-day cloud operations or designing their cloud architecture.


Meta


Don’t chase every shiny new tool.

Learn the tried-and-true ones instead. "Old" tools have stood the test of time. Their strengths and pitfalls are well known. They’re well understood and have a large user base.

Using mainstream tools (programming languages, databases, frameworks) really pays off in this field.

Of course, if you know what you’re doing, maybe you’ve got a use case for Cassandra (or some other LSM-tree database). But if you’re building your first e-commerce project, use Postgres.


Keep the tech stacks of your projects small.

If you have the choice, reduce the cognitive complexity of your projects by using just one programming language and one database.

Think twice before adding more stuff.

You might even want to focus on simplifying the mess in that brownfield project you were assigned. It pays huge dividends in the long run.


It probably doesn’t matter what editor or editing style you use.

Whether it’s a Vim-like or Emacs-like workflow, or just the plain old "whatever the default was in VSCode."

If you commit to one style and learn it thoroughly, you will become very fast with it. I don’t think one over the other will make you 10x more productive.

For comfort and ergonomics, though, I do recommend Vim combined with one of the JetBrains IDEs.


True software revolutions go unnoticed by the general public.

There was hardly a bigger productivity leap in the last 10-15 years than what we've achieved with cloud and containerization.

Yet, when you mention the cloud to your non-tech friends, they usually respond with "Oh, you mean the file backup thingy".

What they do know about, though, is blockchain, smart contracts and AI. And while I agree that LLMs provide tangible value, the real revolutions in software engineering fly under most people's radar.

If there's something software-related your non-tech friend group can't stop talking about, it probably matters little to the field of software engineering.


Some repetition in code is okay.

Since code is “written for people and only occasionally for machines to execute”, making code clear and readable while sacrificing some DRY-ness is okay with me.



Soft skills, psychology & money


You program computers, but you work with people.

While computers are strictly logical, people are more prone to emotion-based behavior. Learn to get along with people, be a nice person—but don’t let others have their way with you.

"Compassionate assertiveness" has been an approach that has served me well so far.


Don’t be a dick.

An experienced network admin once told me about his team’s hiring process—it boiled down to just one sentence: “Don’t be a dick.”

It sounds simple, but once you apply it to real-world candidates, you may quickly realize it filters out more people than you’d expect.


Brilliant people can sometimes be dicks.

You’ll probably run into colleagues who are technically proficient, but come off as self-important and a bit too in love with their own intellect. While they don’t make great conversation partners, I often try to learn something technical from them.


Before you get mad at your colleagues or boss, learn their motives.

This is advice I wish I’d been given when I was starting out. To give an example:

I had a boss who micromanaged us, pushed us into overtime, and set ridiculous deadlines he pulled out of his ass. Meanwhile, he kept preaching some long-term vision that made zero sense.

Plot twist: the company got acquired a month later. Then it hit me.

All his actions were driven by one thing—selling the company. It wasn’t about making a great, stable software product and selling it to customers. No, it was about selling the company itself.

So yeah—figure out what’s driving people. In a work environment, it’s usually money or prestige.

But mostly money.


Speaking of money, freelancing can 2x–10x your monthly income.

It’s not for everyone, but it’s worth giving a shot.


Junior programmers are the best-paid employees in an engineering team (relatively speaking).

There's two reasons for that.

First, new hires usually get higher starting salaries (for reasons such as inflation, rising labor costs and whatever else makes companies pay more to new people while neglecting their best in-house talent).

If you started at company 3 years ago and your total compensation is x, newly hired people can easily pocket up to 1.5x.

Second, and this isn't at all obvious, is that senior people are often 5x to 20x more productive than juniors. All the usual reasons apply: they know both the product and the codebase better, they know more people in the org, they have made more mistakes in the past and accrued more experience as a result.

Yet, you don't see their salaries being 20x the junior salary.

Hence, when you consider total compensation per unit of productive output, junior programmers are the best-paid employees in an engineering team.


Don’t be outcome-dependent.

There were times in my career when I spent weeks on a feature that was eventually scrapped and never used by the client. I worked my ass off on some module that was almost completely rewritten 2 weeks later.

And you know what? I learnt not to care that much.

Only thing I care about these days is whether I learned something new from writing that code. Sure, it’s nice when your code gets used—and in a well-run organization, it usually will.

But don't sweat it if your brainchild gets scrapped. Just go on and enjoy the meditative process of writing code! :)


Don’t marry your code—this touches the same point as the above.

If you work in a team, your code is ultimately owned by the team. Don’t cry if someone rewrites your tests or alters your incredibly clean design you spent 3 days on.

Focus on the team effort: put the team first. Do what’s best for the team, not what’s best for your ego.


Tools & practices


Ubuntu is a great free OS for programmers.

Nuff said.


Apple currently makes the best laptops—whether it’s the MacBook Air or the MacBook Pro.

There’s no close second.

If software engineering is your profession, then the initial cost of a reasonably specced MacBook Pro is nothing compared to the hours of comfort, stability, speed, and joy it’ll bring you.


Test-driven development is nice...

...although I prefer its less strict cousin–something I call the “Test aided development”.

I don’t strictly write the test first and then fill in the code. Instead, I write a test for a small portion of the desired functionality and then fill in the code.

This is especially helpful when the design isn't yet clear or when requirements are likely to shift under my feet.


Breaking down large tasks into manageable, small sub-problems is a superpower.

This is such a basic thing, but it took me four years before I started to employ it consistently. Since then, no task has seemed daunting to me.

I’m also a big fan of the saying: “Make it work, make it right, make it fast”.

The first iteration of a solution to a programming problem I produce is usually ugly and slow, but gets the job done.

The second iteration is a refined and refactored version of the previous one.

If need be, I also produce a third iteration, which then improves the performance.


Writing and diagramming are superpowers–gotta do more of both myself.

Diagramming: we are visual creatures, therefore I maintain that nothing makes a software architecture as clean as a reasonably detailed, high-level diagram. It’s been a lifesaver for me on several occasions.

While the legacy code I was dealing with was perhaps too complicated to quickly make sense of, a single glance at the architecture diagram made things clearer.

Writing is even better. Nothing, in my opinion, reveals holes in your reasoning better than writing. Hard problems I’m stuck on suddenly become clear (or at least more manageable) once I write down the part I’m struggling with.

My process looks like this.

  • Describe part of the problem
  • Write down my assumptions about input/output or the inner workings of the code, step by step
  • Test my assumptions by experiment
  • Usually at this point, my faulty reasoning is exposed and the problem is resolved
  • Repeat until the ticket at hand is finished


Misc


It's about the product and the (perceived) value the users are receiving from the product.

I understand that we, the developers, care a lot about clean architecture, DRY code, beautiful abstractions, REST interfaces and ACID properties...

And while all the above things are important, in the end, it's about solving the user's needs. The user won't care whether the back-end is hacked together in PHP or carefully crafted in Rust.

As long as it solves the user's problem, they will be happy and they might even pay you for your app.


LLMs won’t make programmers obsolete.

This is just my personal prediction, but LLMs do not address the essential complexities of building software.

At best, they shift the abstraction layer at which we operate one level higher. Java did the same to C did the same to Assembly.

That upward shift didn’t eliminate software engineering jobs. On the contrary, software engineers remain some of the most sought-after employees.


The antidote to a certain kind of burnout is disciplined working habits.

If you suffer from serious burnout, this advice probably won't be for you. I wish you good luck in your recovery and don't hesitate to seek help if you need to.

That being said, this is what helped me overcome some mild burnout symptoms:

I once thought that rest was the only solution, but what helped me was kinda the opposite. No overtime, but also no slacking. Consistent ~6 hours of focused development work per day, day in and day out.

No distractions. No meetings. No interruptions.

After implementnig the above principles, my motivation levels improved noticeably, because I could see I was making tangible progress on my projects.

If you are a manager, try to provide this environment for your team if you don't already. Come back in three months and tell me the team’s productivity hasn’t improved or that your engineers aren’t happier. I think you’ll be surprised.


Interruptions are a huge productivity killer.

I don't mean planned interruptions to recharge your batteries during programming sessions.

What I mean are incessant messages from colleagues or bosses, shifting priorities, or too many meetings sprinkled throughout the day. Avoid them like plague, focus on delivery.

Remember, Focus is a developer's best friend


Recommended reading for someone who’s starting out or is medium-advanced: