modulo 17 di 24 / Ore 41-60

Moduli 17-24 / Checkpoint 60 ore

Scegliere una variante: database, API o mock server

Confrontare le tre alternative infrastrutturali per il Registro — database leggero, API REST e mock server — e scegliere quella giusta per il proprio contesto.

30 minArchitettura del software

Scegliere una variante: database, API o mock server

Questa lezione appartiene al Modulo 17 — Variante database o API.

Le tre varianti a confronto

Il Registro del laboratorio usa localStorage per default. Esistono tre alternative più avanzate, ognuna adatta a contesti diversi.

Variante 1: database leggero (SQLite / JSON file)

Un database leggero come SQLite gira senza un server separato — il file del database è nella stessa cartella del progetto. In Node.js si usa con librerie come better-sqlite3.

// infrastructure/archivioStrumentiSQLite.js
import Database from "better-sqlite3";

const db = new Database("registro.db");

db.exec(`
  CREATE TABLE IF NOT EXISTS strumenti (
    id TEXT PRIMARY KEY,
    nome TEXT NOT NULL,
    categoria TEXT NOT NULL,
    stato TEXT NOT NULL DEFAULT 'disponibile'
  )
`);

function creaArchivioStrumentiSQLite() {
  function leggiTutti() {
    return db.prepare("SELECT * FROM strumenti").all();
  }

  function trovaPerId(id) {
    return db.prepare("SELECT * FROM strumenti WHERE id = ?").get(id) ?? null;
  }

  function salva(strumento) {
    db.prepare(`
      INSERT INTO strumenti (id, nome, categoria, stato)
      VALUES (@id, @nome, @categoria, @stato)
      ON CONFLICT(id) DO UPDATE SET nome=@nome, categoria=@categoria, stato=@stato
    `).run(strumento);
  }

  return { leggiTutti, trovaPerId, salva };
}

Quando scegliere: vuoi dati persistenti, transazioni atomiche, e il progetto gira su Node.js. Non serve un server separato.

Limite: non funziona nel browser — richiede Node.js o un backend.


Variante 2: API REST

Il Registro parla con un server che espone endpoint HTTP. Il frontend chiama fetch("/api/strumenti") e il server gestisce il database.

// infrastructure/archivioStrumentiAPI.js
function creaArchivioStrumentiAPI(baseUrl = "/api") {
  async function leggiTutti() {
    const risposta = await fetch(`${baseUrl}/strumenti`);
    if (!risposta.ok) throw new Error("ARCHIVIO_NON_DISPONIBILE");
    return risposta.json();
  }

  async function trovaPerId(id) {
    const risposta = await fetch(`${baseUrl}/strumenti/${id}`);
    if (risposta.status === 404) return null;
    if (!risposta.ok) throw new Error("ARCHIVIO_NON_DISPONIBILE");
    return risposta.json();
  }

  async function salva(strumento) {
    const risposta = await fetch(`${baseUrl}/strumenti`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(strumento)
    });
    if (!risposta.ok) throw new Error("ARCHIVIO_NON_DISPONIBILE");
  }

  return { leggiTutti, trovaPerId, salva };
}

Quando scegliere: vuoi dati condivisi tra più utenti, o hai già un backend disponibile.

Limite: richiede un server reale. Durante lo sviluppo, serve un mock server per non dipendere dal backend.


Variante 3: mock server

Un mock server simula un’API reale restituendo risposte predefinite, senza un vero backend. Strumenti come json-server o msw (Mock Service Worker) lo permettono in pochi minuti.

Con json-server:

# Installa e avvia
npm install -g json-server
json-server --watch db.json --port 3001
// db.json
{
  "strumenti": [
    { "id": "s1", "nome": "Trapano", "categoria": "Elettrico", "stato": "disponibile" }
  ],
  "prestiti": []
}

Il mock server espone automaticamente:

  • GET /strumenti → lista tutti
  • GET /strumenti/:id → trova per ID
  • POST /strumenti → salva
  • PUT /strumenti/:id → aggiorna
  • DELETE /strumenti/:id → elimina

Il tuo adapter API (creaArchivioStrumentiAPI) funziona senza modifiche puntando a http://localhost:3001.

Quando scegliere: stai sviluppando il frontend e il backend non è ancora pronto, oppure vuoi testare il comportamento con un’API reale senza scrivere un server.

Limite: i dati in db.json si resettano se il file viene sovrascritto. Non è per la produzione.


Tabella di confronto

Caratteristica localStorage Database SQLite API REST Mock server
Setup Zero Libreria NPM Server backend json-server
Funziona nel browser ✓ (via fetch) ✓ (via fetch)
Dati condivisi Parziale
Transazioni Dipende
Adatto per sviluppo Con mock
Adatto per produzione Sì (app desktop)

Cosa cambia nel codice del Registro

Niente, se l’architettura è corretta. Il caso d’uso registraPrestito riceve l’archivio come dipendenza — non sa quale variante viene usata.

// main.js — l'unico punto che cambia
// Variante localStorage:
const archivioStrumenti = creaArchivioStrumentiLocalStorage();

// Variante SQLite (Node.js):
// const archivioStrumenti = creaArchivioStrumentiSQLite();

// Variante API:
// const archivioStrumenti = creaArchivioStrumentiAPI("http://localhost:3001");

