With over 15 years of experience in software development, I’ve worked across various domains—everything from backend and infrastructure to frontend, mobile, and IoT. I’ve seen the industry evolve, and I’ve been part of projects that have stood the test of time. In fact, the very first project I worked on is still alive and running with the same backend and frontend we built 14 years ago, with absolutely minimal updates since its launch.
Throughout my career, I’ve learned that success in software engineering isn’t just about technical skills. It’s about the lessons you pick up along the way—many of which have nothing to do with code.
Your attitude and your willingness to continuously grow will set you apart. The most valuable insights always come from experience.
Let’s go over the software engineer career advice I’d like to share with you based on everything I’ve learned. Today, as a senior developer, these experiences shaped my career.
Advice 1: What users think matters
In software development, it's easy to get lost in the technical side of things—clean code, efficient algorithms, and scalable architectures. But something that’s just as important, often overlooked, is the user’s perspective. When you're deep in a project, you might assume that the domain doesn't matter as much, especially if it's something you're not personally invested in. But what you’re passionate about might not always align with the end-user’s passion, and that’s something developers must keep in mind.
Take the example of a food recipe site I worked on. The technology behind it was incredibly advanced for its time, a developer’s playground, really. We had image processing for search by color, multi-resolution photo storage, and even the ability to generate and print custom cookbooks. But for most of the users—many of them women from an older generation—it wasn’t the tech they cared about. They were there for the recipes, the community, and the recognition they earned. They shared their decades-old family recipes, took pride in their awards, and even invested in DSLR cameras just to upload professional-quality images of their dishes.
These users were so passionate about the recipes that when two of them accused each other of recipe theft, it escalated to the point of threats—serious enough that we had to pull their message logs at the request of the police. For them, this wasn't just a hobby; it was a deeply personal endeavor, and they saw their contributions as part of their identity.
This experience taught me a valuable lesson
Even if the technology is impressive, it’s not what makes or breaks a product for the users. It’s the emotional connection, the community, and how well the software serves their needs that matters most. It may seem trivial to you as a developer, but to the user, it can be everything. So always remember—the user’s opinion isn’t just important, it can be the defining factor between success and failure.
Advice 2: A bad client doesn't mean a bad project
Every software developer has likely encountered a “client from hell”—one who makes your life difficult with unrealistic demands, lack of trust, or constant second-guessing of your work. But just because a client is difficult doesn’t mean the project can’t be a rewarding experience.
A few years ago, my team and I faced one of these nightmare clients. Calls were an endless cycle of explaining every little detail, only for them to bring in unqualified contractors who botched basic tasks. The client’s expectations constantly shifted, and getting paid without a fight? Forget it. We were tempted to throw in the towel more than once.
But there was something about the project that kept us going—it was complex, challenging, and offered an opportunity for growth. We dealt with 5 repositories, a mix of frontend and four microservices, Dockerized environments, Postgres, and ElasticSearch. Not to mention, we had to figure out how to deploy this into a banking intranet, totally isolated from the internet, while maintaining data collection services. This pushed us out of our comfort zones for 6-7 months straight, constantly forcing us to find creative solutions.
Then came the blow. An email from my boss: “Stop all work. The client says we’ve caused damages with unmaintainable code and copy-pasting.” They sent over a 10+ page report, put together by one of their contractors, accusing us of incompetence. Morale hit rock bottom. But instead of giving up, we decided to fight back, and it was one of the most satisfying moments of my career. We ran our code through six different software analysis tools—and every one of them returned excellent scores. We meticulously countered every argument in that document and came out with our heads held high.
Growth comes outside your comfort zone
The truth is, a bad client doesn’t define a project. In fact, the difficulties we faced brought our team closer and pushed us to learn new tools and strategies we wouldn’t have explored otherwise. The experience also showed me that growth often comes from the least expected places—outside your comfort zone when everything seems to be falling apart.
So, while you may not enjoy dealing with certain clients, remember that the project itself might still be an incredible learning experience. The difficult clients will come and go, but the lessons you learn from these situations will stay with you forever.
Advice 3: Keep an open mind: You might not always have (or need) the full context
As developers, we often like to have a complete understanding of a project before diving in. But sometimes, you won’t have all the context—and that’s okay. In fact, it might even lead to some unexpected learning opportunities.
I remember one project where my initial reaction was, “This is too simple for me—can’t they give it to a junior developer?” The task seemed basic: build three API endpoints for user registration and login and two more for tracking users' locations every minute. On the surface, it looked like a straightforward project for a mobile app with about 30,000 users. “I’ll have this wrapped up in a week,” I thought.
But once I started to dig deeper, I realized just how wrong I was. Tracking 30,000 users every minute meant handling 500 requests per second—this was going to require some serious scaling, load balancing, and database optimizations. Suddenly, a “simple” task turned into a seven-week project that stretched my abilities. I had to learn about read/write database separation, performance tuning, and scaling systems in real time. It was a crash course in performance optimization that I wasn’t expecting but desperately needed.
In the end, the project wasn’t just about building a few endpoints—it was part of a larger research effort. We sent the database dump to Cambridge University for analysis, and a few months later, I found out that the project had been part of the BBC Pandemic initiative. They were simulating how a virus might spread in a rural area of 30,000 people, using one individual as Patient Zero to model transmission over time. The project even won an award for best medical research in 2018!
What did I learn?
Had I dismissed the project initially, I would have missed out on the opportunity to work on something impactful and to push my technical skills in unexpected ways.
The lesson here is that you won’t always have the full picture, and sometimes the most unassuming projects can be the ones that teach you the most. Keep an open mind, embrace the unknown, and take every project as a chance to learn something new.
Advice 4: Never skimp on security
As developers, we often focus on building features, meeting deadlines, and pushing projects live, but there’s one thing you should never, ever rush or take lightly—security. A small oversight can lead to serious consequences, not just for your project but for your users as well.
A few years ago, I was working with a team on a web app for a chain of hotel apartments. It was a straightforward app—search, list, and rent an apartment. The catch was that users had to provide personal data and photos for verification, which meant we needed to store these images securely. To handle the storage, we used Amazon S3 buckets. Since none of us were experts in S3 at the time, we set the bucket permissions to public, thinking it would be easier to test the photo uploads. We planned to lock it down before going live—but we forgot. Soon, the app was in production, with thousands of users uploading their personal data.
Then, one day, our CTO received an email from a white-hat security expert. He politely informed us that our S3 bucket was public, and he had found personal photos from our users online. He attached some of the images to prove it. Our hearts sank. We were convinced we’d been hacked and braced ourselves for a ransom demand. But as we read on, he explained that he wasn’t out to harm us. He simply wanted to give us two weeks to fix the issue. If we did, all would be fine.
Needless to say, we didn’t sleep for the next 36 hours. We immediately locked down the S3 bucket, implemented secure one-time pre-signed URLs for each photo, and fixed the issue before the deadline. We were incredibly grateful for his ethical approach and even made a donation to thank him for his help.
Never rush the security
The whole ordeal was a wake-up call. It taught me that no matter how pressed you are for time, cutting corners on security is never an option. What seems like a small oversight can have massive repercussions, not just in terms of data loss but also the trust your users place in you.
In software development, security isn’t just a box to check—it’s essential to the survival and reputation of your product. Never skimp on it. Prioritize it from day one, and make sure it’s part of your team’s DNA.
Advice 5: Your attitude towards things is the single most important thing in engineering
In software engineering, you’ll find yourself working on all kinds of projects, from cutting-edge new builds to messy legacy systems that seem like they haven’t been touched in a decade. While your technical skills are important, your attitude and mindset toward these challenges will often determine your success more than anything else.
I remember being assigned to a legacy project early in my career. At the time, it felt like the worst possible thing that could happen. The code was ancient, riddled with hacks and workarounds, and my mentor—a no-nonsense, Gordon Ramsay-like figure—wasn’t exactly a patient teacher. Every small feature I tried to implement seemed to balloon into hours of refactoring someone else’s spaghetti code. My frustration grew by the day.
I finally reached a breaking point and decided to confront my mentor. I complained about the endless refactoring, the lack of tests, and the sheer volume of copy-pasted code I had to deal with. His response was simple, but it completely changed my perspective. He asked me a few key questions:
-
“Did anyone complain about your big estimates?” No.
-
“Are you allowed to improve things while implementing new features?” Yes.
-
“Do you have time to write tests?” Yes.
He looked at me and said, “Then stop whining and make your own life easier.”
It hit me. I had been so focused on what was wrong with the project that I hadn’t seen the opportunity in front of me. Instead of complaining, I could take control of the situation. I started writing tests, refactoring the code bit by bit, and implementing small improvements as I went. Over time, the project became more manageable, and I realized that I was the one benefiting the most from the experience.
Work on your attitude
By taking ownership of the situation, I learned more than I ever would have on a straightforward project. I got better at refactoring, testing, and improving performance. My mentor’s tough love pushed me to grow, and even though the client never showered us with praise, I knew I had done solid work.
The key takeaway? Your attitude matters more than anything else. Whether you're working on a shiny new app or untangling the worst legacy code you’ve ever seen, how you approach the problem is what counts. Refactor the bad, automate the boring, and find ways to improve—even if no one else is looking. Your growth and satisfaction will come from how you handle the challenges, not just the final product.
Our Tech Lead, Ante Crnogorac, at the Digital Labin 2024 conference
Each experience is an opportunity to grow.
Being a great software engineer isn’t just about mastering technical skills, knowing every programming language, or keeping up with the latest web technologies. While those are undeniably important, what truly shapes your career is how you handle the non-technical aspects—the people you work with, the tough situations you navigate, and your ability to adapt and grow in the face of challenges.
Throughout my 15 years in software development, I’ve learned that success comes from more than just writing clean code or deploying a flawless app. It’s about maintaining a balance between technical skills and soft skills—understanding that sometimes the biggest obstacles aren’t in the codebase but in how you communicate, collaborate, and approach problems with an open mind.
Your approach to these moments will define your career more than your knowledge of any particular tool or technology.
So, my advice to every software engineer is this: Stay curious. Experiment. Make mistakes. Learn from every project—whether it’s a dream gig or a nightmare client. Don’t shy away from challenges or from stepping outside your comfort zone. And most importantly, embrace continuous learning. The tech world moves fast, and the only way to stay relevant and valuable is to keep evolving.