There are tons of these type of articles out on the internet. Articles that explain “How to get started developing with Framework XYZ”.
Unfortunately, none of the Odoo specific articles have gone into enough detail for me or my team to really learn about an ideal day to day workflow. There are plenty of explanations on how to create a sample Odoo module. Then there are forum posts with documentation about more technical topics like framework extensions, frontend widget development, security rules, etc.
Coming from other programming environments, even other python environments, it’s not perfectly clear how to take a group of developers, stick them in an office together, and be productive while building Odoo based systems.
How should projects actually be organized within the git repositories so that each developer can work on what they need to? When dealing with dozens or hundreds of instances, how should each developer manage their local environment? Etc.
Here is a (hopefully) in-depth explanation of my day to day as an Odoo developer working with other Odoo developers and how we work together to get code pushed out to clients. I’ll provide as much context as possible because we have certain systems and processes in place now that may not be obvious.
Coming into the office every morning, I usually grab some coffee. Caffeine should be a requirement for working with Odoo every day. You have to be prepared for the days where Odoo decides that none of your XML is valid and won’t provide good error messages to explain why.
But afterward, I try to spend at least 30–60 min checking our systems. By systems I mean:
- Email (Gmail)
- Google Calendar
- Project Management (Odoo Tasks)
- Pull Requests (Bitbucket)
Each system has a different responsibility for our team. Email is primarily an interface between our team and the clients. Slack is our internal communication system to chat with each other. Google Calendar acts as our agenda items. Project Management defines and prioritizes work for each developer on the team. Bitbucket contains all of the source code that we write. We use a Pull Request workflow to move code from development to staging or production environments.
We’ve gone back and forth on these sort of meetings for years. We initially tried to do stand up meetings.
I guess just because that’s the norm. After a while we asked ourselves “what is the point?” and that’s the only answer we could come up with. Eventually, we couldn’t stand behind responses like “it helps bond team members” or “it increases transparency”. All it did for us was waste 15–30 minutes of everyone's time in the morning.
The meeting didn’t only waste the time we spent physically in the meeting. It also lowered productivity. Some people are deep into a project or task by 10 am every day. So it takes time to get a few notes together right before the meeting, it takes time to stand in a circle listening to things that you probably already heard about the day before, and then time to get back into what you were doing before the meeting started.
Stand up meetings may work for some teams, but we have 5 developers on the team at the moment, we all sit in the same room, we all talk to each other almost every day, we spend time in meetings with each other, so we roughly know what’s going on with each other week to week.
So we decided on a daily check-in virtually instead of standing up in a circle:
Every morning, between 6 am — 10 am, each team member will post a short sentence or a list of what they have going on for the day into a general slack channel. If they need anything they’ll throw out a question.
This lets each person work on their own time because they can type up their check-in when they are available and read other responses when they are available.
Along with our virtual daily check-in process, we introduced a weekly meeting called a Tactical Meeting.
This term was taken from Holacracy. They describe it as:
Tactical Meetings are focused on the operational work of the Circle. Their purpose is to triage issues that have come up during the week and remove obstacles so that the work can move forward. Each circle conducts tactical meetings; they occur roughly weekly and are scheduled by the circle’s Secretary.
The formal output of Tactical Meetings is Projects and Actions, but they can be used to address any operational need: sharing information, giving updates, requesting projects and actions from other roles, etc.
This is essentially how we treat them. Our meeting happens every Friday at 11AM, replacing our daily Slack check-in on Fridays, and could be described as:
- A 45-minute meeting with the entire team
- Check-in and high-level status update from each team member
- Discussions on individual blockers and how to resolve them
- Discussion on project-wide blockers and how to resolve them
- Potential improvements for the entire team
- Items that team members have learned that week or want to focus on learning
This gives us a concise forum to primarily focus on team-wide issues and improvements. It still has some of the same downfalls as a stand-up meeting except that it only occurs once a week and is relatively short compared to the cumulative time spent on daily meetings.
After the morning ritual of getting prepared and checking in with the team, developers are usually plugging in their headphones and writing code.
Here’s a little bit of context on how our code is organized. This is not exactly normal compared to other environments or projects.
A repository per client
All of our code is stored in Bitbucket. As a company, we work with clients who typically have unique environments so each client gets their own repository. This provides a clean separation of concerns. If you were to pull up our repository list, it would look like:
A set of Odoo addons
At the core of each repository, it is essentially just a list of addons. This is similar to what you would see with a standard Odoo repository, just like any of the OCA repositories.
We also keep quite a few additional files in the root of the repo and in dot folders which help us develop day to day.
Generally, we only want to track custom addons that we are developing.
We even keep 3rd party addons separated out into a
_lib folder which is not tracked in the repository. This folder is ignored in the
file, and then we have developed an internal dependency management system that allows us to run a simple command
$ om setup dependencies
This command will download the latest versions of the 3rd party addons which the project relies on and
place those with the
/client_a_addons _lib/ account_due_list/ project_stage_closed/ project_role/ project_task_code/ custom_addon_a/ custom_addon_b/ custom_addon_c/ docker-compose.yml # container configurations requirements.txt # python requirements to run the project __manifest__.py # module dependency requirements
Every one of our repositories has what it needs packaged inside of it so that a developer can simply clone down a repository, run a script, and have a localized instance of the project to work with.
We do this using Docker, Docker Compose, and custom scripts. You’ll see these described in the workflow section below.
We also define our own configuration files in each project to pull in external dependencies for the project. By dependencies here, I mean outside Odoo modules such as OCA modules. These are automatically downloaded.
Quick side note on some tools. Every developer on the team uses whatever tools they are comfortable with. So you’ll see a variety of things like the following in our office:
- Sublime Text
- VS Code
The standardization of certain development tools can slow people down and generally just piss people off.
The Initial Setup
Because of the Isolated Environments that I described above, it makes setup extremely easy. We do not need to worry about the underlying OS very often and each developer on the team can run any project on their local machine despite the Odoo version or external dependencies because of Docker. We also do not run into conflicts between projects on a single machine.
So the initial setup when Tom The Developer needs to setup Project A will look something like this:
$ git clone firstname.lastname@example.org:mycompany/project_a.git $ cd project_a $ ./make.sh $ docker-compose up -d # Now the project has built and is accessible locally. Typically we # will run on http://localhost:10102 but this changes depending on # the project environment variables.
Data is tricky and we do not have a completely streamlined process.
When a developer gets initially setup, they will have a brand new Odoo instance running with all of the custom functionality needed, but no real data. So depending on the situation and project, one of a few things happens:
- If the developer has access, they can download a copy from a Staging environment and upload the database to their local.
- If the project has a robust set of demo data/sample data configured in a module, then that module can be installed instead.
- Simple data can be manually created as needed depending on the functionality.
No project should have a hard dependency on a certain set of data or a specific database. So we try to develop our modules in a way that they have everything that they need packaged up within the module, and if they have hard dependencies on certain configurations then those are enforced within the module as well.
So now that we’ve covered some of the context about how our code is structured, the tools that we are using, and how our developers get up and running with projects, you can see how we actually work on tasks day to day.
1. Pick up a task
As I described in the beginning, we have project management system with a set of tasks. We happen to use Odoo internally, but development teams typically have some sort of system in place (Jira, Asana, Trello, etc.).
Each developer has their task list, with estimate hours, client comments, requirements, attachments, and anything that they need to get the task done. Once developers get settled in for the day, assuming they have no meetings or phone calls, they pick up a task off their list.
2. Write the code and tests (in the order that works for them)
Then they’ll start working.
If it’s a task for a new project, then they may need to clone down the repo, build the project, and run it first, otherwise, they’ll pull up their existing instance and start working.
We currently, roughly follow a feature branching pattern. This lets us assign a git repository branch to a task/feature number.
git checkout -b feature/11425/add-a-cool-new-feature
Adding the task number from our project management system helps us track what’s going on with certain tasks.
After checking out the right branch, the developer will either write automated tests for the task, watch them fail, and then start writing the code to correct those tests (a standard TDD process). Or they’ll do the opposite and write the functionality, manually test it in the interface, and then write the automated tests to confirm. This is up to the developer depending on how they like to work.
3. Create a pull request
Once the feature is ready to code, the developer will make a pull request from their feature branch into a
developmentbranch on the repository. Some of our projects have multiple version so it could potentially be a
4. Two team members review and approve the pull request
Two developers must review and approve each pull request. So randomly throughout each day a developer with go through the open pull requests and ensure that the code is high quality. Generally, we look for the code to match our style standards, to be performant, to be readable, to be secure, to be maintainable, and to meet the customers’ requirements.
Our repositories are also linked to a continuous integration server called Drone, where our tests are automatically run. This allows developers to easily see if anything could cause an issue even before reviewing and manually testing the code.
5. The pull request is merged to a
Once the PR (pull request) is approved, then it’s merged!
The code now lives in the development branch where it can be deployed out to a server.
is deployed to staging
Depending on the project, the code is either automatically deployed out to a certain server via a continuous integration process or a developer manually deploys code to a staging server (almost always this for us at the moment).
These staging servers are typically accessible by the customer and we work with them to approve features for production.
7. Code is eventually merged to
when a release is identified
Identifying a proper release candidate can be somewhat random, but once we have a set of features that we
feel are ready to be released to production and a client has completely approved/validated, then we’ll
merge the current dev branch into a
masterbranch for release.
is deployed to production
Then finally, the same process for staging is utilized for production. The code is released to the production server for the client to utilize in their live system.
Analysis and Troubleshooting
Writing code can be frustrating at times, but it helps to have other developers around. Generally, most of us try to not bother the other developers on the team unless we must.
Breaking another person’s concentration can really throw them off for a while. This makes it harder on everyone, especially if you depend on someone’s work for your deadline, but we also don’t want people sitting around for hours or days completely stuck.
Using a specific time limit can help to create a balance between these two scenarios. We generally tell the developers to not allow themselves to be blocked for more than 20–30 minutes before taking a break, talking to a rubber ducky, or asking another developer for help.
So when developers need help they can often put their questions online somewhere (in project management or in a chat tool like Slack), where each developer can check it on their own time.
We can of course just walk over and quickly hash things out if there’s a bigger question to answer, like if two developers need to debug or work on a problem together, or if there is an emergency.
We try to just lean on common sense as much as possible instead of pages of exact procedures.
Long Term Planning
Lastly, we’ll do some longer-term planning as a company each quarter. This lets us take a day every few months and think about some long term goals we have as a team. These could be an improvement to our internal tools/toolset, new processes that we want to put in place, or ideas on how we handle client work. Anything that makes us better as a company or as individual developers.
I’m sure there are dozens of other small things that we do as a team that I’m leaving out of there. Writing code involves a huge amount of moving pieces.
Thanks For Reading
I appreciate you taking the time to read any of my articles. I hope it has helped you out in some way. If you're looking for more ramblings, take a look at theentire catalog of articles I've written. Give me a follow on Twitter or Github to see what else I've got going on. Feel free to reach out if you want to talk!