Ogni Scelta Ha una Ragione
Ho cambiato ambiente di sviluppo molte volte in quarant'anni. Ogni volta che credevo di aver trovato la configurazione definitiva, arrivava qualcosa di meglio. Oggi ho smesso di cercare. Ecco cosa uso — e soprattutto perché.
Da Docker Desktop e Devcontainer a WSL con Docker Nativo
Il mio punto di partenza è stato Docker Desktop su Windows con i devcontainer — in particolare l'immagine Bookworm di Microsoft, già configurata con Node.js e TypeScript. Un ottimo punto di partenza: veloce da avviare, riproducibile, con tutto dentro un container.
Il problema non è quello che fanno i devcontainer. Il problema è il livello che aggiungono. Docker Desktop su Windows esegue i container Linux all'interno di una macchina virtuale che gestisce internamente. Ogni operazione sul filesystem attraversa più livelli di astrazione: il filesystem Windows, la VM, il container. Il risultato è visibile in pratica: build lente, comportamento imprevedibile dei permessi sui volumi, e un attrito costante di basso livello che si accumula nel corso della giornata.
La soluzione è chirurgica: rimuovere completamente Docker Desktop e installare Docker Engine nativamente dentro una distro WSL2. Con questa configurazione il filesystem è Linux reale, il runtime del container è nativo, e le performance sono performance reali. Nessun livello di traduzione, nessun overhead della VM, nessuna sorpresa sui permessi.
Questo ragionamento vale anche per chi usa Linux direttamente con i devcontainer: il layer aggiuntivo di containerizzazione aggiunge complessità senza benefici equivalenti, una volta che la distro è già stabile e ben configurata.
Perché Debian — e Perché Trixie Nello Specifico
Quando sono passato a un ambiente WSL nativo ho dovuto scegliere una distribuzione base. Il candidato ovvio era Ubuntu — diffuso, ben documentato, consigliato da Microsoft. L'ho provato. Funzionava, fino a quando non ha funzionato.
Il problema è emerso mentre sviluppavo la mia prima applicazione NestJS con autenticazione JWT. Volevo deployare il backend su un'immagine Ubuntu LTS perché era più leggera. La libreria bcrypt — che compila binding nativi tramite node-gyp — falliva. La versione di GLIBC e il build environment di quella release Ubuntu non erano allineati con quello che i binari compilati si aspettavano. La correzione richiedeva ricompilare dai sorgenti, aggiustare il build environment, e il risultato era comunque fragile. Ho sostituito con un'immagine Bookworm lite e il problema è scomparso.
Per WSL uso Trixie — il ramo testing di Debian, completamente compatibile con Bookworm. L'immagine WSL ufficiale di Bookworm non esiste nel Microsoft Store, ma Trixie è disponibile e si comporta in modo identico nella pratica. Debian mi dà una base minimale e stabile con versioni prevedibili delle librerie di sistema. I moduli nativi di Node.js — bcrypt, argon2, canvas, qualsiasi cosa compili con node-gyp — si compilano correttamente al primo tentativo, senza dover modificare il build environment.
Il principio è semplice: Ubuntu è opinionated e si aggiorna velocemente. Debian è minimale e prevedibile. Per un ambiente di sviluppo da cui dipendi ogni giorno, la prevedibilità vale più della comodità.
Perché VSCode
Ho usato molti editor nel corso degli anni. Oggi uso VSCode — non perché sia il migliore in assoluto, ma perché ha la migliore integrazione con tutto quello che uso concretamente.
L'estensione WSL Remote è il pezzo chiave. Permette a VSCode su Windows di connettersi direttamente al filesystem Linux dentro WSL, in modo trasparente. Il terminale, il file explorer, il debugger, l'integrazione con Git — tutto gira nell'ambiente Linux mentre l'interfaccia rimane su Windows. La distanza tra i due sistemi operativi scompare completamente.
Al di là di WSL, l'ecosistema di estensioni di VSCode è imbattibile per il lavoro pratico quotidiano. Formattazione, linting, gestione Docker, client database, client REST, visualizzazione Git — c'è tutto, mantenuto e consistente. Ho smesso di valutare alternative quando ho capito che quel tempo lo spendevo meglio costruendo cose.
Perché un Assistente AI per il Codice — e Come lo Uso
Oggi uso GitHub Copilot. La scelta dello strumento specifico è secondaria — il ragionamento vale allo stesso modo per Claude Code o qualsiasi strumento simile. Quello che conta non è lo strumento. Quello che conta è come lo usi.
Un assistente AI usato senza contesto è uno strumento generico. Genera codice plausibile per il progetto medio. Il tuo progetto non è medio — ha uno stack specifico, decisioni architetturali specifiche, convenzioni specifiche che hai impiegato tempo a stabilire. Se l'assistente non conosce queste cose, ogni suggerimento ha bisogno di correzioni. Il back-and-forth costa più tempo di quanto ne risparmi.
La soluzione è la directory .github/instructions/. Sono file markdown che dicono a Copilot — esplicitamente, in linguaggio naturale strutturato — cos'è il tuo progetto, come è organizzato, quali regole si applicano, quali pattern seguire. Mantengo file di istruzioni separati per diversi tipi di file: uno per la struttura dei contenuti, uno per le convenzioni CSS e PHP, uno per le regole generali del progetto.
La differenza non è sottile. Un Copilot che conosce il tuo progetto genera output che assomiglia al codice che avresti scritto tu. Segue le tue convenzioni di naming, rispetta la tua architettura, usa le librerie che usi tu. Smette di essere un assistente generico e diventa un collaboratore che capisce il contesto.
Costruire e mantenere questi file di istruzioni è lavoro. È anche il lavoro più redditizio che faccio su un progetto — perché ogni sessione successiva ne beneficia.