25 years on: what I’ve learned about software development
I’ve been developing software since the early 1990s, and in recent years have also had the privilege of teaching adults how to code, preparing them for work in the real world of software development.
For a while now I’ve had a few ideas kicking around in my head about what constitutes best practice in software development… so I’ve finally put fingers to keyboard.
Although none of this is new, I can see a real benefit in collating these ideas in one place. I’ve taken varying amounts of time to learn some of them, so my hope is that they will be beneficial to others, no matter what stage of your software development career you are in.
I’ve undoubtedly missed some things, and I’m sure people will have varying opinions, so let me know in the comments!
Consider the next developer
To me, this principle underpins all software development good practice: when you are building software, bear in mind the next developer who will be reading and maintaining it.
I sometimes call it “the principle of least surprise”: structure and write your code in such a way that it causes the least number of WTFs to the next person looking at the code.
More times than I’m comfortable with, I’ve wondered what’s going on with a piece of code… and checked the git history only to find that I was the one who had written it, only a few months earlier!
Communicate effectively
Most of us tend to under-communicate, and even then, poorly.
And let’s face it, we developers have a pretty lousy reputation for communication, often known in the wider business for a reluctance to communicate outside our developer caves — which tend to be no-go zones for non-developers!
In-person communication is very much underrated. Instead of sending an email or message, spend a few minutes with the person.
This is not always possible with geographically-distributed teams — so on the conference call, make it a rule that everyone switches on their video. The communication is so much better.
These are just examples of starting points… the topic is big and much-researched. Do your own thinking and investigation to find out how to more effectively communicate in the environment you are in.
Manage expectations
By far most of the conflicts and issues that I have seen have been the result of misaligned expectations, and could have been pre-empted if a bit more time had been spent establishing what each party expects of the other.
This is closely linked the previous point on communication: we need to know how to ensure that the other party has understood what we expect of them, and to understand what they are expecting of us.
Document your work
Tricky one this… by observation, documentation tends to be either too much (ever seen a spaghetti-mess of hundreds of Confluence pages?) or not enough (nothing, or just links to the libraries used in the codebase).
In my view, the starting place is in the repository itself: if it relates to the code, document it in the codebase.
If the documentation applies across multiple repositories, sure, stick in a relevant part of Confluence / wiki / whatever — but also consider creating a separate repo just for the docs if developers are the sole the intended audience.
But most importantly, think of the next developer: what is going to be of most use to them as they start developing?
Test all the things
Not just code: wherever possible, apply (automated!) testing to infrastructure, devops, deployment, etc.
The mindset of testing all stages of delivery has been one of the most significant developments in the progression of my career.
Over the years, a lot of research has proven that the cost of a software bug increases exponentially the longer it remains undiscovered.
So a key aim is to engineer a development environment that enables us to find and fix bugs as early as possible.
In addition, one of the main benefits of tested code is that we end up with better code: writing testable code forces us to think about how to effectively structure our code.
And this applies to admin / utility code, not just code that is released to production: if you’ve done it more than once, script it, test it, and include it as part of the CI/CD pipeline.
CI/CD
I hesitated before including this, but… it needs to be said: crucial to modern software development is being able to automate the build and deploy process.
I’ve worked in an organisation where another developer wrote a bunch of useful tests — but they were effectively useless because there was no build process that they could be added to.
I realise this is a big topic, and there is a clear difference between CI and CD, but the concept is this: the process of building and deploying needs to be automated, and core to the standard development process in an organisation.
Choose your culture
Blame is toxic.
I’ve worked on teams where the default response to any issue is to find who to blame.
This is destructive, and demoralising for everyone.
I’ve also worked in environments where the emphasis is first to fix the issue, and then to find out how things can be done better in the future.
This does not mean avoidance of responsibility: it’s essential that someone carries the can.
But there’s a world of difference between the two types of response I’ve described above.
And remember the old adage “if you can’t change your manager, change your manager”. Life’s too short to be working in a toxic environment.
Use conventions, consistently
Here I’m talking about naming conventions — directories, classes, methods, variables, etc.
It’s a pointless waste time arguing over where the opening curly-bracket should be placed — just make sure that it’s the same across your code, so that developers working across multiple repos find consistent coding patterns.
Taking a few extra minutes to think about how you name and structure your code massively increases readability for the next developer, and reduces the need for unnecessary comments to document the code.
Of course automate these conventions, and include in the CI/CD pipeline!
And if you’re not sure, consult your peers.
Consult
Speaking of which… consult your peers!
Seriously: don’t be afraid to ask your co-developers for ideas.
You can’t do it all alone, and you should not be expected to.
Plus, you get to know your colleagues better — and work together as a team more effectively — when there is a healthy interdependence in your daily working methods.
Review
Code reviews used to make me feel insecure.
I’d be scared that every part of the code I had written was under the microscope of other developers, who were clearly better than me, and would be keen to demonstrate how.
But for years now, it’s been one of my favourite parts of development: I don’t know everything, and I actively rely on other developers having the potential to have better ideas than me.
Every day is a learning day!
Avoid code comments
If in doubt, don’t comment your code.
Hear me out.
Code comments tend to become obsolete (as the code’s functionality or implementation changes over time) and not updated (because the next developer is too scared / lazy to update them).
So a default position of not writing comments will force you to think more about how you structure your code to make it easier to maintain for the next developer.
You will then only add code comments as an exception, when they are absolutely necessary.
If you want to describe an approach taken in software development, document this in the repository separately.
Mentor others
While there is always an imperative to deliver solutions, it’s also essential not to forget about nurturing your less-experienced developers.
Firstly, you’re passing on to others the experience you’ve gained to other team members.
And secondly, you will also discover that you end up understanding something much better when you have the opportunity to teach someone else.
I have definitely found this in my teaching career: as I was preparing to teach, I discovered that I didn’t know the material as well as I thought. Having to explain it to other people, who were experiencing the subject matter for the first time, helped me really understand it.
Cross-functional teams
The most effective teams I have worked on have consisted of one or more of each the following:
- Developers (in my case front-end & back-end)
- Devops engineer (can be spread across multiple teams)
- QA engineer
- Product owner
The context was building a web application, but the crucial part is having the QA engineer and Product owner as part of the process.
So instead of developers doing some testing themselves and then throwing it over the fence to testers, QA is built in to the overall process: the piece of work is not “done” until the QA engineer and Product owner have approved it.
And the QA engineer is in close contact with the Product owner, so that the requirements are clear and up to date.
This leads to a much shorter turnaround of errors being found and fixed.
Be inquisitive
An inquiring mind is a real asset to a software developer.
How does TLS work? Apple’s Airdrop? Where is web technology heading? What are the latest developments in cloud technology?
Look at the tools you use daily, and find out more about how they work. Subscribe to relevant newsletters that keep you up to date. Monitor what’s trending on GitHub. Find stuff to ask questions about!
Get a life
Outside software development, that is.
If we want to excel in the workplace, I’m convinced we need to have totally unrelated hobbies and interests outside of work that make us buzz.
Apart from my family, mine are mountain biking and bass uke (not usually together).
What are yours?
Summary
I’ve touched on a lot of topics, each of which has had books written about them — so I have been necessarily brief on each.
It’s fair to say that most of them will cost you time up-front. But experience has taught me that they are all worth it, and you will be repaid many times over if you put them into practice.
And even if you don’t see the immediate need for some of these points, I suggest you do them anyway.
Build them into your standard work practices, and they will become the mark of excellence and sign of a quality and trusted software developer.
Further reading
- Google’s Postmortem culture
- The Basecamp Guide to Internal Communication
- What is the cost of a bug?
- The Fail-Safe Organization
- Continuous integration vs. continuous delivery vs. continuous deployment
- You Never Really Learn Something Until You Teach It
NOTE: this article has been cross-posted on LinkedIn.