At Bitboundaire, we constantly seek ways to deliver maximum value in the shortest time possible. In this article, we’ll share some practices we recently applied when implementing a new feature from scratch for one of our clients. While they may seem simple, these practices have brought significant benefits in terms of organization, workflow, collaboration, and documentation. In other words, we’re working more efficiently—and delivering value more rapidly. All of this was achieved through the practices outlined below.
Design Docs: The Beginning of the Journey
Design Docs, RFCs, ADRs — call them what you will. Despite their different purposes, these formats have one thing in common: they encourage collaboration when tackling a problem. These docs help us lay out our ideas and solutions for a particular challenge and, as a result, bring us quick feedback from colleagues. Whenever possible, we try to start a feature with a Design Doc.
In the feature we worked on from scratch, which served as the basis for this article, it was no different. The starting point wasn’t a code editor, but a Design Doc in Notion, accompanied by several sketches and diagrams created in Excalidraw. But why start this way? What are the benefits?
Why a Design Doc?
The Design Doc served several purposes for this feature (and others as well), such as:
- Sharing and Validation: We shared the implementation idea with colleagues to gather suggestions and validation. Are we heading in the right direction? Is there another way to do this? Is all of this necessary? Are we forgetting any factors? All these questions can be addressed during the review of the Design Doc by the team.
- Deep Thinking: It’s common to believe (irrationally) that we already have a nearly complete solution in our heads and can just proceed. However, almost always, we later realize the solution we jumped into was shallow and missed many edge cases. Writing the solution in a Design Doc forces us to think deeply about the proposed approach, leading to a more robust implementation.
- Initial Planning: The Design Doc doesn’t just cover the technical side of a project—it also helps align expectations around deadlines and milestones to be achieved during implementation.
- Dynamic Documentation: We use the Design Doc space to centralize decisions and track changes made throughout the implementation and maintenance of a project. This way, it’s possible to understand the entire project in one place, avoiding discrepancies between the doc and the actual implementation.
This brief (and non-exhaustive) list of benefits from writing a Design Doc before implementation highlights an important idea: documentation shouldn’t happen only at the end of a project, but throughout the project. Personally, I believe in this approach and have always had better experiences when applying it. That’s why I always prefer to start a project with a Design Doc.
But what format should we follow when writing this document?
How We Did It
The format of a Design Doc isn’t set in stone. Ideally, it should fit the needs and reality of each company and team responsible for creating the document. Here at Bitboundaire, within my team and for the specific project that inspired this article, this was the format we used:
- Context and Scope: A brief description of why the feature is being developed and its main objectives.
- Goals and Non-Goals: A clear definition of the feature’s scope, listing what we intend to solve and also what falls outside the project’s scope.
- Technical Design: Architectural details, focusing on the initial design, the new design, service layer, API layer, and the overall implementation plan.
- New Requirements: Sections added later to document solutions and adjustments prompted by new requirements.
- Supporting Material: Useful links to dive deeper into the project, the proposed solution, and the tools mentioned in the document.
- Open Questions: A space for reader doubts and comments. However, since we used Notion to write the document, this section became obsolete—Notion allows readers to comment directly on any text section, making questions more dynamic and contextualized.
Again, this format is something we shaped based on our team’s specific reality. After seeing the structure we used, you might feel that some sections are missing or that some aren’t necessary for your context. That’s totally fine. The key is to adapt your Design Doc to your own team’s needs. However, regardless of your format, there’s one thing I highly recommend: include diagrams. They’re incredibly powerful!
Diagrams: A Visual Perspective
One action that significantly improved the quality of our Design Doc was adding diagrams whenever we felt they were useful. These diagrams made it much easier to communicate the ideas we wanted to convey, offering a clearer view of flows and system components. Below is a (non-real) example of the kind of diagram we included.
It’s important to note that diagrams, while helpful, don’t replace the need for supporting text. Fully understanding a diagram without written context is difficult. That’s why we followed this simple approach for diagrams:
- Contextualize the image
- Present the image itself
- Add a brief explanation about the diagram
By combining text and visuals, we clarified many complex concepts and ideas within the project. This significantly improved reader understanding and, as a result, increased the volume and quality of feedback we received, which is extremely valuable to us.
Rapid Feedback: Refining the Implementation
The Design Doc phase provided fast and valuable feedback—both technical and non-technical. Colleagues helped identify issues like circular dependencies and suggested interesting improvements to the API layer design. This feedback saved us many hours of rework and strengthened the project’s “final” design.
Beyond technical input, we also involved the product team in reviewing the Design Doc, making the content accessible even to non-engineers. This led to great suggestions and thoughtful questions that positively influenced the implementation.
After a few iterations on the Design Doc, we ended up with a much more robust solution than the one we initially proposed, plus a clear implementation plan covering everything from the API layer to the database.
However, the implementation details aren’t the focus here. What really matters is the strong collaboration we had during the implementation phase, which we’ll dive into next.
API Layer: Coordination Between Backend and Frontend
Implementing the API layer can often seem simple, especially for the backend engineer. However, it can easily become a project bottleneck. Often, this bottleneck isn’t even perceived by the backend team, who may believe their work is done once their code is deployed and the frontend engineer has been notified that integration can start. This type of handoff is very common but far from ideal. For this project, we focused on two key points to prevent integration from becoming a blocker.
The Backend Coordinates
One of the biggest mistakes when designing a backend solution is assuming that small logic details can be left for the frontend team to handle. This approach is one of the main reasons for frontend delays and codebase issues. Even if the logic seems minor, passing that responsibility to the frontend means delaying the implementation of other screens and components.
For example, when we decide — often unconsciously — that the frontend will build the text displayed on screen X, we’re effectively choosing to have them spend time on that instead of progressing on screen Y or component Z.
Also, it’s worth emphasizing that the backend typically finishes its part before the frontend does. By taking on more of the logic, the backend can help close this gap and reduce delays. When the frontend is burdened with additional logic, the gap between backend and frontend progress only grows.
While I say the frontend “lags behind,” the truth is, so does the backend, because until the frontend is done, the project isn’t done. Nobody wins, everyone loses.
That’s why the API design for this project was fully focused on providing responses that were ready to be displayed on the frontend, with no need for extra sorting, filtering, text construction, or business logic. This allowed the frontend team to focus purely on building screens, components, and integrations, which we also worked to make as simple as possible (as you’ll see next).
Integration Documentation
Our project uses GraphQL in the API layer. It’s a great technology but can bring challenges for frontend integration. Among the frontend developers on my team, there’s a consensus: integrating with GraphQL tends to be more complex and time-consuming than with a RESTful API.
To help with this, we aimed to reduce friction and prevent integration from becoming a project bottleneck.
We addressed two common problems that usually slow down frontend integration:
- Uncertainty about which fields to fetch from the GraphQL API: Many backend developers think their work ends once the code is deployed, leaving the frontend to build the GraphQL query that best fits the screen. But this task carries a lot of friction for frontend devs, who don’t have the same backend context or the right tools to identify the ideal query. As a result, they lose time on something the backend could prepare in minutes. This often leads to overfetching too.
- Uncertainty about where each returned field should appear on the screen: Frontend devs frequently report confusion about where each field from the backend response should go. While this is usually straightforward for simple queries, complex screens with multiple nested fields can create significant confusion and slowdowns.
To tackle both issues, we applied two simple but highly effective actions:
- We built the query for the frontend: Based on the screen preview shared with us, the backend team—especially the dev who built the feature—assembled the query, including all necessary inputs and fields. This took just minutes and saved hours on the frontend side.
- We created an integration diagram: To help the frontend team understand exactly where each field belonged, we created a diagram showing two elements: the screen preview and the corresponding query. We then drew arrows linking each field to its correct placement on the screen.
These small steps led to much faster backend–frontend integration. They also encouraged quicker communication. When the backend provides a fully prepared query, any errors are clearly on the backend side, making frontend devs more comfortable reaching out for clarification. If the frontend had built the query themselves and ran into errors, they might hesitate to escalate the issue.
Gradual Implementation
It’s also important to highlight how effective gradual delivery is compared to a “big bang” launch where everything ships at once, risking a flood of issues right before go-live.
Gradual delivery allowed us to gather feedback in manageable waves, preventing an overload of feedback and bugs all at once. This short cycle between implementation and feedback was key for us. It helped us work faster and reach the final launch phase with no last-minute surprises.
Conclusion
By following all the practices described in this article, we achieved an excellent delivery pace for this project—moving from zero to project validation in just seven working days.
Personally, I believe that a major reason why we developed this feature from scratch without major friction or surprises was our focus on simplicity:
- We simplified the Design Doc
- We simplified the API layer
- We simplified value delivery
Simplicity boosts collaboration. Collaboration boosts speed.
Hope you enjoyed this article. Thanks for reading this far — that’s all for today!
What’s your opinion on the subject? Comment below!