20. Dec 2022Backend & DevOps

How we build our backend tech stack on proven yet future-proof technologies

At GoodRequest, the combination of quality, stability and modern procedures is important to us, and we build on this in our technology stack. Over the years of our experience on the backend, we have tried several technologies, so we know how important their selection is.

Matej DugovičBackend Developer

Each new piece is first followed by hours of analysis and discussion. You don't choose a particular technology for life, but no one in the team wants to find out after a few months that it doesn't quite suit us and we have to look again for something better.

Every technology or innovation must go through a strict sieve, where we first tell ourselves what will improve us compared to the current situation, what are its limits, how is it supported and what will be the costs of including it in our stack.

If it survives the comparison with other available alternatives, it will still face criticism from team members.

Behind each new piece, there are first hours of analysis and discussions, the core of our applications has been a proven Node.js (Express.js framework) server or a memory layer in Redis for years. TypeScript is a matter of course, we can't imagine a world without it.

We try to have an expert in our team for every area, whether it is architecture, databases and security or optimizations, who is constantly learning about the topic.

Databases

For data storage, we most often use relational databases, namely PostgreSQL. When the situation or the client requires it, we also have experience with, for example, MySQL or MariaDB.

PostgreSQL suits us best with its functions and speed, we already have experience from larger projects on how to get the most out of it with the correct configuration, models and indexes.

Of course, it's not always enough, and then we help ourselves with memory storage in Redis, which is ideal for short-term data storage.

When it comes to a quick search, we use ElasticSearch to help us, into which we transform data from main databases, for example, using the PGSync plugin. In specific cases, we consider whether a NoSQL database like MongoDB is more suitable for some part of the application.

Security

We regularly update the main technology stack, as well as the used libraries, not only for new functions, but mainly for bug fixes and security patches. The Renovate bot notifies us of new versions, which automatically creates descriptive pull requests directly into the code. But we always check each change.

It is important to think about the security of the code already during development. A useful guide to what the most common vulnerabilities are is the OWASP Top 10 ranking.

The basic things that should not be missing in any project include handling of HTTP headers using the Helmet library, the Joi library for input validation, and the ORM library for protection against SQL injection, which will also take care of the treatment of dynamically inserted parameters in raw SQL calculations.

Development

Eslint helps us monitor the quality of the code, as well as some security risks.

We use JWT tokens for user authentication, which we use either with the OAuth standard, LDAP, identity providers or, for example, when logging in via social network accounts or Apple ID.

First of all, we try to reach first for active and proven solutions that have already caught flies and are tested on several production projects, but sometimes even those are not enough for us or we come up with significant improvements.

As part of the innovation platform, we develop our own tools that are tailored to our quality requirements across projects - be it optimization, implementation of new technologies, our own libraries or improvements to the ones we use.

In addition to the author, the changes are checked by another colleague in code review, and the new code must successfully pass tests in CI / CD before being published. We make sure that each of our projects is covered from the beginning with unit and integration tests that increase the quality of the delivered products. In cooperation with colleagues from the front end, we also prepare End to End tests.

We then package the finished version of the application in a Docker container and deploy it on our server or, thanks to the containerization technology used, conveniently on the client's infrastructure. We then solve the orchestration of containers and their scaling via Kubernetes.

 

Third Party Services

We monitor application errors via Sentry and more advanced logs, behavior and performance via New Relic. If it concerns sensitive data, we can also integrate these services into our own infrastructure.

We also have extensive experience with third-party service integrations, for payments we have experience with eight payment gateways, such as PayPal, 24Pay, SMS payments, mobile payments for Android and iOS.

We use Firebase for push notifications to apps. If we need to manage regular tasks, we use the BullMQ task queue, and RabbitMQ for a more complex system, for example when communicating between multiple services.

For some projects, we also use AWS infrastructure - for example, virtual servers in EC2, for storing images and files, and S3 or CloudWatch for monitoring and more.

Matej DugovičBackend Developer