Principi per lo sviluppo di applicazioni moderne da NGINX. Parte 1

Ciao amici. In attesa del lancio del corso Sviluppatore back-end PHP, tradizionalmente condividono con voi la traduzione di materiale utile.

Il software risolve sempre più attività quotidiane, diventando sempre più complesso. Come disse una volta Marc Andressen, consuma il mondo.

Principi per lo sviluppo di applicazioni moderne da NGINX. Parte 1

Di conseguenza, il modo in cui le applicazioni vengono sviluppate e distribuite è cambiato radicalmente negli ultimi anni. Questi erano cambiamenti di scala tettonica che hanno portato a una serie di principi. Questi principi si sono dimostrati utili nella creazione di team, nella progettazione, nello sviluppo e nella consegna dell'applicazione agli utenti finali.

I principi possono essere così riassunti: l'applicazione dovrebbe essere piccola, basata sul Web e avere un'architettura incentrata sullo sviluppatore. Tenendo presenti questi tre principi, è possibile creare un'applicazione affidabile end-to-end che può essere consegnata all'utente finale in modo rapido e sicuro ed è facilmente scalabile ed estensibile.

Principi per lo sviluppo di applicazioni moderne da NGINX. Parte 1

Ciascuno dei principi proposti ha una serie di aspetti che discuteremo per mostrare come ogni principio contribuisce all'obiettivo finale, che è la consegna rapida di applicazioni affidabili che sono facili da mantenere e utilizzare. Esamineremo i principi in relazione ai loro opposti per chiarire cosa significa dire: "Assicurati di usare principio di piccolezza'.

Ci auguriamo che questo articolo ti incoraggi a utilizzare i principi proposti per la creazione di applicazioni moderne, che forniranno un approccio unificato alla progettazione nel contesto di uno stack tecnologico in continua crescita.

