Skip to content

Semantic Versioning Guide for Tech Leads

Overview

Comprehensive guide for tech leads on implementing and managing semantic versioning across AzmX projects, with practical examples and decision-making frameworks.

Semantic Versioning Fundamentals

Version Format: MAJOR.MINOR.PATCH

graph LR
    A[1.2.3] --> B[MAJOR.MINOR.PATCH]
    B --> C[Breaking Changes]
    B --> D[New Features]
    B --> E[Bug Fixes]

    C --> F[API Changes]
    C --> G[Remove Features]
    C --> H[Architecture Changes]

    D --> I[Backward Compatible]
    D --> J[New Functionality]
    D --> K[New Endpoints]

    E --> L[Bug Fixes]
    E --> M[Security Patches]
    E --> N[Performance Improvements]

When to Increment Each Version Component

MAJOR Version (X.y.z)

Increment when making incompatible API changes

flowchart TD
    A[Code Change] --> B{Breaking Change?}
    B -->|Yes| C["MAJOR Version Increment"]
    B -->|No| D{New Feature?}

    C --> E[Examples:]
    E --> F[Remove API endpoint]
    E --> G[Change response format]
    E --> H[Remove function parameter]
    E --> I[Change database schema]

    style C fill:#ff6b6b
    style E fill:#ffcccc

Examples by Technology Stack:

Backend API Changes (Django/FastAPI)

# Version 1.0.0 → 2.0.0 (MAJOR)
# Before (v1.x.x)
class UserResponse:
    def __init__(self, id: int, name: str, email: str):
        self.id = id
        self.name = name  # Single name field
        self.email = email

# After (v2.0.0) - Breaking change
class UserResponse:
    def __init__(self, id: int, first_name: str, last_name: str, email: str):
        self.id = id
        self.first_name = first_name  # Split name - BREAKING
        self.last_name = last_name
        self.email = email

Frontend Component Changes (React/TypeScript)

// Version 2.1.3 → 3.0.0 (MAJOR)
// Before (v2.x.x)
interface ButtonProps {
  text: string;
  onClick: () => void;
  variant?: 'primary' | 'secondary';
}

// After (v3.0.0) - Breaking change
interface ButtonProps {
  children: React.ReactNode; // Changed from 'text' - BREAKING
  onClick: () => void;
  variant?: 'primary' | 'secondary' | 'danger'; // Added variant OK
}

MINOR Version (x.Y.z)

Increment when adding backward-compatible functionality

flowchart TD
    A[Code Change] --> B{Breaking Change?}
    B -->|No| C{New Feature?}
    C -->|Yes| D["MINOR Version Increment"]

    D --> E[Examples:]
    E --> F[Add new API endpoint]
    E --> G[Add optional parameter]
    E --> H[New component variant]
    E --> I[Additional configuration]

    style D fill:#4ecdc4
    style E fill:#ccffcc

Examples by Technology Stack:

Backend API Additions

# Version 1.2.0 → 1.3.0 (MINOR)
# Existing endpoint unchanged
@router.get("/users/{user_id}")
async def get_user(user_id: int) -> UserResponse:
    return user_service.get_user(user_id)

# NEW endpoint added - backward compatible
@router.get("/users/{user_id}/preferences")  # NEW in 1.3.0
async def get_user_preferences(user_id: int) -> UserPreferences:
    return user_service.get_preferences(user_id)

# Enhanced existing function with optional parameter
async def create_user(
    user_data: UserCreate,
    send_welcome_email: bool = True  # NEW optional parameter
) -> User:
    # Implementation handles both cases
    pass

Frontend Feature Additions

// Version 1.4.2 → 1.5.0 (MINOR)
// Existing props unchanged
interface ButtonProps {
  children: React.ReactNode;
  onClick: () => void;
  variant?: 'primary' | 'secondary';

  // NEW optional props in 1.5.0
  size?: 'sm' | 'md' | 'lg';           // NEW feature
  disabled?: boolean;                   // NEW feature
  loading?: boolean;                    // NEW feature
}

PATCH Version (x.y.Z)

Increment when making backward-compatible bug fixes

