When writing code, we can fall into the trap of only caring that it works and does what it’s supposed to. But this is only the beginning of a broader set of goals we should consider every time we sit down to program. By clearly structuring our code, we contribute to its scalability, help our teammates, and even help ourselves when we revisit it a few sprints later.
Saying that code is “solid” often depends on the context and the business reality. The bar is undoubtedly lower if we know that our code requires minimal maintenance or doesn’t need to meet high-quality standards. Being a software engineer at Ensolvers also means understanding that the code we write often impacts thousands of clients or businesses, so the level of impact demands a holistic view.
Writing unstructured code may not seem like a big deal at first, but when the codebase needs to grow, it becomes very clear whether there was a planning phase, or if the project was developed improvisationally—some insights, like weird side effects, spaghetti code, or untraceable errors.
After many behavioral changes in one of our customers’ email template generation features, we ended up with a weak structure, complete with interconnected services—each with deprecated functionality—and a web of spaghetti code that made maintenance nearly impossible, despite having test suites in place to verify behavior.
Due to the many AI-based composition strategies we had implemented, there were at least five different code paths, spread across several services, that were essentially doing the same thing: composing the email template with HTML.
A requirement led us to change the behavior of the feature, which rendered most of the existing code obsolete. So, we took the opportunity to rethink how we structure our code.
With this restructuring in mind, we had the chance to plan and properly design all components and processes involved in the feature—this time with a clear direction and the experience gained from previous business iterations.
The general process was pretty straightforward: we needed different components, each responsible for a specific task in the overall composition workflow.
We wrote a component dedicated solely to handling information gathered from the user, so we could process initial data and transform it into meaningful input for email composition.
For each task involving data collection and processing in our workflow, we created a component to centralize the effort of retrieving, processing, and handling information from external sources, whether via scraping user pages or processing with LLMs.
Another component was responsible for building the prompt used in the LLM processing. This ensured that all prompts came from a single source of truth, making this part of the process easier to test, modify, and understand. This was especially valuable, as the previous version had prompts scattered across the codebase.
We also created a component that, based on both user data and external service data, composed the final content to be used in the email templates; this helped us reduce the high coupling between components.
The results were impressive: we reduced processing and email composition time by 80%, which allowed us to save hardware resources. We no longer need as much memory to store data or as much computing power to handle it.
The improvements weren’t just computational. Interactions with LLMs became significantly faster and more structured, while also consuming a fraction of the tokens compared to previous iterations. This enabled us to compose more email templates that deliver impact and value to our clients, while also saving money.
In terms of code quality, making changes is now much faster and more feasible because we know exactly how data flows through the system and what responsibility each component holds.
Having a solid code structure makes it easy to quickly understand what our software does and how it interacts with other components and services. Maintaining strong structures is vital for delivering robust, impressive solutions to our clients.