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
Recommended Tools
- 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.