# Environments (dev / staging / prod)

***"Solo necesito cambiar la variable ENV a 'prod'"* - Spoiler: No**

Ayer: cuándo ejecutar tus pipelines. Hoy: **dónde ejecutarlos.**

Dev, staging, producción. Lo sabes de software tradicional.

Pero en ML, los ambientes son mucho más que código.

---

**Historia:**

Data Scientist: "Ya terminé el modelo, súbelo a producción" Yo: "¿Lo probaste en staging?" DS: "No tenemos staging para ML" Yo: "¿Cómo no?" DS: "Es el mismo código, solo cambias la conexión a la base de datos"

**3 semanas después:**

El modelo en producción degradó un 15%.

¿Por qué? Porque los datos de producción eran diferentes a los de desarrollo.

Nadie lo había probado con datos reales de prod antes del deploy.

**El problema fundamental:**

En software tradicional:

```python
if ENV == "dev":
    db = "localhost:5432"
elif ENV == "prod":
    db = "prod-db:5432"
```

**Eso es todo. Mismo código, diferentes configuraciones.**

---

En ML:

```python
if ENV == "dev":
    db = "localhost:5432"
    dataset = "sample_1000_rows.csv"  # Subset
    model = "model_v1_local.pkl"
    features = ["basic_feature_set"]
    monitoring = False
    
elif ENV == "prod":
    db = "prod-db:5432"
    dataset = "s3://prod/full_dataset/"  # 500GB
    model = "s3://models/prod/v2.3.1/"
    features = ["basic + advanced + experimental"]
    monitoring = True
    drift_detection = True
    A_B_testing = True
```

**No es solo configuración. Son assets completamente diferentes.**

---

**Los 3 tipos de separación necesarios:**

### **1\. Separación de Datos**

```bash
DEV:
├── datasets/
│   ├── sample_1k.parquet      # Subset para desarrollo
│   ├── synthetic_data.parquet  # Datos sintéticos
│   └── anonymized_prod.parquet # Muestra anonimizada

STAGING:
├── datasets/
│   ├── prod_snapshot.parquet   # Snapshot de prod (última semana)
│   └── validation_set.parquet  # Set de validación fijo

PROD:
├── datasets/
│   ├── realtime_stream/        # Datos reales en tiempo real
│   └── historical/             # Todo el histórico
```

**¿Por qué?**

* Dev: necesitas iterar rápido (1k rows, no 500GB)
    
* Staging: necesitas validar con datos realistas
    
* Prod: necesitas todos los datos reales
    

**No puedes entrenar en dev con 1k rows y esperar que funcione en prod con 500GB.**

---

### **2\. Separación de Modelos**

````markdown
# Model Registry por ambiente

DEV:
- Experiments: 1000+ modelos
- No validation estricta
- Cualquiera puede registrar

STAGING:
- Candidates: ~10 modelos pasando validación
- Métricas > baseline required
- Review antes de promover

PROD:
- Active: 1-2 modelos serviendo tráfico
- A/B testing entre versiones
- Rollback automático si falla
```

**El flujo:**
```
DEV → train 100 experiments
    → pick best
    → promote to STAGING

STAGING → validate con prod-like data
        → compare vs prod baseline
        → stress test
        → promote to PROD (if approved)

PROD → shadow mode (sin tráfico real)
     → canary deploy (5% tráfico)
     → gradual rollout (100%)
````

---

### **3\. Separación de Features**

```python
# Feature Store por ambiente

class FeatureStore:
    def get_features(self, env):
        if env == "dev":
            return [
                "basic_features",
                "experimental_features"  # Puedes romper cosas
            ]
        
        elif env == "staging":
            return [
                "basic_features",
                "tested_features"  # Solo features validadas
            ]
        
        elif env == "prod":
            return [
                "basic_features",
                "tested_features",
                "monitored_features"  # + monitoring activo
            ]
```

**Ejemplo real de pipeline multi-ambiente:**

```python
# Pipeline que funciona en todos los ambientes

@pipeline
def training_pipeline(env: str):
    
    # 1. Datos diferentes por ambiente
    if env == "dev":
        data = load_sample_data(n_rows=1000)
    elif env == "staging":
        data = load_snapshot("prod_last_week")
    else:  # prod
        data = load_full_dataset()
    
    # 2. Validación diferente por ambiente
    if env == "dev":
        # Validación light
        assert data is not None
    elif env == "staging":
        # Validación completa
        validate_schema(data)
        validate_distributions(data)
    else:  # prod
        # Validación + alerting
        validate_and_alert(data)
    
    # 3. Training con recursos diferentes
    if env == "dev":
        model = train(data, resources="small")
    else:
        model = train(data, resources="large")
    
    # 4. Evaluation con thresholds diferentes
    metrics = evaluate(model, data)
    
    if env == "dev":
        # Cualquier resultado está OK
        register_model(model, env="dev")
    elif env == "staging":
        # Debe superar baseline
        if metrics.accuracy > BASELINE:
            register_model(model, env="staging")
    else:  # prod
        # Debe superar baseline + pasar A/B test
        if metrics.accuracy > BASELINE:
            deploy_canary(model)
            if canary_metrics_ok():
                promote_to_prod(model)
```

---

**La infraestructura también cambia:**

```python
DEV:
- Local machine o VM compartida
- CPU only (GPUs caras para dev)
- Sin redundancia
- Puede fallar sin problema

STAGING:
- Cluster dedicado
- Similar a prod (pero más pequeño)
- Con monitoring (pero no alerting crítico)
- Datos de prod pero anonymizados

PROD:
- Cluster de alta disponibilidad
- GPUs/recursos necesarios
- Redundancia + auto-scaling
- Monitoring + alerting 24/7
- Backup + disaster recovery
```

