Progettare applicazioni scalabili senza magia
Sfruttare la potenza di calcolo del client per prestazioni elevate con molti utenti
- Pubblicato
- Aggiornato
- (creato )
- Scritto da
- Willem L. Middelkoop
- Argomenti
- cloud · dati · design · guida · iOS · lemmid-store · programmazione · server · smartphone · web · web design
- Versione umana di questo articolo
- https://willem.com/it/2020-05-11_progettare-applicazioni-scalabili-senza-magia/
- English
- Scalable application design without magic
- Nederlands
- Schaalbaar applicatieontwerp zonder magie
- Deutsch
- Skalierbares Anwendungsdesign ohne Magie
- Español
- Diseño de aplicaciones escalables sin magia
- Français
- Concevoir une application scalable sans magie
- Português
- Design de aplicações escaláveis sem magia
- Papiamentu
- Desèño di aplikashon eskalabel sin magia
- Frysk
- Skaalbere applikaasje-ûntwerp sûnder magy
- Lingue
- Tradotto dall’originale inglese da un modello linguistico in due passaggi (traduzione e correzione) con un glossario e un controllo ortografico; non ancora letto da un madrelingua.
Riassunto
Per l'app di ordinazione di cibo online che sto costruendo, dovevo progettare un'infrastruttura backend scalabile, capace di gestire molti utenti contemporanei. La scalabilità è considerata un problema difficile da affrontare. Spesso viene presentata come qualcosa di magico, fatto da aziende da milioni di dollari con strumenti segreti. Ma la magia non esiste, o forse sì?
Testo completo
Che cos'è la scalabilità?
Se stai costruendo un'app, probabilmente parti in piccolo. Pochi utenti (o solo tu, lo sviluppatore) che lavorano con l'app. Tutto va a gonfie vele: l'app funziona bene, è veloce e non ci sono problemi. (goditi questa sensazione!)

In questo scenario iniziale e ridotto, il singolo server che esegue l'app riesce a gestire l'utente che interagisce con essa. Ogni volta che l'utente tocca o clicca un pulsante, il server fa un po' di lavoro. Se programmi bene, questi carichi di lavoro si possono ottimizzare in blocchi di lavoro efficienti. Farlo così è un tipico esempio di architettura software monolitica.
Anche se il tuo progetto o la tua app è piuttosto piccola, a un certo punto potrebbe arrivare un afflusso di utenti. Se il tuo sistema non regge carichi elevati, ha buone probabilità di cedere.

A causa del design monolitico dell'app, tutti gli utenti interagiscono con lo stesso server. Tutta la loro interazione (tocchi, clic, input) è gestita da questo server. Con un carico maggiore deve lavorare molto di più. A un certo punto noterai che le cose rallentano perché il server non riesce a tenere il passo con la quantità di lavoro da fare. Significa che la tua app non scala bene, in altre parole: sei nei guai.
Il crollo nel 'momento supremo'
Non scalare bene è un grosso problema che nessuno dovrebbe sottovalutare. La maggior parte delle app (e dei loro modelli di business) si basa su grandi volumi con pochi ricavi per singolo utente. Se vuoi che la tua app sia un successo (finanziario), devi assicurarti che funzioni bene quando il traffico aumenta all'improvviso. Se la tua app va in crash proprio quando attira all'improvviso l'attenzione delle masse, perdi un'occasione 'irripetibile' di crescita (organica).
In un certo senso progettare per la scalabilità è come tenere le cinture allacciate mentre sei seduto sul tuo razzo fatto in casa, con motori sperimentali. Non sai mai con esattezza quando si accenderà, ma quando succede è meglio essere ben saldi al sedile (e goderti il viaggio!).
Modi comuni per ottenere la scalabilità
Si è scritto moltissimo sulla costruzione di app scalabili. I modi più comuni per migliorare la scalabilità sono:
- Aumentare la capacità del server: aggiungere più memoria, potenza di CPU, spazio di archiviazione. Funziona, ma ti porta solo 'fino a un certo punto'.
- Aggiungere più server: invece di un unico server che fa da collo di bottiglia, puoi aggiungere altri server che si dividono il carico. Più facile a dirsi che a farsi, perché servono bilanciamento del carico e condivisione dei dati, che possono essere complicati (per esempio, se hai un contatore degli ordini e due server stanno contando, quale dei due decide il numero successivo?)
- Ottimizzare il codice: usa gli strumenti giusti! Scegli un linguaggio di programmazione orientato alle prestazioni e un software server altrettanto. Dai un'occhiata alla programmazione funzionale per far girare il tuo codice in modo asincrono su più core. Rendilo senza stato. Fai i benchmark. Ottimizzalo. Ogni millisecondo guadagnato su una singola richiesta si somma in fretta quando gestisci grandi volumi.
- Usare il database e separarlo dal server applicativo: se usi un database, sfrutta la sua potenza! Approfitta della cache delle query, degli indici e delle funzioni di ricerca. La maggior parte delle soluzioni di database offre opzioni di clustering collaudate: non cercare di reinventare la ruota che altri hanno già perfezionato.
La cosa migliore che puoi fare è considerare tutte queste opzioni. Anche se non aggiungi subito altri server, dovresti scrivere il codice in modo da supportarlo più avanti. Fare benchmark e ottimizzare il codice dovrebbe essere parte integrante del tuo lavoro, non un ripensamento.
Sfruttare la potenza di calcolo del client
Quando hai considerato tutti i modi comuni per ottenere la scalabilità, c'è "un'ultima cosa".

