Sempre più prodotti su cui lavoro hanno due componenti. Una è quella con cui interagiscono le persone: un’interfaccia Next.js, un’API Node.js, autenticazione e pagamenti. L’altra riguarda i modelli: inferenza, embedding, audio ed elaborazione dei dati. La prima parla TypeScript, la seconda Python. Padroneggiarli entrambi non significa collezionare linguaggi, ma presidiare il punto di contatto tra i due: proprio lì si rompono molti prodotti AI.
La buona notizia è che i due ecosistemi si somigliano più di quanto si pensi. A Zod corrisponde Pydantic; a tsc, mypy e pyright; a ESLint e Prettier, Ruff; a npm e pnpm, uv e Poetry. FastAPI è l’equivalente di Express e NestJS e genera OpenAPI dai modelli tipizzati. Applico la stessa disciplina su entrambi i fronti: tipi rigorosi, un formatter su cui non si discute, dipendenze bloccate e test in CI.
Il contratto tra i due è il file più importante del sistema. Lo definisco una volta e genero il resto: i modelli Pydantic in FastAPI producono uno schema OpenAPI, da cui derivano il client TypeScript e i relativi tipi. Se rinomini un campo in Python, la build Next.js fallisce prima che un utente possa vedere undefined. Per il lavoro asincrono, il contratto è un payload con uno schema su entrambi i lati, non un blocco JSON libero interpretato diversamente da ciascuno.
La separazione delle responsabilità resta netta. TypeScript gestisce identità, permessi, denaro e UI. Python gestisce il modello e nient’altro: riceve un job, svolge il lavoro pesante — una voce StyleTTS2, un batch di embedding o l’analisi di un documento — e restituisce il risultato. Il servizio Python non parla mai con il browser né decide chi può fare cosa. Le chiamate rapide viaggiano su HTTP, quelle lente su una coda, con timeout, retry e idempotenza da entrambe le parti.
Anche le differenze contano e vanno rispettate. Python è adatto ai prototipi in notebook, ma il notebook non è produzione: il codice pronto passa a un modulo con test. La concorrenza di Python non è l’event loop di Node: l’inferenza intensiva per la CPU va eseguita in processi worker o su un servizio GPU, non in un handler asincrono. Anche le unità di deploy sono diverse — un’immagine Node leggera contro un’immagine Python con CUDA e pesi del modello — quindi cambiano scalabilità, cache e costi.
Per il cliente, il vantaggio di un solo ingegnere su entrambi i fronti è chiaro: niente livello di traduzione tra «la persona AI» e «la persona web» e nessuna API di cui ciascuno incolpa l’altro. Se hai un modello che funziona in un notebook e un’app web che ancora non sa usarlo, mandami entrambi. Ti proporrò il contratto da inserire tra i due e la prima versione che porterei in produzione.
Dai al prossimo prodotto qualcuno che resti.
Pronto a iniziare? Scrivimi: posso cominciare subito e restare. Collaborazioni a lungo termine, non passaggi di consegne dopo due settimane. Parliamo del progetto, dei requisiti e del modo migliore per procedere.