<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Michael Elian Kevin</title>
    <description>The latest articles on DEV Community by Michael Elian Kevin (@kevinkwee27).</description>
    <link>https://dev.to/kevinkwee27</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4055933%2Fb69a7145-385b-4b15-b565-8fd8a303aef1.png</url>
      <title>DEV Community: Michael Elian Kevin</title>
      <link>https://dev.to/kevinkwee27</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kevinkwee27"/>
    <language>en</language>
    <item>
      <title>FckVer: A Practical Versioning Strategy for Odoo</title>
      <dc:creator>Michael Elian Kevin</dc:creator>
      <pubDate>Fri, 31 Jul 2026 04:46:30 +0000</pubDate>
      <link>https://dev.to/kevinkwee27/fckver-a-practical-versioning-strategy-for-odoo-4kfg</link>
      <guid>https://dev.to/kevinkwee27/fckver-a-practical-versioning-strategy-for-odoo-4kfg</guid>
      <description>&lt;h2&gt;
  
  
  FckVer: A Practical Versioning Strategy for Odoo
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;Odoo has a single version field inside &lt;code&gt;__manifest__.py&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;18.0.1.0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple?&lt;/p&gt;

&lt;p&gt;Not really.&lt;/p&gt;

&lt;p&gt;That single version is expected to represent several completely different concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;application version&lt;/li&gt;
&lt;li&gt;module version&lt;/li&gt;
&lt;li&gt;migration version&lt;/li&gt;
&lt;li&gt;deployment ordering&lt;/li&gt;
&lt;li&gt;upgrade detection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In reality, these are different things.&lt;/p&gt;

&lt;p&gt;Coming from ecosystems like Django, Rails, Alembic, Flyway or Liquibase, this felt strange because those ecosystems separate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;application release&lt;/li&gt;
&lt;li&gt;database migration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
v2.0.0

Database
Migration 001
Migration 002
Migration 003
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nobody tries to squeeze both into one version number.&lt;/p&gt;

&lt;p&gt;Unfortunately, Odoo only gives us one.&lt;/p&gt;




&lt;h3&gt;
  
  
  Our Development Workflow
&lt;/h3&gt;

&lt;p&gt;Our company does &lt;strong&gt;not&lt;/strong&gt; have disposable development databases.&lt;/p&gt;

&lt;p&gt;Instead, we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Developer
      │
      ▼
Shared Development Server
(real company users)
      │
      ▼
QA
      │
      ▼
Production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shared development server contains real data.&lt;/p&gt;

&lt;p&gt;Sales use it.&lt;/p&gt;

&lt;p&gt;QA uses it.&lt;/p&gt;

&lt;p&gt;Project members use it.&lt;/p&gt;

&lt;p&gt;Because of that, every deployment to this server becomes part of the database history.&lt;/p&gt;

&lt;p&gt;That immediately breaks many traditional versioning assumptions.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Problem with Semantic Versioning
&lt;/h3&gt;

&lt;p&gt;Semantic Versioning asks questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this a major change?&lt;/li&gt;
&lt;li&gt;Is this a minor feature?&lt;/li&gt;
&lt;li&gt;Is this a patch?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our team had a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"We deployed a new build to the shared development server. Which number do we bump?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Semantic Versioning doesn't answer that.&lt;/p&gt;

&lt;p&gt;Odoo documentation doesn't answer that.&lt;/p&gt;

&lt;p&gt;Different Odoo teams even interpret the five-part version differently.&lt;/p&gt;

&lt;p&gt;Eventually we realized something.&lt;/p&gt;

&lt;p&gt;We weren't trying to version software.&lt;/p&gt;

&lt;p&gt;We were trying to version our deployment lifecycle.&lt;/p&gt;




&lt;h2&gt;
  
  
  Introducing FckVer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  FckVer (Fuckantic Versioning)
&lt;/h3&gt;

&lt;p&gt;Because sometimes software engineering deserves an appropriately named versioning system.&lt;/p&gt;

&lt;p&gt;The format is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;18.0.RELEASE.HOTFIX.DEV
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;18.0&lt;/td&gt;
&lt;td&gt;Odoo version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RELEASE&lt;/td&gt;
&lt;td&gt;Production release generation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HOTFIX&lt;/td&gt;
&lt;td&gt;Production hotfix generation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DEV&lt;/td&gt;
&lt;td&gt;Shared development deployment generation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Unlike Semantic Versioning, none of these numbers describe API compatibility.&lt;/p&gt;

&lt;p&gt;They describe our deployment lifecycle.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Rules
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Rule 1
&lt;/h4&gt;

&lt;p&gt;Every deployment to the shared development server increments DEV.&lt;/p&gt;

&lt;p&gt;It doesn't matter whether the change is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;migration&lt;/li&gt;
&lt;li&gt;new feature&lt;/li&gt;
&lt;li&gt;bug fix&lt;/li&gt;
&lt;li&gt;refactoring&lt;/li&gt;
&lt;li&gt;view changes&lt;/li&gt;
&lt;li&gt;security rules&lt;/li&gt;
&lt;li&gt;XML data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If users receive a new build on the shared development server...&lt;/p&gt;

