In this article, we will outline a robust and efficient release process for web applications, built around trunk-based development and environment-based feature flags. This methodology ensures continuous integration, easy testing in production, and a smooth path from development to release while maintaining high-quality standards.
Core Principles
-
- The trunk branch serves as the single source of truth for all development work.
- Developers create feature branches (e.g.,
feature/xyz
) from the trunk for new features or Jira tickets. - Pull requests (PRs) are submitted from these feature branches to the trunk for review and merging after successful tests.
-
Environment-Based Feature Flags:
- Feature flags are used to control the activation of features across environments.
- Flags are stored in environment-specific configuration files or as part of the CI/CD pipeline configuration.
- In the trunk branch, all feature flags are set to OFF by default.
- Flags can be toggled ON in specific environments (e.g., sandbox, staging, or production) as needed.
JIRA Versions in Sprint
Environment Deployment Flow
-
Sandbox or Staging Environment:
- For QA and integration testing, teams can create a branch prefixed with
sandbox/
(e.g.,sandbox/xyz
) from the trunk. - This branch is deployed to a dedicated sandbox or staging environment using CI/CD pipelines.
- QA teams can validate new features, and integration tests can ensure compatibility.
- Feature flags are toggled ON in this environment for testing specific features.
- For QA and integration testing, teams can create a branch prefixed with
-
Production Release Preparation:
- To prepare for a release, create a
release/xyz
branch from the trunk. - The
release/xyz
branch serves as the release candidate and is initially deployed to 5% of production traffic for beta testing. - Feature flags for new features are toggled ON in this branch to allow testing in production.
- Nginx or a similar load balancer can handle this traffic split, ensuring only a subset of users see the changes.
- To prepare for a release, create a
Feature Flags: Examples and Usage
-
Flag Structure:
- Store feature flags in a configuration file (e.g.,
config/feature-flags.json
):
{ "feature_xyz": false, "feature_abc": true }
- Store feature flags in a configuration file (e.g.,
-
Use environment variables to control flags during runtime:
FEATURE_XYZ=true FEATURE_ABC=false npm start
-
Backend Example:
- Toggle flags in code:
const featureFlags = require('./config/feature-flags'); if (featureFlags.feature_xyz) { console.log('Feature XYZ is enabled!'); } else { console.log('Feature XYZ is disabled.'); }
-
Frontend Example:
- Use flags to conditionally render UI components:
if (process.env.REACT_APP_FEATURE_XYZ === 'true') { render(<NewFeatureComponent />); } else { render(<OldFeatureComponent />); }
-
Toggling Flags During Testing:
- To toggle a flag for testing, update the configuration or environment variables and restart the relevant service (frontend or backend):
FEATURE_XYZ=true npm start
- For CI/CD pipelines, ensure that the appropriate flag values are injected into the environment during deployment.
Testing in Production
-
Traffic Routing for Beta Testing:
- Use Nginx configurations to control traffic allocation:
http { upstream stable_backend { server stable_backend_1; server stable_backend_2; } upstream canary_backend { server canary_backend_1; server canary_backend_2; } upstream mixed_backend { server stable_backend_1 weight=45; server stable_backend_2 weight=45; server canary_backend_1 weight=5; server canary_backend_2 weight=5; } server { listen 80; server_name my-app.example.com; location / { if ($http_x_qa_test = "true") { proxy_pass http://canary_backend; break; } proxy_pass http://mixed_backend; } } }
- Route 5% of production traffic to servers running the new version by adjusting load balancer weights.
-
Dedicated QA Testing in Production:
- QA teams can attach a custom cookie (e.g.,
qa-test=true
) to their requests. - Nginx checks this cookie and routes these requests to the new version 100% of the time, ensuring targeted testing in production.
- QA teams can attach a custom cookie (e.g.,
Stabilizing the Release
-
Fixing Issues:
- Developers fix any issues identified during beta testing by opening PRs to the trunk branch.
- Once merged, these fixes are cherry-picked into the
release/xyz
branch.
-
Finalizing the Release:
- After all issues are resolved and the branch is stable, the release branch is tagged with a semantic version (e.g.,
v1.2.0
), triggering deployment to the stable backend. - Release notes are generated for documentation and shared with stakeholders.
- After all issues are resolved and the branch is stable, the release branch is tagged with a semantic version (e.g.,
Hotfix Process
-
Creating Hotfix Branches:
- For urgent fixes, create a
hotfix/xyz
branch directly from the latest production tag. - Hotfix branches follow the same stabilization and tagging process as release branches.
- For urgent fixes, create a
-
Versioning:
- Hotfixes increment the patch version (e.g., from
v1.2.0
tov1.2.1
) following Semantic Versioning (SemVer) standards.
- Hotfixes increment the patch version (e.g., from
Branch Cleanup
- Routinely delete merged branches to avoid clutter.
- Periodically remove unused feature flags to maintain organization.
- Automate branch deletion post-merge using GitHub Actions or similar tools.
Alternative QA and Testing Strategies
Instead of cookies, additional strategies for routing QA traffic in production include:
-
Header-Based Routing:
- QA adds a custom header (e.g.,
X-QA-Test: true
) to their requests. - Nginx routes these requests to the new version for testing.
- QA adds a custom header (e.g.,
-
IP-Based Routing:
- Restrict traffic to the new version based on QA’s IP addresses.
-
Authentication Token-Based Routing:
- QA logs in with a specific test account tied to a role or token that ensures requests are routed to the new version.
Conclusion
This release process leverages trunk-based development and environment-based feature flags to create a scalable, testable, and production-safe deployment workflow. By using sandbox environments, traffic routing, and dedicated testing strategies, teams can deliver high-quality features while minimizing risk. The approach ensures that issues are caught early and addressed efficiently, paving the way for seamless feature rollouts and hotfixes.
Top comments (0)