Quality Approaches When Developing a Product: How We Avoid Engineering Struggles

Valery Kashentsev
Manychat Tech Blog
Published in
6 min readJul 7, 2023

When it comes to developing a product, the pursuit of speed often leads to compromises in quality. It’s no secret that companies must quickly test hypotheses and make rapid decisions to stay ahead in a competitive global market. This can lead to certain difficulties, including the lack of scalability, and the necessity of refactoring that engineering teams don’t have time for.

Hi! My name is Valery Kashentsev, I’m a backend engineer at Manychat.

Manychat started seven years ago with a few passionate engineers. Today, it has grown into the leading Chat Marketing platform, and Meta’s official business partner. With more than 1 million users worldwide and powering 1 billion conversations each year, ensuring the high quality of our product is paramount.

So, let’s explore the development approaches we use at Manychat when releasing new product functionality. These are the principles we have refined over the past few years, that ensure high product quality.

What’s quality?

Let’s begin by defining what we mean by “high product quality”. At Manychat, we don’t solve abstract problems; we focus on helping our users achieve their goals, like increasing sales, or automating customer service. Therefore, any feature we release should directly contribute to helping our users reach their objectives.

With this in mind, it’s essential that new features should be easy to understand. Through the automation provided by our platform, we aim to relieve our users from routine work, giving them more time to dedicate to business development. And we don’t want them to spend hours trying to figure out how a new feature operates.

From a technical perspective, any solution should be developed while considering its compatibility with high-load systems requirements. It must use queues where necessary, and be scalable and reliable. And of course, it must work properly with no bugs.

Under the hood

Manychat is a platform that helps businesses engage with their customers via different channels: Instagram Direct Messages, Facebook Messenger, and WhatsApp.

So, we work with third-party platforms… a lot! It’s not just Meta products, but also payment processing platforms, CRM systems, and more.

It’s crucial for us to respond quickly to any changes and seamlessly integrate with them quickly and efficiently, so we need to stay flexible and adaptive. That’s why we use LeSS (Large Scale Scrum).

We work in cross-functional teams and in two-week sprints. In each team, there is a product designer, two frontend, and two backend engineers. This approach lets us solve almost any task within the given time frame.

Plan twice, develop once

We firmly believe that proper planning prevents poor performance. So, we dedicate a significant amount of time to a planning phase and hold at least three meetings to define what and how we will code in each upcoming sprint.

It starts with the Product Owner, who presents an idea or a problem to the teams. During the first meeting, we don’t talk about code at all. Instead, we discuss the proposed product solution and the basic methods for its implementation. This collaborative discussion allows us to estimate the necessary time and define acceptance criteria.

Given that we often have several teams working on the same part of the product, at the Sprint Planning 1 meeting their representatives get together to discuss which task will be included in the sprint. This ensures transparency and clarifies responsibility areas of each team member. This approach also helps us identify potential dependencies and roadblocks before we start.

Following Sprint Planning 1, each team conducts its own Sprint Planning 2 meeting. Here, we deconstruct the tasks into smaller technical parts, define the sequence of our actions, and plan technical implementation. This careful planning helps us avoid blocking issues and ensures seamless coordination between team members.

Team Testing

We don’t have QA engineers; instead, each team takes responsibility for testing their own implementations. Firstly, it provides an opportunity for knowledge sharing and gaining an outside perspective.

Typically, only one frontend and one backend engineer work on a specific task, while other team members may not deeply understand the context. Team testing lets everyone in the team stay involved in the process. Most importantly, this approach helps streamline the delivery of value delivery to users, as teams can plan testing and deployment independently.

We test both in development/staging environments and validate on the production after deployment. In cases where there is a risk of potential issues, we also perform testing in local environments.

Before testing, we create a comprehensive document that includes all testing conditions, such as a list of feature flags, and the number of frontend builds, along with test cases that specify user actions and the expected results. Typically, the person who worked on the task prepares this document, as they possess a better understanding of potential risks.

Initially, we test new features in the development environment. This phase often reveals bugs, which we promptly address and fix.

Once everything works as intended, we roll it out to production. To ensure thorough testing without causing disruption to users, we use feature flags. Then we test new features from our Manychat accounts by opening feature flags specifically to them.

After conducting thorough checks in the production environment, we move to the final stage of bug fixing and open up the functionality to a group of users or eventually, to all users.

Here is an example of instructions we follow while testing:

If we discover bugs, we fix them before releasing the feature into production. Sometimes we bump into the bugs that are not related to the current task. In such cases, we promptly address these issues or add them to the backlog for the Product Owner to prioritize.

While we strive to provide the product solution within one sprint, there are certain tasks that require more time and effort. These are known as epic tasks. Sometimes, multiple teams collaborate on these tasks across one or more sprints. To ensure their successful implementation, epic tasks are always decomposed.

The larger and more complex the epic task is, the more important it is to thoroughly check if everything works properly. In such cases, we do epic testing. We hold a test day: Representatives from the teams involved in the epic development get together to test the feature extensively, intentionally trying to break the application to identify any vulnerabilities. As a result, we get a comprehensive list of identified bugs. These bugs are then prioritized based on the company’s goals and objectives. Critical bugs are fixed immediately, while other non-critical bugs may be added to the backlog for resolution at a later time.

Quality Checklist

When implementing any new feature or solution, we stick to a comprehensive checklist that is called “Definition of Done”. This checklist applies to every task, regardless of its size or impact on the product.

The checklist is important as it ensures everyone understands what is a desired outcome, and establishes criteria for determining when task is considered properly completed.

It includes the following:

  • Code is written and aligns with our established agreements.
  • Code review has been conducted and successfully passed.
  • Design review has been conducted and successfully passed.
  • Autotests have been written.
  • Code has been released into the production.
  • The solution has been finally team tested in the production.

Each team follows the checklist to ensure the solution they provide performs its intended functions correctly using optimal resources, its interface is clear and intuitive, and it operated stably with no bugs.

Do good things, avoid bad things

These approaches may appear obvious to larger engineering teams. However, we learned them through trial and error, and I hope outlining our approach will also help other small and growing teams in making fewer mistakes and delivering higher-quality solutions in production.

To avoid sounding like a wise man on the mountain, I must acknowledge that we are not immune to bugs or user complaints about recurring errors. However, our quality approaches have played a significant role in reducing the occurrence of such cases. As a result, our developers now encounter fewer engineering struggles in their day-to-day work.

In product development, our responsibility extends beyond mere release of new features. Next time, I will share quality approaches we use after releasing new features and solutions. (Stay tuned!)

In the meantime, I’d love to hear about the approaches you use to ensure high quality of your products.

--

--