&lt;p&gt;...DEV increments.&lt;/p&gt;

&lt;p&gt;We call this a &lt;strong&gt;fump&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Definition&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;fump&lt;/strong&gt; = fucking bump&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h4&gt;
  
  
  Rule 2
&lt;/h4&gt;

&lt;p&gt;Production releases increment RELEASE.&lt;/p&gt;

&lt;p&gt;Suppose production currently runs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;18.0.4.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Development continues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;18.0.4.0.1
18.0.4.0.2
18.0.4.0.3
...
18.0.4.0.696
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eventually QA signs off.&lt;/p&gt;

&lt;p&gt;Now comes an important step.&lt;/p&gt;

&lt;p&gt;Before deploying to production, we perform a &lt;strong&gt;release fump&lt;/strong&gt; on the shared development server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;18.0.5.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No code changes.&lt;/p&gt;

&lt;p&gt;No migration changes.&lt;/p&gt;

&lt;p&gt;Nothing.&lt;/p&gt;

&lt;p&gt;Only the version changes.&lt;/p&gt;

&lt;p&gt;Then we perform one final smoke test.&lt;/p&gt;

&lt;p&gt;If everything passes...&lt;/p&gt;

&lt;p&gt;Deploy &lt;strong&gt;that exact build&lt;/strong&gt; to production.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shared Dev
18.0.5.0.0

↓

Production
18.0.5.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Production always receives the exact version that was tested.&lt;/p&gt;




&lt;h4&gt;
  
  
  Rule 3
&lt;/h4&gt;

&lt;p&gt;Hotfixes increment HOTFIX.&lt;/p&gt;

&lt;p&gt;Suppose production is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;18.0.5.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An emergency fix is required.&lt;/p&gt;

&lt;p&gt;The hotfix becomes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;18.0.5.1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That version is tested.&lt;/p&gt;

&lt;p&gt;Then deployed.&lt;/p&gt;

&lt;p&gt;Development continues from there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;18.0.5.1.1
18.0.5.1.2
18.0.5.1.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Typical Lifecycle
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Why This Works
&lt;/h3&gt;

&lt;p&gt;This approach gives us several nice properties.&lt;/p&gt;

&lt;h4&gt;
  
  
  Monotonic versions
&lt;/h4&gt;

&lt;p&gt;Odoo's version parser is always happy.&lt;/p&gt;

&lt;p&gt;Every version is greater than the previous one.&lt;/p&gt;




&lt;h4&gt;
  
  
  No version rewrites
&lt;/h4&gt;

&lt;p&gt;Once a version has been deployed anywhere shared, it is permanent.&lt;/p&gt;

&lt;p&gt;No rewriting history.&lt;/p&gt;

&lt;p&gt;No pretending intermediate versions never existed.&lt;/p&gt;




&lt;h4&gt;
  
  
  Production always runs a tested version
&lt;/h4&gt;

&lt;p&gt;There is never a last-minute version change immediately before production deployment.&lt;/p&gt;

&lt;p&gt;The production artifact is the same artifact that passed QA.&lt;/p&gt;




&lt;h4&gt;
  
  
  No Semantic Versioning debates
&lt;/h4&gt;

&lt;p&gt;Nobody asks&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Is this a patch?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nobody asks&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Is this a minor feature?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nobody asks&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Should this be 2.1 or 2.2?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The only question becomes&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Did we deploy a new build to the shared development environment?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If yes...&lt;/p&gt;

&lt;p&gt;Fump.&lt;/p&gt;




&lt;h3&gt;
  
  
  Is FckVer Better Than SemVer?
&lt;/h3&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;It solves a different problem.&lt;/p&gt;

&lt;p&gt;Semantic Versioning describes compatibility.&lt;/p&gt;

&lt;p&gt;FckVer describes deployment history.&lt;/p&gt;

&lt;p&gt;For our Odoo workflow, deployment history is far more important than compatibility semantics.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I don't claim this should become an industry standard.&lt;/p&gt;

&lt;p&gt;I don't even claim it's the best possible solution.&lt;/p&gt;

&lt;p&gt;But after trying to force Semantic Versioning into Odoo's module versioning, our team realized we were solving the wrong problem.&lt;/p&gt;

&lt;p&gt;Once we started treating the manifest version as a deployment lifecycle instead of a semantic version...&lt;/p&gt;

&lt;p&gt;Everything became much simpler.&lt;/p&gt;

&lt;p&gt;Sometimes the best engineering solution isn't the most elegant one.&lt;/p&gt;

&lt;p&gt;It's the one your team can understand at a glance.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, the official name is &lt;strong&gt;Fuckantic Versioning&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You might want to abbreviate it to &lt;strong&gt;FckVer&lt;/strong&gt; because writing "fuck" into deployment scripts somehow felt unprofessional.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>odoo</category>
      <category>versioning</category>
      <category>engineering</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
