Approfondimenti e Trend sull'Intelligenza Artificiale

Disaccoppiare logica di business e framework UI nel vibe coding

5 min di lettura
Laptop 3/4 su scrivania scura, editor a due riquadri con /core/checkout.py e /ui/CheckoutPage.tsx separati da una linea arancione
Windows macOS Linux
Immagine generata: Alex Lunalbi · Gemini · ai riparo

Nel vibe coding l'IA può mescolare business logic e UI. Ecco come disaccoppiare core e framework: cartelle, contratti e prompt che tengono i layer separati.

Se chiedi a un assistente IA di aggiungere una funzione all’app, la strada che può scegliere è la più breve: un unico file in cui un componente React/Vue interroga il database, valida i dati e disegna i bottoni.

Va bene per un prototipo di mezza giornata. Appena il progetto cresce, diventa difficile da mantenere e può aprire falle (logica di sicurezza mescolata alla UI). Nel pezzo sull’architettura di un progetto vibe-coded abbiamo già fissato cartelle e confini; qui scendo sul punto concreto: core vs UI.

Nei miei test con Cursor, prevenire costa meno che rifattorizzare. Ti mostro come tracciare il confine, quali prompt usare e come leggere il diff per rifiutare codice accoppiato.

Cosa significa separare logica e UI

Un file di logica non dovrebbe sapere come i dati vengono disegnati. Un file UI non dovrebbe sapere come i dati vengono calcolati o salvati.

Responsabilità Core (business) UI (framework)
Calcoli e regole Sconti, validazioni, permessi Sì No
Accesso ai dati SQL, API esterne, storage Sì No
Eventi visivi Click, hover, CSS No Sì
Stato di presentazione Modale aperta, spinner No Sì

ℹ️ Nota / Prerequisito operativo
Gli esempi usano un frontend moderno (React/Vue/Svelte) e uno strato TypeScript/Node. Il principio vale anche su altri stack: dipendenze verso l’interno, UI che chiama il core, non il contrario.

Fissa queste regole anche nel manifest / SPEC.md, così non le ripeti a ogni prompt.

Perché i modelli creano «god file»

Un god file fa tutto. I modelli possono generarli perché ottimizzano per una risposta che «funziona» in pochi scambi.

Se chiedi «aggiungi la pagina spese», è più semplice (per loro) un unico Spese.tsx con DB + totale + tabella. Separare tipi, servizi e componenti richiede pianificazione: senza vincoli espliciti, spesso non arriva.

Con Cursor, se il file esiste già, l’assistente può continuare ad appendere lì — e il monolite cresce.

Regola pratica: cartelle e import unidirezionali

1. Separazione nel file system

Fin dal giorno zero:

src/
├── core/     # regole, modelli, servizi (niente React/Vue)
└── ui/       # componenti, layout, stato di presentazione

Non buttare tutto in src/components.

2. Import unidirezionali

Le dipendenze puntano verso l’interno: ui → core. Mai core → ui.

🚨 Avviso critico — Import nel core
Se in src/core/ trovi import React, import { ref } from 'vue', window o hook di stato, il confine è violato. Rifiuta il diff e chiedi di spostare la logica.

L’UI importa funzioni pure dal core; il core non conosce bottoni né CSS.

Esempio: contratto e prompt a due fasi

Obiettivo: aggiungere una spesa.

Prompt da evitare

Crea un componente React per aggiungere una spesa. Campo importo e categoria, salva su Supabase, errore se importo negativo.

Risultato tipico: query + UI nello stesso file.

Prompt migliore (due fasi)

Fase 1 — Core

Scrivi la business logic in src/core/spese.ts.
Crea l'interfaccia Spesa e una funzione pura
validaAggiungiSpesa(importo, categoria) che valida (importo > 0, categoria non vuota)
e restituisce un oggetto sicuro o solleva un errore.
NESSUN import di React/Vue. Nessuna logica visiva. Nessuna query DB in questo file.

Esempio di output atteso:

// src/core/spese.ts
export interface Spesa {
  id: string;
  importo: number;
  categoria: string;
}

export function validaAggiungiSpesa(
  importo: number,
  categoria: string,
): Omit<Spesa, "id"> {
  if (importo <= 0) {
    throw new Error("L'importo deve essere maggiore di zero.");
  }
  if (!categoria) {
    throw new Error("La categoria è obbligatoria.");
  }
  return { importo, categoria };
}

Fase 2 — UI (solo dopo aver verificato il core)

Crea src/ui/AggiungiSpesa.tsx.
Form + stato locale.
Usa ESCLUSIVAMENTE validaAggiungiSpesa da src/core/spese.ts per la validazione
prima del salvataggio (anche se per ora è stub).
Non duplicare le regole di validazione nel componente.

Checklist sul diff (5 allarmi)

Prima di Accept:

  1. ORM/SQL nell’UI — sql, client DB, fetch «grezze» di dominio dentro un .tsx/.vue → spostale in core (o in un layer API dedicato).
  2. Validazione duplicata — if (valore < 0) nel componente invece della funzione core → rifiuta.
  3. Trasformazioni pesanti nel render — map/filter di dominio lunghi nel JSX → estrai formatter/servizio in core.
  4. Framework nel core — window, document, hook → violazione.
  5. Nomi bugiardi — UserService che restituisce JSX → design sbagliato.

💡 Consiglio pratico — Guarda il path
Nell’intestazione del diff di Cursor vedi il percorso file. Se la logica finisce sotto ui/ (o viceversa), fermati prima di Accept.

Tre errori da fretta

  1. «Tanto è un MVP» — nel vibe coding l’MVP diventa produzione in poche ore; disaccoppiare dopo costa di più.
  2. UI + DB nello stesso prompt — l’IA può scegliere la scorciatoia e ignorare i confini.
  3. Testare solo a occhio — se la UI «si vede», il core può comunque essere sporco. Separato, puoi testare le funzioni senza browser.

Domande Frequenti (FAQ)

Cosa significa disaccoppiare business logic e UI?

Mettere regole e trasformazioni dati in file indipendenti da come lo schermo li mostra (form, bottoni, CSS). L’UI chiama il core; non reinventa le regole.

Perché Cursor o ChatGPT mettono tutto in un file?

Spesso è la risposta più corta e «completa» in un solo passo. Senza vincoli di cartelle e import, il monolite è il default pratico.

La logica di business può importare React o Vue?

No. Il core resta agnostico: in teoria potresti cambiare UI senza riscrivere le regole.

In che ordine genero core e UI?

Tipi/contratto → funzioni core → verifica → UI che importa il core. Allineato all’ordine moduli della guida architettura.

Serve sempre un’API HTTP in mezzo?

No. In un monolite locale o con Server Actions, l’UI può importare direttamente il core. Il punto è la responsabilità dei file, non obbligatoriamente REST.

E i React Server Components / Server Actions?

Anche lì conviene estrarre regole e accesso dati in moduli core (o server-only) invece di mescolare query e markup «perché lo stack lo permette». Meno caos quando l’IA modifica il pezzo.

Letture opzionali

Alex Lunalbi

Alex Lunalbi

Security & privacy

Dona su PayPal

Scrivo di sicurezza digitale pratica e codice IA. Su ai riparo ogni procedura è verificata su macchine reali.

Tag
  • vibe coding,
  • architettura,
  • ui,
  • moduli