Pochi sviluppatori ci pensano: il problema della scalabilità contiene la soluzione! Quando hai 1000 utenti, hai 1000 computer con CPU potenti e tanta memoria. I computer e gli smartphone moderni sono diventati sempre più capaci.
Devi solo trovare un modo per attingere alla potenza di calcolo del client. Può sembrare una cosa da cattivi (usare la potenza di calcolo dell'utente), ma gli darà un'esperienza molto migliore e più veloce. La parte migliore è che la sua potenza di calcolo viene spesa per la sua fantastica esperienza, e il tuo problema di scalabilità si risolve come felice effetto collaterale.

Sfruttando la potenza di calcolo dell'utente, riduci la quantità di lavoro che deve fare il server. Invece di far fare al server un po' di lavoro ogni volta che l'utente tocca o clicca un pulsante, ora questo lavoro lo fa soprattutto il dispositivo dell'utente. È più efficiente che comunicare con un server tramite una connessione Wi-Fi/4G (risparmi batteria e tempo).
Richiede di ripensare un po' le cose, ma questo principio si può applicare anche alle applicazioni web. Invece di gestire tutto sul server, puoi fare molto lavoro sul client. Cose come cercare, sfogliare, filtrare, navigare e perfino aggiungere articoli al carrello si possono fare con JavaScript lato client. Tu - caro sviluppatore - devi cercare il modo di farlo funzionare, ma se ci riesci avrai una scalabilità quasi infinita a portata di mano.
Nella pratica: l'app per ordinare cibo
Per l'app di ordinazione di cibo ho cercato modi per sfruttare la potenza di calcolo del client e ottenere prestazioni elevate. La sfida principale per gli ordini a domicilio e da asporto è che raggiungono il picco all'ora di cena. Molte persone usano l'app più o meno nello stesso momento: è la ricetta perfetta per i problemi di scalabilità.

Se pensi all'ordinazione di cibo online, puoi spezzare l'intero processo in blocchi più piccoli:
- 1) Aprire la pagina: caricare l'app/la pagina
- 2) Sfogliare le diverse opzioni: vedere l'elenco dei prodotti, le descrizioni, i prezzi, le foto, ecc.
- 3) Cercare qualcosa di specifico: cercare per categoria, nome del prodotto, ecc.
- 4) Selezionare un prodotto: aggiungerlo al tuo ordine
- 5) Personalizzare un prodotto: scegliere una salsa, un contorno, un condimento, ecc.
- 6) Inserire i tuoi dati: nome, numero di telefono, dettagli di consegna, ecc.
- 7) Pagare l'ordine: scegliere un metodo di pagamento, collegarsi alla banca o alla carta di credito
- 8) Chiudere l'app
La maggior parte di questi passaggi si può programmare in modo che il server non serva. Solo il passaggio 1 (il caricamento) e il passaggio 7 (il pagamento) richiedono un contatto con l'infrastruttura backend. È importante rendersi conto che i passaggi da 2 a 5 si ripetono più volte, perché è normale che gli utenti aggiungano più prodotti al loro ordine.

Separando il carico di lavoro rimanente per compito, il software può essere ottimizzato ancora di più. Il "server dei prodotti" è ottimizzato per servire risorse statiche (testi, prezzi, immagini) che permettono al client di creare l'esperienza di consultazione dei prodotti. Questo tipo di server si può ottimizzare moltissimo sfruttando caching, HTTP/2, compressione, ecc.
Solo gli utenti che completano il processo di ordinazione vengono inoltrati al "server degli ordini", che gestisce il pagamento. Si collega al fornitore di pagamenti. Quando un pagamento è completato, il fornitore di pagamenti contatta il server degli ordini per informarlo sullo stato del pagamento. È qualcosa su cui vuoi avere pieno controllo (lato server), come quando ho progettato un sistema di pagamento in precedenza. Il carico di lavoro rimasto sul "server degli ordini" è molto più piccolo, perché non tutti effettueranno un ordine, e gran parte dell'elaborazione degli ordini si può fare in background.

Per massimizzare la scalabilità puoi aggiungere facilmente più server (o usare una rete per la distribuzione dei contenuti) per servire le risorse statiche. Per l'app di ordinazione di cibo uso un "server dei prodotti" separato per ogni ristorante. Questo garantisce prestazioni elevate e riduce i tempi di caricamento. Le persone notano che è veloce, qualcuno non riesce a credere che sia tecnologia web: è quasi magico.
Conclusione
Progettare un'applicazione scalabile si può fare senza magia e senza budget da milioni di dollari. Devi solo ragionarci bene e cercare le opportunità che si presentano insieme alle sfide.
Il problema contiene la soluzione. Gestire tanti utenti contemporanei non è solo un problema: portano con sé la propria potenza di calcolo, ed è la soluzione! Devi solo usarla.