flowchart TD
    A[Code Change] --> B{Breaking Change?}
    B -->|No| C{New Feature?}
    C -->|No| D{Bug Fix?}
    D -->|Yes| E["PATCH Version Increment"]

    E --> F[Examples:]
    F --> G[Fix calculation error]
    F --> H[Resolve memory leak]
    F --> I[Security vulnerability fix]
    F --> J[Performance improvement]

    style E fill:#45b7d1
    style F fill:#cceeff

Examples by Technology Stack:

Bug Fixes

# Version 1.2.3 → 1.2.4 (PATCH)
# Before - Bug in calculation
def calculate_discount(price: float, discount_percent: float) -> float:
    return price - (price * discount_percent)  # BUG: should divide by 100

# After - Fixed calculation
def calculate_discount(price: float, discount_percent: float) -> float:
    return price - (price * discount_percent / 100)  # FIXED

Performance Improvements

// Version 2.3.1 → 2.3.2 (PATCH)
// Before - Inefficient rendering
const UserList: React.FC<{users: User[]}> = ({users}) => {
  return (
    <div>
      {users.map(user => (
        <UserCard key={user.id} user={user} />
      ))}
    </div>
  );
};

// After - Optimized with memoization
const UserList: React.FC<{users: User[]}> = memo(({users}) => {
  return (
    <div>
      {users.map(user => (
        <UserCard key={user.id} user={user} />
      ))}
    </div>
  );
});

Decision Framework for Version Increments

Version Decision Tree

flowchart TD
    A[Code Change Ready] --> B{Will this break existing clients?}

    B -->|Yes| C[MAJOR Version]
    C --> D[Update migration guides]
    C --> E[Coordinate with dependent teams]

    B -->|No| F{Does this add new functionality?}

    F -->|Yes| G[MINOR Version]
    G --> H[Update feature documentation]
    G --> I[Announce new capabilities]

    F -->|No| J{Is this a bug fix or improvement?}

    J -->|Yes| K[PATCH Version]
    K --> L[Update changelog]
    K --> M[Deploy quickly]

    J -->|No| N[No version change needed]
    N --> O[Internal refactoring only]

    style C fill:#ff6b6b
    style G fill:#4ecdc4
    style K fill:#45b7d1
    style N fill:#95a5a6

Pre-Release Versions

Alpha, Beta, Release Candidate

graph LR
    subgraph "Development Phase"
        A[1.0.0-alpha.1<br/>Early development]
        B[1.0.0-alpha.2<br/>Core features implemented]
        C[1.0.0-alpha.3<br/>API stabilizing]
    end

    subgraph "Testing Phase"
        D[1.0.0-beta.1<br/>Feature complete]
        E[1.0.0-beta.2<br/>Bug fixes]
        F[1.0.0-beta.3<br/>Performance tuning]
    end

    subgraph "Pre-Production"
        G[1.0.0-rc.1<br/>Release candidate]
        H[1.0.0-rc.2<br/>Final adjustments]
    end

    subgraph "Release"
        I[1.0.0<br/>Production release]
    end

    A --> B --> C --> D --> E --> F --> G --> H --> I

Pre-Release Naming Convention: - 1.0.0-alpha.1 - Early development, unstable - 1.0.0-beta.1 - Feature complete, testing phase - 1.0.0-rc.1 - Release candidate, production-ready testing

Practical Scenarios and Examples

Scenario 1: API Evolution

sequenceDiagram
    participant V1 as Version 1.0.0
    participant V11 as Version 1.1.0
    participant V12 as Version 1.2.0
    participant V20 as Version 2.0.0

    Note over V1: Initial API
    V1->>V11: Add optional fields (MINOR)
    V11->>V12: Add new endpoints (MINOR)
    V12->>V20: Change required fields (MAJOR)

    Note over V1,V20: Migration Path
    V1-->>V20: Support both versions
    V20-->>V20: Deprecate v1 after 6 months

Real Example - User API Evolution:

# Version 1.0.0 - Initial Release
GET /api/v1/users/{id}
Response:
  id: integer
  name: string
  email: string

