Best Practice di Sviluppo 11 min di lettura 5 febbraio 2026

Dall'idea alla produzione: come le software house costruiscono piattaforme scalabili

Un resoconto trasparente su come una software house professionale porta un prodotto dal concept a una piattaforma production-ready — discovery, architettura, sviluppo, deployment e le lezioni difficili apprese scalando sistemi reali.

DR

Davide Russo

Platform Engineer

Ogni software house ha una storia sul progetto che sembrava semplice nel brief e si è trasformato in una lotta di sei mesi. Scope sottostimato, architettura scelta per le ragioni sbagliate, deployment lasciato all'ultima settimana, performance testate solo in locale. Questo articolo è uno sguardo trasparente su come strutturiamo il percorso dall'idea alla produzione — non la versione idealizzata, ma il processo reale che usiamo dopo aver imparato da quegli errori iniziali.

Fase 1: Discovery — il lavoro prima del lavoro

La discovery è la fase più sottovalutata di un progetto software. La maggior parte dei clienti vuole saltarla e la maggior parte dei team di sviluppo junior è felice di assecondarlo — la discovery non produce codice e tutti sono ansiosi di iniziare a costruire. Ma il costo di una decisione presa alla settimana otto che avrebbe potuto essere presa alla settimana uno si misura sempre in mesi di rework.

Cosa produce la discovery

  • Problem statement: quale specifico problema operativo o di business stiamo risolvendo? Come viene misurato oggi? Come appare il successo in termini numerici?
  • Flussi utente: l'insieme completo delle azioni che un utente deve compiere per raggiungere il proprio obiettivo — non wireframe, ma percorsi narrativi.
  • Bozza del modello dati: quali sono le entità core e le loro relazioni? Da dove provengono i dati e dove devono arrivare?
  • Inventario delle integrazioni: ogni sistema di terze parti a cui la piattaforma deve connettersi, con documentazione API esaminata e flussi di autenticazione mappati.
  • Registro dei rischi: i 5 principali rischi tecnici, di prodotto e organizzativi e una strategia di mitigazione per ciascuno.
  • Definition of done: criteri espliciti e misurabili per ogni fase di delivery.

Una discovery approfondita richiede tipicamente due settimane. Previene due mesi di rework. Il ROI è chiaro, eppure rimane la fase più frequentemente saltata nello sviluppo software delle agenzie.

Fase 2: Design dell'architettura

L'architettura non riguarda la scelta dello stack più sofisticato — riguarda la scelta dello stack più semplice che soddisfa i requisiti noti con spazio per evolvere. Ogni componente non necessario nell'architettura iniziale è un onere di manutenzione futuro e un ostacolo di onboarding per ogni sviluppatore che si unirà al progetto.

L'Architecture Decision Record

Ogni decisione architetturale significativa — il motore database, il pattern di messaggistica, il meccanismo di autenticazione, il modello di deployment — dovrebbe essere documentata in un Architecture Decision Record (ADR). Un ADR cattura: il contesto e i vincoli che hanno portato alla decisione, le opzioni considerate, l'opzione scelta e la motivazione, e le conseguenze della scelta.

ADR-003-message-broker.mdmarkdown
# ADR-003: Selezione Message Broker

## Stato: Accettato

## Contesto
La piattaforma richiede comunicazione asincrona tra il servizio ordini,
il servizio inventario e il servizio notifiche. Il volume atteso è di 50.000
eventi/giorno al lancio, scalando a ~500.000 eventi/giorno entro 18 mesi.

## Opzioni considerate
1. **RabbitMQ**: maturo, basato su AMQP, ottima semantica di routing, overhead ops ridotto
2. **Apache Kafka**: alto throughput, event log, replay, alto overhead operativo
3. **AWS SQS**: managed, basso overhead, routing limitato, nessun replay

## Decisione
RabbitMQ deployato su CloudAMQP (servizio managed).

## Motivazione
- Il volume non giustifica la complessità operativa di Kafka in questa fase
- Il routing con topic exchange copre i requisiti di fan-out
- Il servizio managed CloudAMQP elimina l'overhead operativo
- La migrazione a Kafka è possibile a volumi più alti senza cambiare le interfacce dei servizi

