cft

A Guide on Good Backend Coding Practices

Five often overlooked development guidelines to follow


user

Jimmy Soh

3 years ago | 5 min read


The importance of good coding practices is not apparent when the team is small. Over time, as the team and applications grow, I started to appreciate good coding practices to be enforced throughout the team — even at the cost of additional efforts and time.

I’ll be sharing with you on five essential practices which I found have been often overlooked when starting in a small and young team. The context will be from a backend API developer’s perspective and working in a microservice/mesh architecture environment.

#1: Validate inputs and handle errors

When your app goes live, anything can happen — a hacker may be trying to penetrate your system, or it could be users triggering an unintended use case. You would want to implement practices to validate inputs are coming into your system such that it doesn’t affect your downstream systems.

You can validate backend inputs at two levels:

  1. API gateway — the validation of inputs at the API gateway level via policies; mainly generic validation, i.e. schema, format.
  2. Microservice — the microservice level validations involve the checking of the existence of entities, etc. There are libraries, e.g. Joi validator, that you can leverage on for ease of input validation depending on your development stack.

After validating the inputs and errors are discovered, it’s crucial to handle the errors properly — especially in a microservices/mesh architecture — where many services are interconnected. As long as one of the services crashes, it can easily trigger a systemic impact; it can also cause developers a lot of effort to troubleshoot.

I’ve used a combination of two methods to handle errors to mitigate the downstream impact:

  1. Circuit breaker — prevents repeated invocation of services that are likely to fail. There are available libraries and examples for NodeJS, Springcloud, etc. which you can implement the pattern quickly.
  2. Handle exceptions with error codes — returns a response without crashing the service with a business or HTTP error code to facilitate troubleshooting.

You can reference an example of proper error code documentation below.

Image from Facebook for Developers
Image from Facebook for Developers

With proper inputs validation and error handling in place, your services will become more resilient, which reduces the need to troubleshoot issues frequently.

#2: Separation of concerns

Separation of concerns is an essential element of software architecture. With the proper separation of concerns, you’ll be able to improve the maintainability of your code — they are modular; this makes it easier for other developers to collaborate on the app which reduces the need for you to spend unnecessary time getting them up to speed.

There are various ways to structure your codes, e.g. MVC framework. The idea is to establish a “best practice” standard that works for your team. You can search online for good references on the separation of concerns and find one that works for you. I’ve provided an extract below from the link above.

Image from Programming Fundamentals Article by Ryan Kay
Image from Programming Fundamentals Article by Ryan Kay

Implementing and following a “best practice” software architecture across your team reduces barriers of entry and learning curve for your codes — which translates to overall speed and efficiency for the team.

#3: Implement health check endpoints and logging

Health checks help with monitoring the uptime of your service so that you can resolve issues quickly and mitigate the impact before it prolongs. Should health checks fail and your service gets disrupted, you’ll need to rely on logs to troubleshoot the root cause and resolve the issue quickly.

I’ll be sharing the three approaches I’ve adopted for this implementation (at a high level):

  1. Health checks (TCP) — basic health checks that ensure that your services are up and running via ping/TCP. Not very helpful as it doesn’t monitor service-level health. These services are available on most cloud platforms.
  2. Health checks (service-level) — advanced health checks that invoke your service and validates the intended output to ensure service is running correctly. Postman offers slightly more advanced service monitoring at a price.
  3. Logging — logs actions, i.e. database queries, requests and responses into a centralized log sink. You can check out some of the logging libraries and log management tools out there. There are many articles on good logging practices which you can search for online.

Having these in place will give you peace of mind after your app goes live.

#4: Implement versioning for your services

Versioning allows you to implement and test subsequent app updates while the current version is still running. When your app grows, change becomes more frequent, and having proper versioning allows you to handle those changes efficiently.

There are two ways to version your service:

  1. URL — an example would be “/accounts/v2.1/{id}”
  2. Header — included in the header as “X-Version:2.1.”

My team follows the URL versioning approach. You can find a sample illustration below.

Image from IBM Cloud
Image from IBM Cloud

There are pros and cons for each option, and it’s up to your team to decide which is better.

#5: Write test cases and documentation

In my experience, writing test cases before development helps with planning and visualizing the end product before jumping into coding; this helps with minimizing subsequent changes which contribute to efficiency. Having test cases would also allow you to detect downstream impact for any changes made in your codebase — especially when it gets huge.

Test-driven development (TDD) is a popular approach that advocates writing test cases before starting on development. While it has its benefits, it can also take up a lot of time. For critical services, it’s recommended to write an elaborate test case eventually. There are testing frameworks which you can follow with good examples on the internet.

I didn’t realize the importance of documentation until the team, and the number of apps in my team grew bigger. We didn’t have any documentation as we were churning out software quickly — it’s mostly a one to two developer show. Subsequently, development became slower because we were always reaching out to each other to clarify codes when we had to collaborate across projects. We spent a lot of time on walk-throughs and clarifications, which hindered productivity.

After trying out various ways of documenting our APIs, we have found the Postman documentation approach to be the most effective for us as most of us use Postman for our API development.

You can find a sample of the Postman documentation below.

Image from Postman Learning Centre
Image from Postman Learning Centre

Mostly, the principles of good documentation are roughly the same. You’ll have to find and adopt an approach that works best for your team.

Takeaway

Some of the benefits of these pointers may not be apparent when you’re starting with a small team of coders. I began to realize the importance of these practices when my team started to grow and had to juggle multiple projects.

It’s better to start early to incorporate these practices, as one of the main challenges I discovered was that bad coding habits are harder to change at a later stage.


Originally published on medium.

Thanks for reading and happy coding!

Upvote


user
Created by

Jimmy Soh

In perpetual beta—playing at the intersection between digital technology and business.


people
Post

Upvote

Downvote

Comment

Bookmark

Share


Related Articles