# Version 1.1.0 - Add optional field (MINOR)
GET /api/v1/users/{id}
Response:
  id: integer
  name: string
  email: string
  avatar_url: string (optional) # NEW optional field

# Version 1.2.0 - Add new endpoint (MINOR)
GET /api/v1/users/{id}/preferences # NEW endpoint
Response:
  theme: string
  notifications: boolean

# Version 2.0.0 - Breaking change (MAJOR)
GET /api/v2/users/{id}
Response:
  id: integer
  first_name: string # BREAKING: was 'name'
  last_name: string  # BREAKING: split from 'name'
  email: string
  avatar_url: string

Scenario 2: Frontend Component Library

// Component evolution example

// Version 1.0.0 - Initial Button Component
interface ButtonProps {
  text: string;
  onClick: () => void;
}

// Version 1.1.0 - Add variants (MINOR)
interface ButtonProps {
  text: string;
  onClick: () => void;
  variant?: 'primary' | 'secondary'; // NEW optional
}

// Version 1.1.1 - Fix button padding (PATCH)
// CSS fix: padding: 8px 16px; (was 4px 8px)

// Version 1.2.0 - Add size prop (MINOR)
interface ButtonProps {
  text: string;
  onClick: () => void;
  variant?: 'primary' | 'secondary';
  size?: 'sm' | 'md' | 'lg'; // NEW optional
}

// Version 2.0.0 - Change text to children (MAJOR)
interface ButtonProps {
  children: React.ReactNode; // BREAKING: was 'text'
  onClick: () => void;
  variant?: 'primary' | 'secondary';
  size?: 'sm' | 'md' | 'lg';
}

Scenario 3: Database Schema Changes

-- Version 1.0.0 - Initial Schema
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  email VARCHAR(255) UNIQUE NOT NULL
);

-- Version 1.1.0 - Add optional column (MINOR)
ALTER TABLE users ADD COLUMN avatar_url VARCHAR(255);

-- Version 1.1.1 - Add index for performance (PATCH)
CREATE INDEX idx_users_email ON users(email);

-- Version 2.0.0 - Split name column (MAJOR)
-- Requires migration script
ALTER TABLE users
  ADD COLUMN first_name VARCHAR(255),
  ADD COLUMN last_name VARCHAR(255);

-- Migration required to split existing names
-- Then drop the old name column
ALTER TABLE users DROP COLUMN name;

Version Management for Different Project Types

Backend Services Versioning

graph TD
    A[Backend Service] --> B[API Versioning]
    A --> C[Database Schema]
    A --> D[Internal Libraries]

    B --> E["URL Path: /api/v1/"]
    B --> F["Header: API-Version: 1.0"]
    B --> G["Accept: application/vnd.api+json;version=1"]

    C --> H[Migration Scripts]
    C --> I[Backward Compatibility]
    C --> J[Rollback Strategy]

    D --> K[Semantic Versioning]
    D --> L[Dependency Management]

API Versioning Strategy:

# URL-based versioning (recommended)
@router.get("/api/v1/users/{user_id}")  # Version 1.x
@router.get("/api/v2/users/{user_id}")  # Version 2.x

# Header-based versioning (alternative)
@router.get("/api/users/{user_id}")
async def get_user(user_id: int, api_version: str = Header(default="1.0")):
    if api_version.startswith("2."):
        return get_user_v2(user_id)
    return get_user_v1(user_id)

Frontend Application Versioning

graph TD
    A[Frontend App] --> B[Application Version]
    A --> C[Component Library]
    A --> D[API Client]

    B --> E[Build Artifacts]
    B --> F[Release Tags]
    B --> G[Deployment Tracking]

    C --> H[NPM Package Version]
    C --> I[Breaking Changes]
    C --> J[Migration Guides]

    D --> K[API Version Compatibility]
    D --> L[Backward Support]

Package.json Versioning:

{
  "name": "@azmx/ui-components",
  "version": "2.1.3",
  "peerDependencies": {
    "react": ">=18.0.0",
    "typescript": ">=4.9.0"
  },
  "engines": {
    "node": ">=18.0.0"
  }
}

Release Management Process

Release Workflow