---

**Los errores más comunes:**

**ERROR 1: "No tenemos staging para ML"**

```python
Resultado: Deploy directo a producción
Primera vez que ves datos reales: en prod
Cuando algo falla: afectas usuarios
```

**ERROR 2: "Staging usa los mismos datos que dev"**

```python
Resultado: Validas con sample de 1k rows
Funciona en staging (1k rows)
Falla en prod (500GB) por memory/performance
```

**ERROR 3: "Prod y staging comparten infraestructura"**

```python
Resultado: Experimento en staging consume recursos
Prod se degrada porque staging le robó memoria
Incident a las 3am
```

**ERROR 4: "Un solo model registry para todo"**

```python
Resultado: 1000 experimentos mezclados con modelos de prod
Nadie sabe qué modelo está en producción
Rollback imposible
```

---

**Arquitectura recomendada:**

```python
┌─────────────────────────────────────────────────┐
│                    DEV                          │
│  - Local/shared VM                              │
│  - Sample data (1k-10k rows)                    │
│  - Rapid iteration                              │
│  - No strict validation                         │
└─────────────┬───────────────────────────────────┘
              │ promote best experiment
              ▼
┌─────────────────────────────────────────────────┐
│                  STAGING                        │
│  - Prod-like cluster (smaller)                  │
│  - Prod snapshot data (last week/month)         │
│  - Full validation pipeline                     │
│  - Metrics vs prod baseline                     │
└─────────────┬───────────────────────────────────┘
              │ if approved
              ▼
┌─────────────────────────────────────────────────┐
│                   PROD                          │
│  - HA cluster                                   │
│  - Real-time data                               │
│  - Shadow → Canary → Full rollout               │
│  - 24/7 monitoring                              │
└─────────────────────────────────────────────────┘
```

---

**Implementación práctica:**

**Opción 1: Namespaces (si usas K8s)**

```yaml
# dev namespace
namespace: ml-dev
resources:
  memory: 4GB
  cpu: 2

# staging namespace  
namespace: ml-staging
resources:
  memory: 16GB
  cpu: 8

# prod namespace
namespace: ml-prod
resources:
  memory: 64GB
  cpu: 32
  replicas: 3
```

**Opción 2: Cuentas separadas (AWS/GCP/Azure)**

```bash
dev-account/
├── s3://dev-ml-data/
├── dev-model-registry
└── dev-feature-store

staging-account/
├── s3://staging-ml-data/
├── staging-model-registry
└── staging-feature-store

prod-account/
├── s3://prod-ml-data/
├── prod-model-registry
└── prod-feature-store
```

**Opción 3: Prefixes (si no puedes separar infraestructura)**

```python
CONFIGS = {
    "dev": {
        "data_bucket": "ml-data",
        "data_prefix": "dev/",
        "model_registry": "models/dev/",
    },
    "staging": {
        "data_bucket": "ml-data",
        "data_prefix": "staging/",
        "model_registry": "models/staging/",
    },
    "prod": {
        "data_bucket": "ml-data-prod",  # Bucket separado
        "data_prefix": "prod/",
        "model_registry": "models/prod/",
    }
}
```

---

**Checklist de separación de ambientes:**

**Datos:**

* \[ \] Dev usa sample/synthetic data
    
* \[ \] Staging usa snapshot de prod
    
* \[ \] Prod usa datos reales
    
* \[ \] Datos de prod nunca en dev (privacidad)
    

**Modelos:**

* \[ \] Model registry por ambiente
    
* \[ \] Promotion workflow claro (dev → staging → prod)
    
* \[ \] Rollback fácil en prod
    
* \[ \] Experiments solo en dev/staging
    

**Features:**

* \[ \] Feature store por ambiente
    
* \[ \] Features experimentales solo en dev
    
* \[ \] Monitoring de features en prod
    

**Infraestructura:**

* \[ \] Recursos separados por ambiente
    
* \[ \] Prod no comparte recursos con dev/staging
    
* \[ \] Credenciales diferentes por ambiente
    
* \[ \] Logs/metrics separados
    

**Proceso:**

* \[ \] CI/CD diferente por ambiente
    
* \[ \] Approvals para promote a prod
    
* \[ \] Testing en staging antes de prod
    
* \[ \] Canary/shadow deploys en prod
    

---

**Mi recomendación como Platform Engineer:**

**Fase 1 - Mínimo viable:**

```markdown
- Dev: local con sample data
- Prod: cluster con datos reales
- Deploy: manual con checklist
```

**Fase 2 - Agregar staging:**

```markdown
- Staging: snapshot semanal de prod
- Validation automática en staging
- Deploy: semi-automático con approval
```

**Fase 3 - Full separation:**

```markdown
- 3 ambientes completamente separados
- CI/CD automatizado
- Canary deploys
- A/B testing
```

**No intentes hacer Fase 3 desde día 1.**

**Mañana:**

Ya sabes ejecutar pipelines en diferentes ambientes.

Pero hay un problema: **todo esto es código que vive en algún lado.**

¿Cómo conectas Terraform, Helm, K8s, GitOps con MLOps?

**Infrastructure as Code para ML. Y por qué no es solo** `terraform apply`.

---

**Tu turno:**

* ¿Cuántos ambientes tienen para ML?
    
* ¿O es "dev es mi laptop y prod es... también mi laptop"?
    

---
