Reflecting on my 20-year journey as a software developer, I realize some things I wish I had started doing sooner. These practices, habits, and mindsets would have accelerated my growth, expanded my knowledge, and enhanced my overall experience as a developer.
This article is what I would give to myself (among the winning lottery numbers 😛) if I could go to the past when my developer journey was starting.
I am an avid reader today, but this is since only a few years ago. I started the habit of reading in my mid-twenties and only started taking it more seriously near my thirties.
Today, I read a variety of books ranging from science to history, self-improvement, and, of course, software engineering.
I cannot tell enough the importance books had in my life, everything I learned from the written word, and how that ultimately took me to start writing myself and work on my first published book, Freelancing 101 For Developers .
I’m not someone who can only read books about software engineering, but I do have a rule: to read at least two books on software engineering per year. This rule includes books about programming and general software engineering practices and trends.
Tutorials, videos, and blog posts like this are excellent for capturing quick ideas, but if you want to get deeper into a given subject, there’s nothing like a good book, so if you want to level up your engineering skills, read more.
So far, we covered the first part of my advice to read more, but what is C.O.D.E.? And yes, it has nothing to do with coding but instead with how I approach my reading on deep subjects such as software engineering and other topics to which I relate deeply.
C.O.D.E. stands for capture, organize, distill, and express, and it is a term that I learned by reading “Building a Second Brain” by Tiago Forte . I’ll provide a quick summary of each step and how I approach it myself, but to learn more, please consider reading Tiago’s book, or he provides a good overview in his introductory guide to building a second brain .
For me, capturing is collecting pieces of information I am interested in from the different sources I consume, such as a book, an article, a video, an email, etc. If it resonates with me, I capture it in my notes. When capturing, I don’t capture the whole text but rather highlights, ideas, and notes.
On a typical day, I’d capture a few different notes, so over time, it’d be easy for them to blend with all my other notes and never resurface again. To prevent that, I take time to organize it. Most of the time, I do this at the same time I capture it by linking (tagging) contents by topics of interest. For example, I organize things by projects I’m working on or by thematics, such as astrophysics, software engineering, history, etc. In some areas, I have subcategories, but the level of detail is up to you. I like to keep it simple and use keywords to link things together.
Now that you have notes with valuable knowledge, it’s important to process them to distill them down to the essence. For me, this is adding notes to what I captured with my interpretation of it. I may have 100 different highlights for a book, but I would summarize it all in a single paragraph or bullet points with my main takeaways.
So far, we put in a lot of effort, but why? What do we take out of it? Because my notes end up being so valuable after steps 1, 2, and 3, when I need to work on something, like an article, a book, or any other creative process, I don’t start from a Google search to research a topic, I already did all that work, I search on my notes, and all the information I need, are there. If something is missing, it is because it is a new concept I didn’t explore before, so I need to learn about it and process it into the system before I create it.
Initially, you may be skeptical, but as you build your system’s foundations and invest more and more time into adding knowledge, the more useful and powerful it becomes.
So, for the first advice, read more, read meaningfully, and C.O.D.E.
Exploring diverse languages can be enticing, but I urge you to resist the urge to spread yourself too thin. Choose a programming language that aligns with your interests and career goals, and dedicate yourself to mastering its intricacies. For me, that language was Python. I studied how Python works in the ins and outs, read many books about Python, and took any chance to learn from the Python community, talks, meetups, etc.
Learning Python in-depth was one of the best decisions I made. It opened new opportunities that helped me work on fantastic projects. It helped me grow and mature to become a technical lead, helping other developers level up their skills and build great products. Finally, when I was ready to start my first blog, to write on advanced technical concepts, that eventually led to having an audience of 100k visitors a month on that blog and transitioning my career from software development to developer advocacy, the most exciting career change in my life.
So focus your energy on knowing everything there is to know about your favorite programming language, but always keep looking to learn new things, including new programming languages. You never know. Perhaps one day, that new programming language you start playing with will change your career forever.
With the whole work from home, I feel that pair programming is becoming a lost art, but I can’t stress enough how important pair programming has been in my life.
As developers, we are proud. We often use clever and creative solutions to problems to produce the desired outcome, and as long as it works, we are happy. But what if there’s another way to do the same? Perhaps a more efficient way, a more “clean” way. Maybe we would never know if no one ever told us. These learning opportunities are one of the reasons why I always recommend developers and organizations embrace code reviews as opportunities to learn from each other’s experiences.
At the heart of pair programming lies a principle that challenges the notion of individual brilliance: we are all better developers when we work together. While developers often take pride in their clever and creative solutions, pair programming breaks down the walls of individual ingenuity and encourages a more open, collaborative approach to problem-solving.
Through exchanging ideas and perspectives, pair programming brings to light alternative approaches that might have otherwise gone unnoticed. This cross-pollination of knowledge forces developers to step out of their comfort zones and consider new ways of thinking, leading to more efficient and innovative solutions.
Moreover, pair programming is an invaluable learning tool, providing developers with real-time feedback and guidance. As the two developers work together, they can observe each other’s coding styles, identify potential flaws in their approach, and learn from each other’s expertise. This continuous learning process improves individual skills and elevates the quality of the code.
The benefits of pair programming extend beyond problem-solving and learning. It fosters a culture of collaboration and shared responsibility, breaking down silos and promoting a more cohesive development environment. By working in pairs, developers develop a deeper understanding of the project, its goals, and its challenges, leading to a more unified and effective approach to development.
Pair programming also plays a crucial role in improving code quality and maintainability. Having two sets of eyes on the code will likely catch potential bugs, errors, and design flaws early on. This collaborative approach to code review reduces the risk of introducing defects and ensures the code is well-structured, easily understandable, and maintainable in the future
So when you can, pair with other developers and code together.
Subscribe to my newsletter for insights and advice on software engineering and coding, with a focus on real-world problems and practical solutions.
Won't spam you, at most once a week.
The importance of refactoring is one of the lessons that took me longer to learn. For many years, my philosophy to coding was always “if it ain’t broke, don’t fix it”, so I would always avoid having to refactor large portions of code.
It took me some time to realize I wasn’t doing it because I was afraid I’d end up breaking more things than I was supposed to be fixing. Still, it took me another while until I felt comfortable jumping into large codebases and improving things.
What changed? For starters, I had more experience and thus confidence, but also, around the same time, I learned about the importance of testing, and I was always striving for high code coverage.
Removing some of the worries about refactoring, I started embracing it much more, making more and more adjustments that seemed beneficial when working on new features, making code more readable, maintainable, and efficient.
As I refactored more and more, I became more proficient at it. Refactoring is a skill; the more you practice, the better you become.
Tools also make a difference. At the time, I had already started using JetBrains IDEs like PyCharm and WebStorm, which have incredible tools for refactoring, such as renaming variables, extracting methods, and more.
Embrace refactoring as a means to cleaner code, and don’t be too afraid about breaking things; for that reason, you have tests! 😉
Unit testing is one of those things we all say we do, but when we look at code bases, it is shocking to see how little test coverage there is, and though scary, it’s not surprising. Why would you spend more time writing code, to test your code?
Unit testing is one of those things you can’t learn from others. It is something you learn from your own experience by seeing how tests you wrote saved the day or how you wished you did, and hopefully the first, as it is a much less traumatic experience.
The first positive encounter I had with testing was when I was working for a client. It was an insurance company, and they had a lot of very complex policy calculations. All the formulas lived in individual functions under a folder with its own README file that warned developers to keep it as is. I remember that as it was shocking to read.
They hired me for the project because they were going to start a major refactoring project, as they wanted to migrate to newer versions of C#. There were some incompatibilities, primarily due to the time the project was stuck in an older version of the framework.
The refactoring took a bit over two months, and I was so surprised to see how smooth it went. Sure, there were issues here and there, tests were broken for a while, but at the end, when most of the work was done, and all tests were green and it was an incredible feeling.
Another not-so-happy anecdote was with my first freelancing customer many years ago. We were building a system in PHP to handle appointments. The project was a complete disaster for multiple reasons. We ran way behind schedule, so the inexperienced team and I decided to take shortcuts. One of them was sacrificing tests to speed up. That ended up terribly bad.
We were constantly working with the customer, but we met with all the company’s founders every month to present progress. In one meeting, we needed to show already delayed new features, and on the day of the presentation, not only that failed, but features that had been working for weeks now were also crashing or having problems, all because we pushed new, untested code that broken critical functionality in the app.
That was an excruciating moment for me. I was ashamed, and I learned the hard way the true importance of testing.
Remember to test, test, and test some more!
Becoming a proficient and accomplished software engineer is a journey, not a sprint. It demands patience, persistence, and a willingness to learn and grow continuously.
As you embark on this journey, embracing the fact that mastery takes time is important. There will be moments of frustration, insurmountable challenges, and lines of code that resist your best efforts. But remember, these are inevitable parts of the learning process, not signs of failure.
Every experienced software engineer has faced similar hurdles and emerged stronger, wiser, and more skilled. They have learned to embrace the learning process, knowing that each challenge is an opportunity to expand their knowledge and refine their abilities.
If you want to improve at software engineering, you’ll have to get experience, so do more of it. Ask for time from senior engineers, join technical meetings, ask questions, code, join open-source communities, or do whatever it takes for you to get exposed to software engineering practices. Remember, mastery takes time, but you can achieve remarkable things with dedication and perseverance.
Teaching others what you learn is one of the most effective ways to solidify your understanding and deepen your knowledge. Explaining concepts to someone else forces you to articulate your thoughts clearly and break down complex ideas into simpler terms. This process benefits the person you’re teaching and enhances your comprehension and retention of the material. So don’t hesitate to share your knowledge with others through blog posts, tutorials, or mentoring opportunities. By doing so, you’ll not only help others grow but also reinforce your growth as a software developer.
Thanks for reading!