sequenceDiagram
    participant Dev as Developer
    participant PR as Pull Request
    participant Main as Main Branch
    participant CI as CI/CD
    participant Prod as Production

    Dev->>PR: Create feature PR
    PR->>Main: Merge to main
    Main->>CI: Trigger version bump
    CI->>CI: Analyze commits
    CI->>CI: Bump version (semantic)
    CI->>Main: Tag new version
    CI->>Prod: Deploy with version

    Note over CI,Prod: Automated Semantic Versioning

Automated Version Bumping

# GitHub Actions workflow
name: Version and Release
on:
  push:
    branches: [main]

jobs:
  version:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Semantic Release
        uses: semantic-release/semantic-release@v19
        with:
          branches: |
            [
              '+([0-9])?(.{+([0-9]),x}).x',
              'main',
              'next',
              'next-major',
              {name: 'beta', prerelease: true},
              {name: 'alpha', prerelease: true}
            ]

Commit Message Format for Automation

# Format: type(scope): description

# PATCH version bump
fix(auth): resolve login timeout issue
fix(database): handle connection pooling error

# MINOR version bump
feat(api): add user preference endpoints
feat(ui): implement dark mode toggle

# MAJOR version bump
feat(api)!: change user response format
BREAKING CHANGE: user.name split into first_name and last_name

# Other types (no version bump)
docs(readme): update installation instructions
style(format): apply prettier formatting
refactor(utils): extract common validation logic
test(unit): add user service test cases

Migration and Deprecation Strategies

Deprecation Timeline

gantt
    title API Deprecation Timeline
    dateFormat  YYYY-MM-DD

    section Version 1.x
    Active Support    :active, v1, 2024-01-01, 180d
    Maintenance Only  :maintenance, 2024-07-01, 180d
    End of Life      :eol, 2024-12-28, 1d

    section Version 2.x
    Development      :dev, 2024-03-01, 90d
    Beta Testing     :beta, 2024-06-01, 60d
    Production Release :prod, 2024-08-01, 365d

Migration Communication

# Deprecation Notice Template

## API Version 1.x Deprecation Notice

### Timeline
- **Announcement**: January 1, 2024
- **New Version Available**: August 1, 2024
- **End of Support**: December 31, 2024

### What's Changing
- User response format updated
- Authentication method enhanced
- New endpoints available

### Migration Guide
1. Update API client to v2
2. Modify response handling for user objects
3. Update authentication headers
4. Test thoroughly in staging environment

### Support
- Migration assistance available until EOL
- Updated documentation at docs.azmx.sa
- Contact: [email protected]

Team Communication and Training

Version Release Communication

graph LR
    A[Version Release] --> B[Automated Notifications]
    B --> C[Slack Channels]
    B --> D[Email Updates]
    B --> E[Documentation]

    C --> F[#engineering-releases]
    C --> G[#product-updates]

    D --> H[Stakeholders]
    D --> I[Customer Success]

    E --> J[Changelog]
    E --> K[Migration Guides]
    E --> L[API Documentation]

Training and Best Practices

  • Monthly Sessions: Semantic versioning workshops
  • Documentation: Keep versioning guidelines updated
  • Code Reviews: Check version impact during reviews
  • Release Notes: Maintain comprehensive changelogs
  • Monitoring: Track version adoption and issues

Tools and Automation

  • semantic-release: Automated version management
  • conventional-commits: Standardized commit messages
  • changelog: Automated changelog generation
  • version-bump: Manual version control
  • git-cliff: Advanced changelog generation

Integration Examples

{
  "scripts": {
    "release": "semantic-release",
    "version:patch": "npm version patch",
    "version:minor": "npm version minor",
    "version:major": "npm version major",
    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
  },
  "release": {
    "branches": ["main"],
    "plugins": [
      "@semantic-release/commit-analyzer",
      "@semantic-release/release-notes-generator",
      "@semantic-release/npm",
      "@semantic-release/github"
    ]
  }
}

This guide provides tech leads with practical tools and examples for implementing effective semantic versioning across all AzmX projects, ensuring consistency and clear communication of changes to all stakeholders.