💻 Développement

dev-etl-designer

Conception de processus ETL/ELT pour l'intégration de données.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- dev-etl-designer --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } dev-etl-designer -Launch"

🚀 Déjà installé ?

claude "/dev-etl-designer"

Ou tapez /dev-etl-designer dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

ETLELTextractiontransformationloaddata integrationdata warehouseSSISTalendInformatica

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/skills/dev-etl-designer ~/.claude/skills/

Payload du plugin : skills/dev-etl-designer · source éditable : dev-skills/etl-designer

📖 Manuel

ETL Designer

Workflow en étapes

1. Analyse des sources et destinations

2. Choix ETL vs ELT

CritèreETLELT
Puissance de la destinationfaible (on-prem DWH)forte (Snowflake, BigQuery)
Données sensiblesmasquage/anonymisation tôtplus difficile à isoler
Flexibilité explorationfaibleforte (raw zone conservée)
Coût computemoteur ETL dédiéwarehouse paie la transformation

Décision à documenter : justifier le choix dans un ADR ou un commentaire de pipeline.

3. Extraction

Full load — snapshot complet ; simple, utiliser quand la table source est petite (<1 M lignes) ou sans colonne de delta fiable.

Incrémental par timestamp/ID :

-- Extraction SQL incrémentale
SELECT *
FROM source_table
WHERE updated_at > :last_run_ts
  AND updated_at <= :current_run_ts
ORDER BY updated_at;

CDC (Change Data Capture) — Debezium sur PostgreSQL/MySQL/SQL Server, Oracle GoldenGate, AWS DMS. Capturer INSERT/UPDATE/DELETE sans polling. Nécessite que le WAL ou le binlog soit activé.

Extraction API paginée (Python) :

def extract_all_pages(url, headers, page_size=200):
    results, cursor = [], None
    while True:
        params = {"limit": page_size, **({"cursor": cursor} if cursor else {})}
        r = requests.get(url, headers=headers, params=params, timeout=30)
        r.raise_for_status()
        data = r.json()
        results.extend(data["items"])
        cursor = data.get("next_cursor")
        if not cursor:
            break
    return results

4. Transformation

Ordre recommandé :

  1. Nettoyage — trim, normalisation casse, formats dates (ISO 8601), suppression des caractères invalides.
  2. Déduplication — window function sur clé naturelle + ROW_NUMBER().
  3. Enrichissement — lookup tables, API tiers (géocodage, scoring).
  4. Mapping de codes — table de correspondance versionnée en base ou fichier YAML.
  5. Calcul de KPIs — uniquement en fin de chaîne, sur données propres.
-- Déduplication avec window function
WITH ranked AS (
  SELECT *,
    ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY updated_at DESC) AS rn
  FROM staging.orders
)
INSERT INTO dw.orders
SELECT * EXCLUDE (rn) FROM ranked WHERE rn = 1;

5. Stratégie de chargement (Loading)

ModeQuand l'utiliserSnippet
Full refreshpetits référentiels, pas de SCDTRUNCATE + INSERT
Upsert/Mergetables transactionnelles, clé naturelle stableMERGE SQL ou INSERT … ON CONFLICT
SCD Type 1on écrase, pas d'historique requisUPDATE direct
SCD Type 2historisation obligatoire (audit, BI temps)colonnes valid_from, valid_to, is_current
Append-onlyévénements immuables (logs, factures)INSERT pur
-- MERGE Snowflake / SQL Server
MERGE INTO dw.customers AS tgt
USING staging.customers AS src
  ON tgt.customer_id = src.customer_id
WHEN MATCHED THEN
  UPDATE SET tgt.email = src.email, tgt.updated_at = src.updated_at
WHEN NOT MATCHED THEN
  INSERT (customer_id, email, created_at, updated_at)
  VALUES (src.customer_id, src.email, src.created_at, src.updated_at);

6. Error handling & idempotence

# Réconciliation source vs destination
def reconcile(src_count: int, dst_count: int, tolerance_pct: float = 0.01):
    diff_pct = abs(src_count - dst_count) / max(src_count, 1)
    if diff_pct > tolerance_pct:
        raise ValueError(f"Reconciliation failed: src={src_count}, dst={dst_count}, diff={diff_pct:.1%}")

7. Performance

# Chargement bulk Snowflake via connector
conn.cursor().execute(f"""
  COPY INTO {schema}.{table}
  FROM @my_stage/{filename}.parquet.gz
  FILE_FORMAT = (TYPE=PARQUET)
  PURGE = TRUE
""")

8. Orchestration & monitoring

Outils : Apache Airflow (DAG Python), Dagster (assets), dbt Cloud (scheduling dbt), Prefect, SSIS (on-prem legacy).

DAG Airflow minimal :

from airflow.decorators import dag, task
from pendulum import datetime

@dag(schedule="0 3 * * *", start_date=datetime(2026, 1, 1), catchup=False)
def orders_etl():
    @task
    def extract(): ...

    @task
    def transform(raw): ...

    @task
    def load(clean): ...

    load(transform(extract()))

orders_etl()

Monitoring obligatoire :


Garde-fous & anti-patterns

Anti-patternProblèmeSolution
SELECT * en extraction sans schéma fixérupture silencieuse à l'ajout de colonnessélectionner les colonnes explicitement, versionner le schéma
Transformation dans la requête d'extractioncouplage fort, difficile à testerséparer extraction brute et transformation
Chargement sans idempotencedoublons à chaque retryfenêtre temporelle explicite + upsert ou truncate
Pas de dead letterperte silencieuse d'enregistrements invalidestable d'erreurs systématique
ETL monolithique sans étapes atomiquesrollback impossible en cas d'échec partieldécouper en tâches redémarrables indépendamment
Secrets hard-codés dans le codefuite de credentialsvariables d'environnement ou vault (AWS Secrets Manager, Azure Key Vault)
Ignorer les fuseaux horairesdécalages silencieux autour du changement d'heurestocker et transmettre en UTC, convertir en aval

Bonnes pratiques 2026