Backend developers are responsible for building the structure and logic behind all software projects. They create the functionality behind our favorite apps, maintain and improve it all the time so we enjoy them without too many glitches and bugs. But, as uncle Ben put it, with great power comes great responsibility. And because of that responsibility, backend developers find themselves under a lot of pressure, which ultimately leads to mistakes. So, today we are looking at the 10 most common mistakes backend developers make, and how to avoid them.
1. Technical debt and over-engineering
Technical debt is when developers break the SOLID and DRY rules by cutting corners, such as skipping testing or code review and refactoring. Sometimes this happens because the project is behind schedule, or it exceeded the budget. In this situation, developers take a calculated risk and push the MVP on the market before it’s ready. Unfortunately, other times, developers skip these steps simply because they forgot or think of them as a waste of time.
Other times, developers get distracted or too focused and forget about the KISS (keep it simple, stupid) principles. So, they overcomplicate irrelevant things with unnecessarily complex techniques. Basically, instead of focusing on features that affect the overall performance, or bottlenecks, they over-optimize features that are not as crucial. This results in poor performance from features that are important, and of course a bad experience for the end-users.
In both situations, the backend result is a tangled mess that developers won’t touch for fear of breaking it. Refactoring, updating, or scaling the project at this point is out of the question. The only option… rebuild.
How to avoid it
Rebuilding a project means twice the work and twice the money (best case scenario). So, the first step in avoiding too much technical debt or over-engineering your project is communication. If you are a product owner or a project manager, make sure your team understands the requirements. More importantly, a have clear and realistic list of deliverables, their priority and deadlines. Chaotic requirements such as “everything is crucial and it needs to be done by tomorrow”, will be met with chaos.
Instead, start with a simple MVP showcasing a few crucial features and grow from there. With each release, your developers have a chance to look at the next required features and figure out what technologies and strategies to use. They will also have a better understanding of what features are possible or what might jeopardize the project. This way, you add on top of what you already have instead of making changes every time you require a new feature.
If you are a backend developer, use the standup meetings to discuss your daily tasks with both your technical and non-technical teammates. You may get distracted by a non-crucial feature and overthink its solution. But, since your team is detached from your work, they can set you back on track. Always remember that you are not alone, you are not a one-man-band. You are part of a team, so use your team for the benefit of the project.
2. Improper or no testing
Testing is an essential part of the development process. It allows developers to find bugs and errors and fix them in a timely manner. While it is impossible to test everything, it is important that developers write and run tests during each stage for as many scenarios as possible. Improper testing or skipping tests altogether creates an unpredictable and unstable backend. Aside from that, maintenance is impossible as your developers will never know what is wrong and why.
How to avoid it
Write and run tests both while building new features as well as after fixing specific bugs. Use the agile mindset of TDD (test-driven development), where you build, test, fix, and only then move on. In the long-run, this will save the project a lot more time and money because you will find and fix bugs before they surface and break anything else.
Another strategy is having someone review your code. Be it a CTO, your tech lead, or other members of your team, a pair (or several) of fresh eyes is always recommended. Think of it as proofreading. Your teammates have fewer chances of getting distracted or skipping code lines because it is new to them. However, please remember that this method complements testing, not replaces it.
If a high-influence stakeholder, such as your product owner is opposing or is skeptical about testing, keep in mind, communication is the key. Invite them for a meeting with you and your project manager. Discuss the aspects of testing with them in a non-technical manner so they understand the importance of it.
3. Not reviewing code or analyzing static code
Peer-to-peer code reviews are often a part of a development company’s practices. So when a developer is ready to push a feature, the code goes to a different developer for review. This person manually checks each line, and if everything is fine, the code is pushed to the main branch.
Static code analysis, also known as source code analysis is a more automated process that also tests the code before it is deployed. Developers use tools for static code analysis that check the code against development guidelines such as MISRA and report back.
How to avoid it
First advice, trust your team, and accept feedback. Your team members have their own unique set of skills that will benefit the quality of your work. They also have different expertise that gives you insights you may have not thought of.
At the same time, there are many tools for automated static code analysis out there that might come in handy. So, together with your team, find one suited for you and your project and implement is as soon as possible.
That being said, there are situations where developers push their code by accident. So, it is important that the person in charge of approving merge requests configures GitHub (or GitLab) so mishaps like this don’t happen.
4. Technology and tools chaos
There are countless programming languages, frameworks, libraries, and tools that developers use in their daily tasks. As a consequence, each developer has their favorites and often find themselves disagreeing with one another over which technology is best for each scenario.
How to avoid it
Before starting the project, make sure you and your team all agree on a set of tools you use throughout the development process and stick with it. This is not the time to be creative or experimental.
Using too many tools or a too complex toolset will make the project difficult to maintain as the developer in charge of that will have to know all of the tech used in the development process. It will be a mess. Not to mention that the project will be unstable as some technologies simply don’t work well together. Keep it light and keep it simple.
5. No automatic backups
When talking about automatic backups, we are talking about saving a copy of the production data on a regular basis, automatically. By production data, we mean both a version of the code as well as all of the information within the databases.
However, while the code can be replicated or rewritten, user data is irreplaceable. So you understand why a partially or completely deleted database by a bug or simply human error is a massive problem. And here is where automatic backup comes in. If any of the databases get corrupted, all you need to do is restore the previous version. Yes, some data might be lost, but most of it is once again safe.
How to prevent it
Configure your database for periodic automatic backups as soon as you set the database up. But if you haven’t done that yes, you should do it now. If you’re lucky, nothing bad happened and you data is still intact. Still haven’t done it? Tell you what, go do that now, then come back to this article. It’s ok, we will wait.
Done? Good, let’s move on.
6. Not monitoring microservices
Microservices are features packed into independent code-sets that developers implement to enhance the features of a product. For example, look at the login/signup function of most websites today. Your options are login by using your email or Google account, different social media accounts, etc. Some sites don’t even require that, they allow users to signup directly using their Gmail or social media accounts.
The idea is that microservices make the overall user experience better, faster, and more secure. However, as these services are independent and most often come from third parties, developers have little to no control over them.
As a result, if a microservice is inactive and there is no alternative around it, users can’t access that specific feature. Back to our login example, if your users can only login waiting their Gmail account and the microservice is down, your users are locked out.
How to avoid it
First of all, give you users alternatives when possible. Logging in with Gmail is easier, faster and more secure. But if your users can’t access their account because of Google’s microservice, they will blame you, not Google.
Secondly, once you production environment is set up, make sure you configure monitors for each microservice. This way you will know in time when one of them is down and hopefully will be able to take action.
7. Bad data models
Data models are the first part of database design. Data modeling dictates what data is collected by the database, how is it collected and what is the correlation between each data item.
Bad data modeling affects your overall performance as queries will take a much longer time. On top of that, upgrades, and maintaining your infrastructure will be costly and very difficult in the long-run.
How to prevent it
Before the start of your project, discuss the project with your team, and create a model fit for those needs. No two projects are the same and no two data models are alike! If you skipped this step, at the beginning of your project, don’t worry. You can still fix the model after you started the project, but the more you wait the more time consuming it is.
But, if your faulty data model was already deployed, you need to update the model and write a migration script for the problematic data. Unfortunately, at this point, you will lose some information from your database, but hopefully not too much.
8. SQL injections
SQL injections are queries written by unauthorized users that are executed in the database via interconnected string. These actions give the malevolent user access to sensitive data they should not have access to.
However, SQL injection is a rather general term, as the same type of other query languages are also prone to injections.
How to prevent it
Some good practices include avoiding string concatenations as much as possible, pass parameters to each query instead. The previously mentioned code review is also a good option but also make sure your string queries are validated by a series of database users and databases. This way, even is a user tries to obtain information, their access is limited. Finally, set automatic database backups, so you make sure none of your data is lost if anything does happen.
9. Missing logs
Logs help developers in charge of maintenance save an enormous amount of time. Unfortunately, logging is not as popular with software developers as it should be. Compared to stack trace (the popular go-to strategy of developers), logging allows you no only to what and where something went wrong, but also how it happened.
If you have ever reported a bug to a developer, you know that if they can’t reproduce the error, they probably can’t fix it either.
How to avoid it
Implement a logging system for your production environment that tracks every server error. This includes timestamps, stack trace, and body/path/header requests and (if possible) IP address and username. For the development environment, each request should be logged with a full response for faster reading.
A simple system gathering basic data such as endpoint usage, timestamp etc. also gives you a statistical overview of how your system is used. But remember to redact credentials before logging them so you avoid breaches.
10. No client error details or server error detail in the API
We all know errors like 404 – page not found. These types of errors that start with a 4 are client-side errors and should have a little bit of information in them. This way developers understand fast what is the issue and fix it.
However, server-side errors, who start with 5, should not have any kind of information in them. Showing information in a “500” error exposes the system to exploitation, and it can even contain vital credentials.
How to avoid it
Everything we learned so far helps us avoid leaking information through a 500 error. Follow the good practices of development and implement each endpoint accordingly. Do proper code reviews, and finally test, test, test and when you are done testing, test some more. Oh, and make sure any 500 error comes back with a simple “internal server error message”.
We hope that the list above helped you, whether you are a developer, a project manager or a product owner. The fact is that most times, these mistakes are made because of pressure which leads to human error. So don’t cut corners, test your project from top to bottom and remember to keep it simple. Overcomplicating things or rushing them will only take you down, and soon enough you have to start over.
In the long-run, playing by the rules and good practices of development will save you time and money. But more importantly, your users’ first impression will be a much, much better one.