## Conseguenze
- Nessun replay degli eventi da offset arbitrario (mitigato memorizzando gli eventi su PostgreSQL)
- Il team operativo deve imparare RabbitMQ (curva di apprendimento bassa)

Fase 3: Sviluppo — struttura degli sprint e quality gate

Lavoriamo con sprint di due settimane con una struttura costante. I primi tre giorni sono dedicati allo sviluppo del deliverable principale dello sprint. I successivi tre giorni completano i deliverable secondari e affrontano il debito tecnico. Gli ultimi quattro giorni sono dedicati a test, code review, documentazione e preparazione della demo dello sprint. Questo ritmo previene il pattern comune in cui i test vengono compressi all'ultimo giorno.

Quality Gate

Ogni pull request deve superare quality gate automatici prima che inizi la revisione umana. Eseguire manualmente una suite di test completa è troppo lento e applicato in modo non uniforme — l'automazione è l'unico meccanismo di enforcement affidabile.

.github/workflows/ci.ymlyaml
name: CI Quality Gate

on:
  pull_request:
    branches: [main, develop]

jobs:
  quality-gate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: "pnpm"

      - name: Installa dipendenze
        run: pnpm install --frozen-lockfile

      - name: Verifica tipi TypeScript
        run: pnpm tsc --noEmit

      - name: Lint
        run: pnpm lint

      - name: Test unitari con copertura
        run: pnpm test:cov
        env:
          CI: true

      - name: Verifica soglia copertura
        run: |
          COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
          if (( $(echo "$COVERAGE < 80" | bc -l) )); then
            echo "Copertura $COVERAGE% sotto la soglia dell'80%"
            exit 1
          fi

      - name: Test di integrazione
        run: pnpm test:integration
        env:
          DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test

Fase 4: Infrastruttura e deployment

L'infrastruttura deve essere trattata come codice fin dal primo giorno. Creare infrastruttura manualmente tramite la console cloud è veloce inizialmente e catastrofico quando devi riprodurre un ambiente, fare debug di un incidente o fare onboarding di un nuovo membro del team. Usiamo Terraform per l'infrastruttura, Docker per la containerizzazione e GitHub Actions per il CI/CD.

Strategia degli ambienti

Strategia degli ambienti

SviluppoStack Docker Compose locale. Ambiente completo riproducibile in locale in pochi minuti.
StagingArchitettura identica alla produzione, 20% della capacità. Usato per test di integrazione e UAT del cliente.
ProduzioneStack completo con auto-scaling, RDS Multi-AZ, CloudFront, alert PagerDuty.

Deployment senza downtime

ecs-service-definition.jsonyaml
{
  "deploymentConfiguration": {
    "deploymentCircuitBreaker": {
      "enable": true,
      "rollback": true
    },
    "minimumHealthyPercent": 100,
    "maximumPercent": 200
  },
  "deploymentController": {
    "type": "ECS"
  },
  "healthCheckGracePeriodSeconds": 30
}

// Rolling deployment: ECS avvia i nuovi task prima di fermare quelli vecchi.
// Circuit breaker: se il nuovo deployment fallisce gli health check,
// ECS fa automaticamente rollback alla task definition precedente.

Fase 5: Observability — non puoi risolvere ciò che non puoi vedere

L'observability è la capacità di comprendere lo stato interno di un sistema dalle sue uscite esterne. I tre pilastri sono le metriche (come si comporta il sistema?), i log (cosa è successo e quando?) e le trace (come è fluita questa richiesta attraverso il sistema?). In produzione, avrai bisogno di tutti e tre.

  • Metriche: strumenta ogni servizio con metriche Prometheus — tasso di richieste HTTP, tasso di errori, percentili di latenza (p50, p95, p99), profondità della coda, utilizzo del connection pool del DB.
  • Logging strutturato: emetti log JSON con campi coerenti (traceId, tenantId, userId, operazione, durata). Non loggare mai stringhe in chiaro in produzione.
  • Distributed tracing: propaghi il contesto trace OpenTelemetry attraverso tutti i confini di servizio. Una singola trace deve mostrare il percorso completo di una richiesta.
  • Alert: PagerDuty o Opsgenie per picchi di latenza p95, anomalie nel tasso di errori, soglie di profondità delle code e lag della replica del database.
  • Dashboard: dashboard Grafana per ogni servizio con metriche RED (Rate, Error, Duration) visibili a colpo d'occhio.

