Help me een feature vlag systeem implementeren in mijn Flask applicatie
description
Door een feature vlag systeem te implementeren, kan ik feature releases effectiever beheren, A/B testen uitvoeren en functies met minimale moeite terugdraaien, wat leidt tot een stabielere applicatie en een betere gebruikerservaring.
prompt
try_prompt
Ik wil een feature vlag systeem implementeren in mijn Flask applicatie om feature releases en A/B testen te controleren. Mijn huidige structuur van de applicatie is: {{app_structuur}}. Leg uit hoe ik featur ... more
generate_helper
...
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Het implementeren van een feature vlag systeem in je Flask-applicatie helpt je om nieuwe functies gecontroleerd vrij te geven en A/B tests uit te voeren zonder direct codewijzigingen. Hier is een overzicht van hoe je dat kunt aanpakken en wat de beste praktijken zijn:
1. **Structuur en opslag van feature vlaggen**
- **Configuratiebestand**: Maak bijvoorbeeld een JSON-, YAML- of Python-bestand (bijv. `feature_flags.py` of `config/feature_flags.yaml`) waarin je alle vlaggen definieert. Bijvoorbeeld:
```python
# app/feature_flags.py
FEATURE_FLAGS = {
'nieuwe_feature': True,
'ab_test_variant_A': False,
'ab_test_variant_B': False,
}
```
- **Database**: Voor meer dynamiek en beheerbaarheid kun je vlaggen in een database opslaan, bijvoorbeeld via een eenvoudige tabel met kolommen voor naam, status, en eventueel doelgroepen.
2. **Integratie in je Flask app**
- **Initialisatie**: Laad de vlaggen bij het opstarten van de app:
```python
# app/__init__.py
from flask import Flask
from .feature_flags import FEATURE_FLAGS
def create_app():
app = Flask(__name__)
app.config['FEATURE_FLAGS'] = FEATURE_FLAGS
# andere initialisaties
return app
```
- **Gebruik in routes/templates**:
```python
# app/routes.py
from flask import current_app, render_template
@app.route('/')
def index():
feature_flags = current_app.config['FEATURE_FLAGS']
if feature_flags.get('nieuwe_feature'):
# gedrag voor nieuwe feature
pass
return render_template('index.html', feature_flags=feature_flags)
```
Of direct in templates:
```html
{% if current_app.config['FEATURE_FLAGS'].get('nieuwe_feature') %}
<!-- nieuwe feature HTML -->
{% endif %}
```
3. **Dynamisch beheer zonder codewijziging**
- **Backend beheer**: Gebruik een admin interface of een dashboard om vlaggen aan te passen (bijv. via een eenvoudige webpagina die de database bijwerkt).
- **API endpoints**: Maak endpoints om vlaggen te wijzigen en op te halen, zodat je deze zonder nieuwe deployment kunt aanpassen.
- **Caching en refresh**: Zorg dat de app de vlaggen herlaadt of dat je een cache invalidatie hebt, zodat wijzigingen meteen effect hebben.
4. **Beste praktijken voor soepele uitrol en rollback**
- **Graduele uitrol**: Zet nieuwe functies eerst uit voor alle gebruikers, en schakel ze in voor een kleine testgroep via vlaggen.
- **Fouttolerantie**: Zorg dat je code veilig is als een vlag ontbreekt of onjuist is ingesteld. Gebruik `get()` met een default.
- **Monitoring**: Houd bij hoeveel gebruikers de nieuwe functies gebruiken en of er problemen zijn.
- **Rollback**: Schakel snel de vlag uit via je beheerinterface of API, zonder codewijziging. Bij grote problemen kun je de app herstarten of de vlaggen opnieuw instellen.
- **Feature flags met versiebeheer**: Documenteer welke vlaggen voor welke releases bedoeld zijn, zodat je makkelijk terug kunt schakelen.
Door deze aanpak te volgen, kun je feature releases en A/B tests efficiënt beheren, en snel reageren op problemen zonder herdeployments.
provider: deepseek
model: deepseek-chat
Hier is een uitgebreide uitleg voor het implementeren van feature flags in je Flask applicatie:
## 1. Basis Feature Flag Implementatie
**app/__init__.py:**
```python
from flask import Flask
import os
class FeatureFlags:
def __init__(self):
self.flags = {
'nieuwe_ui': os.getenv('FEATURE_NIEUWE_UI', 'false').lower() == 'true',
'ab_test_pagina': os.getenv('FEATURE_AB_TEST', 'false').lower() == 'true',
'beta_functie': os.getenv('FEATURE_BETA', 'false').lower() == 'true'
}
def is_enabled(self, feature_name):
return self.flags.get(feature_name, False)
def set_flag(self, feature_name, enabled):
self.flags[feature_name] = enabled
def create_app():
app = Flask(__name__)
app.feature_flags = FeatureFlags()
from app import routes
return app
```
**app/routes.py:**
```python
from flask import render_template, request
from app import app
@app.route('/')
def home():
if app.feature_flags.is_enabled('nieuwe_ui'):
return render_template('nieuwe_home.html')
else:
return render_template('oude_home.html')
@app.route('/dashboard')
def dashboard():
# A/B test voor nieuwe dashboard layout
if app.feature_flags.is_enabled('ab_test_pagina'):
return render_template('dashboard_nieuw.html')
else:
return render_template('dashboard_oud.html')
```
## 2. Geavanceerde Feature Flag Configuratie
**Verbeterde FeatureFlags klasse:**
```python
import json
import yaml
from typing import Dict, Any
class AdvancedFeatureFlags:
def __init__(self, config_file=None):
self.flags = {}
self.config_file = config_file
self.load_flags()
def load_flags(self):
# Standaard flags
default_flags = {
'nieuwe_ui': {
'enabled': False,
'description': 'Nieuwe gebruikersinterface',
'rollout_percentage': 0
},
'ab_test_pagina': {
'enabled': False,
'description': 'A/B test voor nieuwe pagina layout',
'rollout_percentage': 50
}
}
# Laad externe configuratie als beschikbaar
if self.config_file and os.path.exists(self.config_file):
with open(self.config_file, 'r') as f:
external_flags = yaml.safe_load(f) or {}
default_flags.update(external_flags)
# Environment variables hebben voorrang
for flag_name in default_flags:
env_var = f'FEATURE_{flag_name.upper()}'
if os.getenv(env_var):
default_flags[flag_name]['enabled'] = os.getenv(env_var).lower() == 'true'
self.flags = default_flags
def is_enabled(self, feature_name, user_id=None):
flag_config = self.flags.get(feature_name)
if not flag_config:
return False
if not flag_config['enabled']:
return False
# Percentage-based rollout
rollout_percentage = flag_config.get('rollout_percentage', 0)
if rollout_percentage > 0 and user_id:
return hash(user_id) % 100 < rollout_percentage
return flag_config['enabled']
```
## 3. Gebruik in Routes met A/B Testing
**app/routes.py (uitgebreid):**
```python
@app.route('/producten')
def producten():
user_id = request.cookies.get('user_id') or request.remote_addr
if app.feature_flags.is_enabled('nieuwe_product_weergave', user_id):
# Nieuwe feature
producten = get_producten_nieuwe_weergave()
template = 'producten_nieuw.html'
else:
# Oude feature
producten = get_producten_standaard()
template = 'producten_standaard.html'
return render_template(template, producten=producten)
@app.route('/api/data')
def api_data():
if app.feature_flags.is_enabled('nieuwe_api'):
return jsonify({'data': nieuwe_api_implementatie()})
else:
return jsonify({'data': oude_api_implementatie()})
```
## 4. Dynamische Configuratie Bestanden
**Maak een configuratiebestand (features.yaml):**
```yaml
nieuwe_ui:
enabled: true
description: "Nieuwe React-based UI"
rollout_percentage: 25
ab_test_pagina:
enabled: true
description: "A/B test voor conversie optimalisatie"
rollout_percentage: 50
beta_functie:
enabled: false
description: "Nieuwe beta functie"
rollout_percentage: 0
```
## 5. Best Practices voor Feature Flag Beheer
### **Uitrol Strategieën:**
1. **Canary Release:**
```python
# Langzame uitrol naar specifieke gebruikers
def is_canary_user(user_id):
return user_id in ['user123', 'user456'] # Specifieke testgebruikers
@app.route('/feature')
def feature():
user_id = get_user_id()
if is_canary_user(user_id) or app.feature_flags.is_enabled('nieuwe_feature'):
return nieuwe_implementatie()
return oude_implementatie()
```
2. **Percentage-based Rollout:**
```python
def should_show_feature(user_id, percentage):
return hash(user_id) % 100 < percentage
```
### **Monitoring en Logging:**
```python
import logging
@app.route('/track-feature-usage')
def track_usage():
feature_name = 'nieuwe_ui'
user_id = get_user_id()
is_enabled = app.feature_flags.is_enabled(feature_name, user_id)
# Log feature usage voor analytics
logging.info(f"Feature {feature_name} - User: {user_id} - Enabled: {is_enabled}")
return jsonify({'status': 'tracked'})
```
### **Terugdraaien Procedure:**
1. **Snel terugdraaien via environment variables:**
```bash
# Feature uitzetten
export FEATURE_NIEUWE_UI=false
# Of via config file aanpassen
```
2. **Noodprocedure:**
```python
def veilige_feature_controle(feature_name, fallback_function):
try:
if app.feature_flags.is_enabled(feature_name):
return nieuwe_function()
else:
return fallback_function()
except Exception as e:
logging.error(f"Feature {feature_name} error: {e}")
return fallback_function() # Altijd terugvallen op bewezen code
```
## 6. Deployment en Beheer
**Dockerfile example:**
```dockerfile
FROM python:3.9
# Feature flags als environment variables
ENV FEATURE_NIEUWE_UI=false
ENV FEATURE_AB_TEST=true
ENV FEATURE_BETA=false
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
```
**Runtime configuratie:**
```python
# Herlaad feature flags zonder restart
@app.route('/admin/reload-flags')
def reload_flags():
if app.feature_flags.config_file:
app.feature_flags.load_flags()
return "Flags reloaded"
return "No config file set"
```
## Belangrijkste Voordelen:
- ✅ **Geen code changes nodig** voor feature toggle
- ✅ **Snel terugdraaien** zonder deployment
- ✅ **Gecontroleerde uitrol** naar specifieke gebruikersgroepen
- ✅ **A/B testing** mogelijkheden
- ✅ **Minder risico** bij nieuwe feature releases
Deze aanpak zorgt voor een soepele, gecontroleerde feature release cyclus met minimale risico's.

