Efficienza

I programmatori esperti possono facilmente distinguere un'architettura buona da una cattiva, ma se viene loro chiesto di descriverla in poche parole, è improbabile che siano in grado di farlo. Non esiste un unico criterio per una buona architettura né una singola definizione.

Tuttavia, se ci pensi, puoi scrivere una serie di criteri che una buona architettura dovrebbe soddisfare. Una buona architettura è, prima di tutto, un'architettura logica che rende il processo di sviluppo e manutenzione di un programma più semplice ed efficiente.

Quando un programma ha una buona architettura, è sempre abbastanza facile capire come funziona e dove scrivere il codice. Un programma ben architettato è più facile da modificare, testare, eseguire il debug e sviluppare. Le persone intelligenti hanno formulato i seguenti criteri per una buona architettura:

  • Efficienza;
  • Flessibilità;
  • Espandibilità;
  • Scalabilità;
  • testabilità;
  • Manutenibilità del codice.

Efficienza del sistema. Il programma, ovviamente, deve risolvere i compiti assegnati ed eseguire bene le sue funzioni e in varie condizioni. Sembra che qualsiasi programma faccia quello che dovrebbe fare (se è scritto), ma spesso non è affatto così.

Ti imbatterai costantemente in programmi che non fanno ciò che affermano di fare.

  • Libre Office è un sostituto completo di Microsoft Office (non proprio);
  • Il browser Edge supporta tutti gli standard web (non proprio);
  • La banca ha a cuore la sicurezza dei dati personali dei suoi utenti (in realtà no).

E non abbiamo ancora toccato prestazioni, affidabilità, correzioni di bug tempestive o la pubblicazione di informazioni su vulnerabilità note.

È chiaro che nessuno è perfetto, ma il programma deve risolvere i suoi compiti primari. Pertanto, senza efficienza, da nessuna parte.

Flessibilità

L'unica cosa più importante dell'efficienza secondo me è la flessibilità. Qualsiasi applicazione deve cambiare nel tempo, poiché i requisiti cambiano, ne vengono aggiunti di nuovi. Più veloce e conveniente è apportare modifiche alla funzionalità esistente, minore è il numero di problemi ed errori che provoca, più flessibile è l'architettura del sistema.

Molto spesso, i programmatori / architetti alle prime armi pensano di aver bisogno di un'architettura ideale per le attività correnti. NO. Hai bisogno di un'architettura ideale per le attività che ti verranno annunciate tra un anno. Tu, già ora che non conosci i compiti futuri, dovresti sapere quali saranno.

Non ha senso cercare di prevederli, perché ci sarà sempre qualcosa di inaspettato. Ma devi tenere conto del fatto che appariranno tali attività. Pertanto, nel processo di sviluppo, cerca di valutare ciò che si ottiene in termini di come dovrà essere modificato.

Chiediti: "Cosa succede se l'attuale decisione architettonica si rivela sbagliata?", "Quanto codice verrà modificato?". La modifica di un frammento del sistema non dovrebbe influire sugli altri suoi frammenti.

Quando possibile, le decisioni architettoniche non dovrebbero essere scolpite nella pietra e le conseguenze degli errori architettonici dovrebbero essere ragionevolmente limitate. "Una buona architettura ti consente di RITARDARE le decisioni chiave" (Bob Martin) e minimizza il "costo" degli errori.

Uno di questi approcci è la suddivisione dell'applicazione in microservizi: è facile suddividere la logica già esistente in parti separate. Ma il problema più grande è apportare modifiche future a una dozzina di servizi contemporaneamente per implementare una piccola funzionalità.

Scalabilità

La scalabilità è la capacità di ridurre i tempi di sviluppo aggiungendo nuove persone al progetto. L'architettura dovrebbe consentire la parallelizzazione del processo di sviluppo in modo che più persone possano lavorare contemporaneamente al programma.

Sembra che questa regola venga eseguita da sola, ma in pratica tutto è esattamente l'opposto. C'è persino un libro super popolare, The Mythical Man-Month , che spiega perché l'aggiunta di nuove persone a un progetto aumenta i tempi di sviluppo.

Espandibilità

L'estensibilità è la capacità di aggiungere nuove funzionalità ed entità a un sistema senza violarne la struttura centrale. Nella fase iniziale, ha senso inserire nel sistema solo le funzionalità di base e più necessarie.

Questo è il cosiddetto principio YAGNI: non ne avrai bisogno , "non ne avrai bisogno". Allo stesso tempo, l'architettura dovrebbe consentire di aumentare facilmente le funzionalità aggiuntive secondo necessità. E così che l'introduzione dei cambiamenti più probabili ha richiesto il minimo sforzo.