Fase 6: Scalabilità — proattiva, non reattiva

La maggior parte del lavoro di scalabilità avviene prima che il traffico arrivi, non durante l'incidente. Il load testing su infrastruttura simile alla produzione identifica i colli di bottiglia prima dei clienti. Usiamo k6 per il load testing, partendo da un profilo di traffico realistico basato sul pattern giornaliero previsto e scalando fino a 3× il picco atteso.

k6-load-test.jsjavascript
import http from "k6/http";
import { check, sleep } from "k6";

export const options = {
  stages: [
    { duration: "5m",  target: 100  },  // Ramp up
    { duration: "10m", target: 500  },  // Picco atteso
    { duration: "5m",  target: 1500 },  // Stress test 3×
    { duration: "5m",  target: 0    },  // Ramp down
  ],
  thresholds: {
    http_req_duration: ["p(95)<500"],  // 95% delle richieste sotto 500ms
    http_req_failed:   ["rate<0.01"],  // Meno dell'1% di tasso di errore
  },
};

export default function () {
  const payload = JSON.stringify({
    idOrdine: `ORD-${Math.random().toString(36).substring(7)}`,
    articoli: [{ idProdotto: "PROD-001", quantita: 2 }],
  });

  const risposta = http.post("https://api.staging.example.com/ordini", payload, {
    headers: { "Content-Type": "application/json", Authorization: `Bearer ${__ENV.API_TOKEN}` },
  });

  check(risposta, {
    "status è 201": (r) => r.status === 201,
    "tempo di risposta OK": (r) => r.timings.duration < 500,
  });

  sleep(1);
}

Gli errori più comuni e come evitarli

  1. 1Saltare la discovery e iniziare a scrivere codice da un file Figma. Il file Figma non risponde alle domande sulle integrazioni, i requisiti di performance o la proprietà dei dati.
  2. 2Scegliere l'architettura prima di comprendere il profilo di carico. Un sistema che prevede 100 utenti/giorno e uno che ne prevede 100.000 hanno architetture ottimali differenti.
  3. 3Lasciare la sicurezza alla fine. Le vulnerabilità OWASP Top 10 costano molto meno da prevenire che da rimediare in produzione.
  4. 4Infrastruttura manuale. Se non riesci a ricreare l'ambiente di produzione da zero in due ore, perderai giorni durante il prossimo incidente.
  5. 5Nessuna baseline di performance prima del lancio. Non sai se le tue ottimizzazioni funzionano davvero se non hai una baseline con cui confrontarle.

Conclusioni

Costruire piattaforme software scalabili è una disciplina, non un talento. I team che consegnano costantemente software funzionante nei tempi previsti non sono necessariamente i più brillanti — sono quelli con un processo ripetibile: discovery rigorosa, architettura deliberata, quality gate automatizzati, infrastructure as code e observability dal primo giorno. Le scorciatoie che sembrano velocità alla settimana uno si accumulano come debito al mese sei. Il processo è la difesa contro l'entropia.

Nexora gestisce lo sviluppo di prodotto end-to-end: dalla discovery e dal design dell'architettura fino al deployment in produzione e al passaggio di consegne operativo. Se stai costruendo una nuova piattaforma o stai cercando di risollevare un progetto in difficoltà, parliamone.

Tag

Sviluppo ProdottoArchitetturaDevOpsCI/CDScalabilitàDiscoveryDelivery

Prossimo passo

Hai bisogno di implementare questa architettura?

Il nostro team di ingegneria costruisce e scala i sistemi descritti in questo articolo. Dalla discovery alla produzione — con risultati misurabili.