FckVer: A Practical Versioning Strategy for Odoo
Disclaimer
This article contains profanity. The naming is intentional. The idea started from a long debugging session with Odoo's module versioning. If you don't appreciate the name, feel free to rename it internally.
The Problem
Odoo has a single version field inside __manifest__.py.
{
"version": "18.0.1.0.0",
}
Simple?
Not really.
That single version is expected to represent several completely different concepts:
- application version
- module version
- migration version
- deployment ordering
- upgrade detection
In reality, these are different things.
Coming from ecosystems like Django, Rails, Alembic, Flyway or Liquibase, this felt strange because those ecosystems separate:
- application release
- database migration
For example:
Application
v2.0.0
Database
Migration 001
Migration 002
Migration 003
Nobody tries to squeeze both into one version number.
Unfortunately, Odoo only gives us one.
Our Development Workflow
Our company does not have disposable development databases.
Instead, we have:
Developer
│
▼
Shared Development Server
(real company users)
│
▼
QA
│
▼
Production
The shared development server contains real data.
Sales use it.
QA uses it.
Project members use it.
Because of that, every deployment to this server becomes part of the database history.
That immediately breaks many traditional versioning assumptions.
The Problem with Semantic Versioning
Semantic Versioning asks questions like:
- Is this a major change?
- Is this a minor feature?
- Is this a patch?
Our team had a different question:
"We deployed a new build to the shared development server. Which number do we bump?"
Semantic Versioning doesn't answer that.
Odoo documentation doesn't answer that.
Different Odoo teams even interpret the five-part version differently.
Eventually we realized something.
We weren't trying to version software.
We were trying to version our deployment lifecycle.
Introducing FckVer
FckVer (Fuckantic Versioning)
Because sometimes software engineering deserves an appropriately named versioning system.
The format is:
18.0.RELEASE.HOTFIX.DEV
where
| Component | Meaning |
|---|---|
| 18.0 | Odoo version |
| RELEASE | Production release generation |
| HOTFIX | Production hotfix generation |
| DEV | Shared development deployment generation |
Unlike Semantic Versioning, none of these numbers describe API compatibility.
They describe our deployment lifecycle.
The Rules
Rule 1
Every deployment to the shared development server increments DEV.
It doesn't matter whether the change is:
- migration
- new feature
- bug fix
- refactoring
- view changes
- security rules
- XML data
If users receive a new build on the shared development server...
...DEV increments.
We call this a fump.
Definition
fump = fucking bump
Rule 2
Production releases increment RELEASE.
Suppose production currently runs
18.0.4.0.0
Development continues:
18.0.4.0.1
18.0.4.0.2
18.0.4.0.3
...
18.0.4.0.696
Eventually QA signs off.
Now comes an important step.
Before deploying to production, we perform a release fump on the shared development server.
18.0.5.0.0
No code changes.
No migration changes.
Nothing.
Only the version changes.
Then we perform one final smoke test.
If everything passes...
Deploy that exact build to production.
Shared Dev
18.0.5.0.0
↓
Production
18.0.5.0.0
Production always receives the exact version that was tested.
Rule 3
Hotfixes increment HOTFIX.
Suppose production is
18.0.5.0.0
An emergency fix is required.
The hotfix becomes
18.0.5.1.0
That version is tested.
Then deployed.
Development continues from there.
18.0.5.1.1
18.0.5.1.2
18.0.5.1.3
Typical Lifecycle
18.0.4.0.0 Production Release 4
18.0.4.0.1 Dev deployment
18.0.4.0.2
18.0.4.0.3
...
18.0.4.0.696
18.0.5.0.0 Release fump
Final smoke test
18.0.5.0.0 Production Release 5
18.0.5.0.1 New development
18.0.5.0.2
18.0.5.1.0 Production hotfix
18.0.5.1.1 Continue development
18.0.5.1.2
Why This Works
This approach gives us several nice properties.
Monotonic versions
Odoo's version parser is always happy.
Every version is greater than the previous one.
No version rewrites
Once a version has been deployed anywhere shared, it is permanent.
No rewriting history.
No pretending intermediate versions never existed.
Production always runs a tested version
There is never a last-minute version change immediately before production deployment.
The production artifact is the same artifact that passed QA.
No Semantic Versioning debates
Nobody asks
"Is this a patch?"
Nobody asks
"Is this a minor feature?"
Nobody asks
"Should this be 2.1 or 2.2?"
The only question becomes
"Did we deploy a new build to the shared development environment?"
If yes...
Fump.
Is FckVer Better Than SemVer?
No.
It solves a different problem.
Semantic Versioning describes compatibility.
FckVer describes deployment history.
For our Odoo workflow, deployment history is far more important than compatibility semantics.
Final Thoughts
I don't claim this should become an industry standard.
I don't even claim it's the best possible solution.
But after trying to force Semantic Versioning into Odoo's module versioning, our team realized we were solving the wrong problem.
Once we started treating the manifest version as a deployment lifecycle instead of a semantic version...
Everything became much simpler.
Sometimes the best engineering solution isn't the most elegant one.
It's the one your team can understand at a glance.
P.S.
Yes, the official name is Fuckantic Versioning.
You might want to abbreviate it to FckVer because writing "fuck" into deployment scripts somehow felt unprofessional.
Top comments (0)