When we talk about programming in Odoo, we are directly talking about the creation or modification of modules. It is the cornerstone on which the Odoo ecosystem is built, and that is why the correct management of them must be a fundamental task. In this article, we are going to talk about good practices and how we at Dixmit consider a good module structure, so that it is sustainable in the long term.
Beyond what the structure of Odoo modules is like, which we all already know, we want to talk about their content.
What Should We Keep in Mind?
Follow the existing development approach
First, it is advisable to follow the nomenclatures defined by Odoo and divide the development into files according to the model it affects. On the other hand, we must always check that what we want has not been done before, such as the creation of a field, or that there is something we can reuse. We should also break down the code into methods with an action as specific as possible so that it can be reused in the same module or in future modules, and also make use of as few dependencies as possible.
In our case, if a module starts to grow, we usually break it down into smaller pieces so we can manage it more atomically and in a more controlled way. This allows us to better reuse the functionalities. Additionally, it is essential to extract generic functionalities and, when possible, contribute them to an OCA module. For example, if we are asked to add five new fields to contacts and two of them make sense beyond this implementation, we create an OCA module containing that specific functionality.
Tests
Next, we must take seriously two vital aspects of development that determine the quality of a development: the creation of tests and documentation. Testing development is a separate task, not essential but highly recommended. And by focusing on it and developing a good set of tests, on one hand, the module will be more robust and therefore maintainable in the long term, and on the other hand, we will ensure that we have correctly understood and implemented the module. With good testing, we could even make sure we understand what the module consists of just by looking at the tests. In addition, since it is a separate task, it should also involve good development of the test code and documentation for it.
One detail that has saved us during more than one migration: we always add tests for the “invisible business rules”—those not obvious when looking only at Python or XML. For example, validations depending on dates, intermediate states, or rounding behaviour. These tests serve as a historical contract and prevent regressions when, four versions later, we no longer remember why something was implemented a certain way.
Documentation
As we mentioned earlier, documentation is another of the pillars for making a module maintainable in the long term, and just like tests, special attention must be paid to its development—not simply writing a brief description, but explaining and making clear the purpose of the module, the need it covers, what it is composed of, possible implications, an explanation of its use, its installation, future aspects, deficiencies found and still to be resolved. That is, everything that allows us to understand the structure of the module and its context, since to ensure the correct maintainability of the module, we will have to keep reviewing its functionality and its contextual framework.
A common issue we have seen in older projects is relying too heavily on oral knowledge: modules without a README, or with one that explains nothing. At Dixmit, we always try to keep the README properly updated. Moreover, all changes are tracked in the version control system, allowing us to see when each change occurred and the discussion surrounding it.
Be Careful with JavaScript!
As an extra tip to make your modules maintainable in the long term, it is advisable to reduce the amount of JavaScript code to the minimum possible and use other substitute tools. This is because JavaScript code changes a lot between versions and migrations are more costly, making its maintainability in the long term more difficult. In any case, starting from version 18, if you choose to write code with OWL and JavaScript, you should implement tests that help you maintain it, as we have already explained.
We’ve learned this the hard way: modules with custom JS in Odoo 12–14 were the most difficult to migrate to OWL. That’s why we now follow a clear rule: if a feature can be solved with views, server actions, commands or backend configuration, we avoid JS. And if we write OWL, we always include component and snapshot tests.
Conclusion
At Dixmit, we encourage you to follow all these tips and never neglect the proper management of modules. It is also advisable to follow the OCA's good practices guide, as it consists of guidelines agreed upon by the top Odoo development experts and can ensure that a module is sustainable in the long term.
Sustainability is not achieved through magic tricks, but through small daily decisions: not mixing responsibilities, documenting why things are done, writing tests for anything that might break, and avoiding unnecessary dependencies. This philosophy is what allows us to maintain modules that started in Odoo 11 and still run in Odoo 18 today without major issues.