Applicando questi principi, ti ritroverai a trarre vantaggio dalle ultime tendenze nello sviluppo del software, incluso il DevOps allo sviluppo e alla consegna di applicazioni, l'uso di contenitori (ad esempio, docker) e framework di orchestrazione dei contenitori (ad esempio, kubernetes), l'uso di microservizi (inclusa l'architettura dei microservizi Nginx и architettura di comunicazione di rete per applicazioni di microservizi.

Cos'è un'applicazione moderna?

Applicazioni moderne? Pila moderna? Cosa significa esattamente "moderno"?

La maggior parte degli sviluppatori ha solo un'idea generale di cosa sia un'applicazione moderna, quindi è necessario definire chiaramente questo concetto.

Un'app moderna supporta più client, sia che si tratti di un'interfaccia utente della libreria JavaScript React, di un'app mobile Android o iOS o di un'app che si connette a un'altra API. Un'applicazione moderna implica un numero indefinito di client per i quali fornisce dati o servizi.

Un'applicazione moderna fornisce un'API per accedere ai dati e ai servizi richiesti. L'API deve essere immutabile e costante e non scritta specificamente per una richiesta specifica da un client specifico. L'API è disponibile su HTTP(S) e fornisce l'accesso a tutte le funzionalità disponibili nella GUI o nella CLI.

I dati devono essere disponibili in un formato interoperabile comunemente accettato come JSON. Un'API espone oggetti e servizi in modo pulito e organizzato, come RESTful API o GraphQL forniscono un'interfaccia decente.

Le applicazioni moderne sono basate sullo stack moderno e lo stack moderno è rispettivamente lo stack che supporta tali applicazioni. Questo stack consente a uno sviluppatore di creare facilmente un'applicazione con un'interfaccia HTTP e endpoint API chiari. L'approccio scelto consentirà alla tua applicazione di ricevere e inviare facilmente dati in formato JSON. In altre parole, lo stack moderno corrisponde agli elementi dell'applicazione a dodici fattori per microservizi.

Le versioni popolari di questo tipo di stack si basano su Java, Python, Nodo, Ruby, PHP и Go. Architettura a microservizi Nginx rappresenta un esempio di uno stack moderno implementato in ciascuno dei linguaggi citati.

Tieni presente che non stiamo sostenendo un approccio esclusivamente basato sui microservizi. Molti di voi lavorano con monoliti che devono evolversi, mentre altri hanno a che fare con applicazioni SOA che si espandono e si evolvono per diventare applicazioni di microservizi. Altri ancora si stanno muovendo verso applicazioni serverless e alcuni stanno implementando combinazioni di quanto sopra. I principi delineati nell'articolo si applicano a ciascuno di questi sistemi con solo poche modifiche minori.

Principi

Ora che abbiamo una comprensione comune di cosa siano un'applicazione moderna e uno stack moderno, è tempo di approfondire l'architettura e i principi di sviluppo che ti serviranno bene nello sviluppo, nell'implementazione e nel mantenimento di un'applicazione moderna.

Uno dei principi suona come "crea piccole applicazioni", chiamiamolo semplicemente principio di piccolezza. Esistono applicazioni incredibilmente complesse composte da molte parti mobili. A sua volta, la creazione di un'applicazione da componenti piccoli e discreti semplifica la progettazione, la manutenzione e l'utilizzo dell'intera applicazione. (Notare che abbiamo detto "semplifica" non "rende semplice").

Il secondo principio è che possiamo aumentare la produttività degli sviluppatori aiutandoli a concentrarsi sulle funzionalità che stanno sviluppando, liberandoli al tempo stesso dai problemi di infrastruttura e CI/CD durante l'implementazione. Quindi, in poche parole, il nostro approccio focalizzato sugli sviluppatori.

Infine, tutto ciò che riguarda la tua applicazione deve essere connesso alla rete. Negli ultimi 20 anni, abbiamo fatto passi da gigante verso un futuro in rete man mano che le reti diventano più veloci e le applicazioni più complesse. Come abbiamo visto, un'applicazione moderna deve essere utilizzata in rete da molti client diversi. L'applicazione del pensiero di rete all'architettura ha vantaggi significativi che si sposano bene principio di piccolezza e il concetto di approccio, orientato allo sviluppatore.

Se tieni a mente questi principi durante la progettazione e l'implementazione di un'applicazione, avrai un innegabile vantaggio nello sviluppo e nella consegna del tuo prodotto.

Diamo un'occhiata a questi tre principi in modo più dettagliato.

principio di piccolezza

È difficile per il cervello umano percepire una grande quantità di informazioni contemporaneamente. In psicologia, il termine carico cognitivo si riferisce alla quantità totale di sforzo mentale richiesto per conservare le informazioni nella memoria. Ridurre il carico cognitivo sugli sviluppatori è una priorità perché consente loro di concentrarsi sulla risoluzione del problema invece di mantenere nella loro testa l'attuale modello complesso dell'intera applicazione e le funzionalità in fase di sviluppo.

Principi per lo sviluppo di applicazioni moderne da NGINX. Parte 1

Le applicazioni si decompongono per i seguenti motivi:

  • Carico cognitivo ridotto sugli sviluppatori;
  • Accelerazione e semplificazione dei test;
  • Consegna rapida delle modifiche nell'applicazione.


Esistono diversi modi per ridurre il carico cognitivo sugli sviluppatori, ed è qui che entra in gioco il principio di piccolezza.

Quindi ecco tre modi per ridurre il carico cognitivo:

  1. Riduci il periodo di tempo che devono prendere in considerazione quando sviluppano una nuova funzionalità: più breve è il periodo di tempo, minore è il carico cognitivo.
  2. Riduci la quantità di codice su cui viene eseguito il lavoro una tantum - meno codice - meno carico.
  3. Semplifica il processo di apportare modifiche incrementali a un'applicazione.

Riduzione dei tempi di sviluppo

Torniamo ai giorni in cui la metodologia waterfall era lo standard per il processo di sviluppo e i tempi da sei mesi a due anni per lo sviluppo o l'aggiornamento di un'applicazione erano una pratica comune. In genere, gli ingegneri leggono prima i documenti pertinenti come i requisiti del prodotto (PRD), il documento di riferimento del sistema (SRD), il progetto dell'architettura e iniziano a combinare tutte queste cose insieme in un modello cognitivo, in base al quale codificano. Poiché i requisiti e, di conseguenza, l'architettura sono cambiati, è stato necessario compiere uno sforzo serio per informare l'intero team sugli aggiornamenti del modello cognitivo. Un tale approccio, nel peggiore dei casi, potrebbe semplicemente paralizzare il lavoro.

Il più grande cambiamento nel processo di sviluppo delle applicazioni è stata l'introduzione della metodologia agile. Una delle caratteristiche principali della metodologia agile è uno sviluppo iterativo. A sua volta, ciò porta a una riduzione del carico cognitivo sugli ingegneri. Invece di richiedere al team di sviluppo di implementare l'applicazione in un lungo ciclo, agile approccio consente di concentrarsi su piccole quantità di codice che possono essere rapidamente testate e distribuite, ricevendo anche feedback. Il carico cognitivo dell'app è passato da un periodo di tempo di sei mesi a due anni con un'enorme quantità di specifiche per un'aggiunta di due settimane o una modifica delle funzionalità mirata a una comprensione più sfocata di un'app di grandi dimensioni.

Spostare l'attenzione da un'applicazione massiccia a piccole funzionalità specifiche che possono essere completate in uno sprint di due settimane, con in mente non più di una funzionalità prima dello sprint successivo, è un cambiamento significativo. Questo ci ha permesso di aumentare la produttività dello sviluppo riducendo al contempo il carico cognitivo, che oscillava costantemente.

Nella metodologia agile l'applicazione finale dovrebbe essere una versione leggermente modificata del concetto originale, quindi il punto finale dello sviluppo è necessariamente ambiguo. Solo i risultati di ogni specifico sprint possono essere chiari e precisi.

Piccole basi di codice

Il prossimo passo per ridurre il carico cognitivo è ridurre la base di codice. Di norma, le applicazioni moderne sono enormi: un'applicazione aziendale robusta può essere composta da migliaia di file e centinaia di migliaia di righe di codice. A seconda di come sono organizzati i file, i collegamenti e le dipendenze tra codice e file possono essere evidenti o viceversa. Anche l'esecuzione stessa del codice di debug può essere problematica, a seconda delle librerie utilizzate e della capacità degli strumenti di debug di distinguere tra librerie/pacchetti/moduli e codice personalizzato.

La creazione di un modello mentale funzionante del codice di un'applicazione può richiedere una quantità impressionante di tempo e, ancora una volta, comportare un grande onere cognitivo per lo sviluppatore. Ciò è particolarmente vero per le basi di codice monolitico, dove esiste una grande quantità di codice, la cui interazione tra i componenti funzionali non è chiaramente definita e la separazione degli oggetti di attenzione è spesso sfocata perché i confini funzionali non sono rispettati.

Uno dei modi efficaci per ridurre il carico cognitivo degli ingegneri è passare a un'architettura di microservizi. In un approccio basato sui microservizi, ogni servizio si concentra su un set di funzionalità; mentre il significato del servizio è solitamente definito e comprensibile. Anche i confini di un servizio sono chiari: ricorda che la comunicazione con un servizio avviene tramite un'API, quindi i dati generati da un servizio possono essere facilmente trasferiti a un altro.

L'interazione con altri servizi è in genere limitata a pochi servizi utente e alcuni servizi provider che utilizzano chiamate API semplici e pulite, come l'utilizzo di REST. Ciò significa che il carico cognitivo sull'ingegnere è notevolmente ridotto. La sfida più grande rimane la comprensione del modello di interazione del servizio e il modo in cui cose come le transazioni avvengono tra più servizi. Di conseguenza, l'uso di microservizi riduce il carico cognitivo riducendo la quantità di codice, definendo chiari confini del servizio e fornendo una comprensione della relazione tra utenti e fornitori.

Piccole modifiche incrementali

L'ultimo elemento del principio piccolezza è la gestione del cambiamento. È una tentazione particolare per gli sviluppatori guardare la base di codice (forse anche il loro codice più vecchio) e dire: "Questa è una schifezza, dobbiamo riscrivere tutto". A volte questa è la decisione giusta, a volte no. Mette l'onere del cambiamento del modello globale sul team di sviluppo, che a sua volta porta a un enorme carico cognitivo. È meglio che gli ingegneri si concentrino sui cambiamenti che possono apportare durante lo sprint, in modo da poter implementare le funzionalità necessarie in modo tempestivo, anche se gradualmente. Il prodotto finale dovrebbe assomigliare a quello pre-progettato, ma con alcune modifiche e test per soddisfare le esigenze del cliente.

Quando si riscrivono grandi porzioni di codice, a volte non è possibile consegnare rapidamente la modifica perché entrano in gioco altre dipendenze di sistema. Per controllare il flusso delle modifiche, puoi utilizzare l'occultamento delle funzionalità. In linea di principio, ciò significa che la funzionalità è in produzione, ma non è disponibile utilizzando le impostazioni della variabile di ambiente (env-var) o qualche altro meccanismo di configurazione. Se il codice ha superato tutti i processi di controllo della qualità, potrebbe finire in produzione in uno stato latente. Tuttavia, questa strategia funziona solo se la funzione viene infine abilitata. Altrimenti, ingombrerà solo il codice e aggiungerà un carico cognitivo che lo sviluppatore dovrà affrontare per essere produttivo. La gestione delle modifiche e le stesse modifiche incrementali aiutano a mantenere il carico cognitivo degli sviluppatori a un livello accessibile.

Gli ingegneri devono superare molte difficoltà anche con la semplice introduzione di funzionalità aggiuntive. Da parte del management, sarebbe prudente ridurre l'onere inutile per il team in modo che possa concentrarsi sugli elementi funzionali chiave. Ci sono tre cose che puoi fare per aiutare il tuo team di sviluppo:

  1. Usa la metodologia agileper limitare il lasso di tempo in cui il team deve concentrarsi sulle caratteristiche chiave.
  2. Implementa la tua applicazione come più microservizi. Ciò limiterà il numero di funzionalità che possono essere implementate e rafforzerà i confini che mantengono il carico cognitivo al lavoro.
  3. Preferisci modifiche incrementali a quelle grandi e ingombranti, modifica piccole parti di codice. Usa l'occultamento delle funzionalità per implementare le modifiche anche se non saranno visibili immediatamente dopo averle aggiunte.

Se applichi il principio della piccolezza nel tuo lavoro, il tuo team sarà molto più felice, più concentrato sull'implementazione delle funzionalità necessarie e più propenso a implementare cambiamenti qualitativi più velocemente. Ma questo non significa che il lavoro non possa diventare più complicato, a volte, al contrario, l'introduzione di nuove funzionalità richiede la modifica di più servizi, e questo processo può essere più difficile che simile in un'architettura monolitica. In ogni caso, i vantaggi dell'adozione dell'approccio della piccolezza valgono la pena.

La fine della prima parte.

Presto pubblicheremo la seconda parte della traduzione, e ora aspettiamo i vostri commenti e vi invitiamo a farlo Giornata Aperta, che si svolgerà oggi alle ore 20.00.

Fonte: habr.com

Aggiungi un commento