const registraPrestito = creaRegistraPrestito({ archivioStrumenti, archivioPrestiti });

Una riga cambia. Il resto del sistema rimane invariato.

Come scegliere per il tuo contesto

Stai sviluppando nel browser senza server → localStorage o mock server
Stai sviluppando con Node.js e vuoi persistenza reale → SQLite
Il progetto ha già un backend → API REST
Vuoi testare il comportamento con fetch senza un server reale → mock server
Stai preparando la presentazione finale → localStorage (il più semplice)

Procedura guidata

  1. Scegli la variante più adatta al tuo contesto tra le quattro.
  2. Crea il nuovo adapter in infrastructure/ che rispetta il contratto (leggiTutti, trovaPerId, salva).
  3. Sostituisci l’archivio in main.js — solo quella riga.
  4. Verifica che il Registro funzioni identicamente con la nuova variante.
  5. Documenta la scelta nel README con motivazione.

Attività in classe

## Scelta della variante infrastrutturale

Variante scelta:

Motivo della scelta:

Setup necessario:

Adapter creato (file):
  - metodi implementati: leggiTutti, trovaPerId, salva

Riga in main.js modificata:

Verifica funzionamento:

Limite noto della variante scelta:

Spiegazione guidata per studiare

Le tre varianti (database, API, mock server) risolvono problemi diversi. La scelta dipende dal contesto — non esiste la variante “migliore” in assoluto. Un mock server è perfetto durante lo sviluppo ma inutile in produzione. SQLite è eccellente per un’app desktop ma non serve in un laboratorio scolastico con browser.

Il punto centrale è: la scelta dell’infrastruttura non cambia il dominio né i casi d’uso. Questa è la prova concreta che la separazione dei livelli funziona. Se cambiare variante richiede di modificare registraPrestito.js, c’è una dipendenza nascosta da correggere prima.

Il rischio tipico è scegliere la variante più complicata disponibile invece della più semplice che risolve il problema. Per un laboratorio scolastico, localStorage è spesso sufficiente. La complessità aggiuntiva va giustificata con un problema reale.

Passo per passo nel progetto

  1. Descrivi il problema che vuoi risolvere passando a una nuova variante.
  2. Scegli la variante minima che risolve quel problema.
  3. Scrivi il nuovo adapter — rispetta esattamente il contratto { leggiTutti, trovaPerId, salva }.
  4. Sostituisci in main.js — una riga.
  5. Verifica: registra uno strumento, apri un prestito, cerca per categoria. Tutto funziona?

Esempio da leggere lentamente

// I tre adapter rispettano lo stesso contratto —
// il caso d'uso non sa quale sta usando

// localStorage
const archivio = creaArchivioStrumentiLocalStorage();
// → leggiTutti() restituisce JSON.parse(localStorage...)
// → salva() chiama localStorage.setItem(...)

// mock server
const archivio = creaArchivioStrumentiAPI("http://localhost:3001");
// → leggiTutti() chiama fetch("http://localhost:3001/strumenti")
// → salva() chiama fetch("http://localhost:3001/strumenti", { method: "POST" })

// SQLite (Node.js)
const archivio = creaArchivioStrumentiSQLite();
// → leggiTutti() esegue SELECT * FROM strumenti
// → salva() esegue INSERT OR REPLACE INTO strumenti

// Il caso d'uso:
const registraPrestito = creaRegistraPrestito({ archivioStrumenti: archivio, ... });
// → non sa quale archivio ha ricevuto — non gli interessa

Prova di comprensione

  • Qual è la differenza tra un mock server e un’API REST reale?
  • Se scegli la variante API, quali file del Registro devi modificare?
  • Quale variante sceglieresti se volessi condividere i dati tra tre computer nell’aula?

Errori da evitare

  • scegliere la variante più complessa perché “è più professionale”;
  • implementare il nuovo adapter ma dimenticare di aggiornare main.js;
  • testare la nuova variante senza verificare tutti gli scenari (non solo il caso felice);
  • non documentare perché hai scelto quella variante.

Prodotto da consegnare

Può essere:

  • il nuovo adapter implementato con i tre metodi del contratto;
  • la modifica a main.js con la nuova variante attiva;
  • una nota nel README che spiega la variante scelta e i motivi.

Checklist di chiusura

  • Ho scelto una variante e motivato la scelta
  • Il nuovo adapter ha leggiTutti, trovaPerId, salva con le stesse firme
  • Ho modificato solo main.js per attivare la nuova variante
  • Il Registro funziona identicamente con la nuova variante
  • Ho documentato la scelta nel README

Domande per la revisione

  • Hai dovuto modificare file fuori da infrastructure/ e main.js? Se sì, c’era una dipendenza nascosta.
  • La variante scelta risolve il problema per cui l’hai scelta?
  • Qual è il limite principale della variante scelta?

Risultato atteso

Alla fine lo studente deve saper dire:

Ho scelto la variante [X] perché [motivo concreto].
Ho implementato l'adapter in [file].
Ho modificato solo main.js per attivarlo.
Il Registro funziona identicamente — ho verificato con [scenario].
Il limite principale della variante è [limite].

Se questa spiegazione non è possibile, la lezione non è ancora davvero conclusa.