Il requisito che l'architettura del sistema sia flessibile ed estensibile (cioè capace di cambiamento ed evoluzione) è così importante che è stato persino formulato come principio separato - il "principio aperto/chiuso " . Il principio aperto-chiuso è il secondo dei cinque principi SOLID: le entità software (classi, moduli, funzioni) dovrebbero essere aperte per l'estensione, ma chiuse per la modifica .

In altre parole: dovrebbe essere possibile modificare ed estendere il comportamento del sistema senza riscrivere parti esistenti del sistema .

Ciò significa che l'applicazione deve essere progettata in modo tale che la modifica del suo comportamento e l'aggiunta di nuove funzionalità si ottengano scrivendo nuovo codice (estensioni), senza dover modificare il codice esistente.

In questo caso, l'emergere di nuove esigenze non comporterà una modifica della logica esistente, ma potrà essere implementata principalmente ampliandola. Questo principio è alla base dell'"architettura plug-in" (Plugin Architecture). Le tecniche con cui ciò può essere ottenuto saranno discusse in seguito.

Ricordi servlet e filtri? Perché erano necessari filtri, e anche con interfacce separate, se, in effetti, tutta la stessa logica poteva essere implementata utilizzando i servlet?

È stata l'invenzione del concetto di filtri (servlet di servizio) che ha permesso di spostare varie funzioni di servizio su un livello separato. E in futuro, quando si modifica il comportamento dei filtri, non è stato necessario modificare i servlet.

Prima dell'invenzione dei filtri, tutta la logica di servizio responsabile del reindirizzamento delle richieste si trovava nei servlet stessi. E spesso un piccolo cambiamento nella logica porterebbe alla necessità di esaminare tutti i servlet e apportare varie modifiche a tutti.

Testabilità

Se sei uno sviluppatore di backend Java, le tue applicazioni server spesso espongono una serie di metodi come API REST. E per verificare che tutti i tuoi metodi funzionino come previsto, devono essere coperti da test.

In generale, la copertura del test API è un buon stile. Ti consente di assicurarti che la tua API faccia davvero quello che doveva fare. Inoltre, cosa ancora più importante, puoi apportare modifiche alla logica del server e verificare facilmente di non aver rotto accidentalmente nulla .

Non appena inizi a scrivere test, ti renderai conto che la maggior parte del codice non può essere testata affatto: metodi privati, accoppiamento forte, classi statiche e variabili.

"Perché abbiamo bisogno di test se il codice funziona?", Chiederà il principiante.

"Perché abbiamo bisogno di un codice funzionante se non può essere testato?", Chiederà il professionista.

Il codice facile da testare conterrà meno bug e sarà più affidabile. Ma i test non migliorano solo la qualità del codice. Quasi tutti gli sviluppatori alla fine giungono alla conclusione che il requisito della "buona testabilità" è anche una forza guida che porta automaticamente a un buon design.

Ecco una citazione dal libro Ideal Architecture: "Usa il principio di "testabilità" di una classe come "cartina di tornasole" di una buona progettazione di classe. Anche se non scrivi una sola riga di codice di test, rispondendo a questa domanda in 90 % dei casi aiuterà a capire quanto tutto sia buono" o "cattivo" con il suo design."

Esiste un'intera metodologia per lo sviluppo di programmi basati sui test, che si chiama Test-Driven Development (TDD). Questo è ovviamente l'altro estremo: scrivi il codice prima di scrivere il codice.

Manutenibilità del codice

Di norma, molte persone lavorano al programma: alcune se ne vanno, ne arrivano di nuove. L'orario di lavoro medio di un programmatore in un'azienda IT è di un anno e mezzo. Quindi, se sei arrivato a un progetto che ha 5 anni, solo il 20% dei tuoi colleghi ci ha lavorato fin dall'inizio.

Mantenere e sviluppare un programma che altri hanno scritto è molto difficile. Anche se il programma è già scritto, spesso è necessario continuare a mantenerlo: correggere errori e apportare correzioni minori. E spesso questo deve essere fatto da persone che non hanno preso parte alla sua stesura.

Pertanto, una buona architettura dovrebbe rendere relativamente facile e veloce per le nuove persone comprendere il sistema . Il progetto deve essere:

  • Ben strutturato.
  • Non contenere duplicati.
  • Avere un codice ben formattato.
  • È auspicabile includere la documentazione.
  • È necessario applicare soluzioni standard e familiari per i programmatori.

Puoi facilmente valutare il progetto su cui stai lavorando su una scala a 5 punti . Basta contare due punti per ciascuno di questi requisiti . E se ne ottieni 5 o più, allora sei fortunato.

I programmatori hanno persino un principio di minima sorpresa : più il sistema è esotico, più difficile è per gli altri capirlo. Di solito viene utilizzato in relazione all'interfaccia utente, ma è applicabile anche alla scrittura di codice.