Ogni giorno, ogni momento della nostra carriera ingegneristica, incontriamo molti problemi diversi di varia complessità e situazioni in cui dobbiamo prendere una decisione o rimandarla a causa della mancanza di dati. Ogni volta che creiamo nuovi servizi, costruiamo infrastrutture o persino formiamo processi di sviluppo, tocchiamo un mondo enorme di varie sfide.
È difficile, e forse persino impossibile, elencare tutti i problemi. Incontrerai alcuni di questi problemi solo se lavori in una nicchia specifica. D'altro canto, ce ne sono molti che tutti dobbiamo capire come risolvere, poiché sono cruciali per la creazione di sistemi IT. Con un'alta probabilità, li incontrerai in tutti i progetti.
In questo articolo condividerò le mie esperienze con alcuni dei problemi che ho riscontrato durante la creazione di programmi software.
Se guardiamo su Wikipedia, troveremo la seguente definizione
Nello sviluppo software orientato agli aspetti, le preoccupazioni trasversali sono aspetti di un programma che interessano diversi moduli, senza la possibilità di essere incapsulati in nessuno di essi. Queste preoccupazioni spesso non possono essere nettamente scomposte dal resto del sistema sia nella progettazione che nell'implementazione e possono causare dispersione (duplicazione del codice), groviglio (dipendenze significative tra sistemi) o entrambi.
Descrive ampiamente di cosa si tratta, ma voglio estenderlo e semplificarlo un po':
Una preoccupazione trasversale è un concetto o un componente del sistema/organizzazione che influenza (o "attraversa") molte altre parti.
Gli esempi migliori di tali preoccupazioni sono l'architettura di sistema, la registrazione, la sicurezza, la gestione delle transazioni, la telemetria, la progettazione del database e ce ne sono molte altre. Ne approfondiremo molte più avanti in questo articolo.
A livello di codice, le preoccupazioni trasversali sono spesso implementate utilizzando tecniche come Aspect-Oriented Programming (AOP) , dove queste preoccupazioni sono modularizzate in componenti separate che possono essere applicate in tutta l'applicazione. Ciò mantiene la logica aziendale isolata da queste preoccupazioni, rendendo il codice più leggibile e manutenibile.
Esistono molti modi possibili per classificare gli aspetti segmentandoli con diverse proprietà come ambito, dimensione, funzionalità, importanza, target e altro, ma in questo articolo userò una semplice classificazione dell'ambito. Con questo intendo dove è diretto questo aspetto specifico, che si tratti dell'intera organizzazione, di un sistema particolare o di un elemento specifico di quel sistema.
Quindi, dividerò gli aspetti in Macro e Micro .
Per aspetto macro intendo principalmente le considerazioni che seguiamo per l'intero sistema, come l'architettura di sistema scelta e la sua progettazione (monolitica, microservizi, architettura orientata ai servizi), lo stack tecnologico, la struttura organizzativa, ecc. Gli aspetti macro sono correlati principalmente a decisioni strategiche e di alto livello.
Nel frattempo, l'aspetto Micro è molto più vicino al livello di codice e allo sviluppo. Ad esempio, quale framework viene utilizzato per interagire con il database, la struttura del progetto di cartelle e classi o persino specifici pattern di progettazione di oggetti.
Sebbene questa classificazione non sia ideale, aiuta a strutturare la comprensione dei possibili problemi e dell'importanza e dell'impatto delle soluzioni che applichiamo.
In questo articolo mi concentrerò principalmente sugli aspetti macro.
Quando ho appena iniziato a studiare l'architettura software, ho letto molti articoli interessanti sulla legge di Conway e il suo impatto sulla struttura organizzativa. In particolare questo . Quindi, questa legge afferma che
Qualsiasi organizzazione che progetta un sistema (definito in senso lato) produrrà un progetto la cui struttura è una copia della struttura di comunicazione dell'organizzazione.
Ho sempre creduto che questo concetto sia davvero universale e rappresenti la Regola d'Oro.
Poi ho iniziato a imparare l'approccio Domain-Driven Design (DDD) di Eric Evans per la modellazione dei sistemi. Eric Evans sottolinea l'importanza dell'identificazione del Bounded Context. Questo concetto implica la suddivisione di un modello di dominio complesso in sezioni più piccole e gestibili, ciascuna con il proprio set limitato di conoscenze. Questo approccio aiuta nella comunicazione di squadra efficace, poiché riduce la necessità di una conoscenza approfondita dell'intero dominio e riduce al minimo il cambio di contesto, rendendo così le conversazioni più efficienti. Il cambio di contesto è la cosa peggiore e più dispendiosa in termini di risorse di sempre. Anche i computer hanno difficoltà con questo. Sebbene sia improbabile che si raggiunga una completa assenza di cambio di contesto, ritengo che sia ciò a cui dovremmo aspirare.
Tornando alla legge di Conway, ho trovato diversi problemi.
Il primo problema che ho incontrato con la legge di Conway, che suggerisce che la progettazione del sistema rispecchia la struttura organizzativa, è il potenziale per la formazione di contesti delimitati complessi e completi. Questa complessità sorge quando la struttura organizzativa non è allineata con i confini del dominio, portando a contesti delimitati che sono fortemente interdipendenti e carichi di informazioni. Ciò porta a frequenti cambi di contesto per il team di sviluppo.
Un altro problema è che la terminologia organizzativa trasuda a livello di codice. Quando le strutture organizzative cambiano, ciò richiede modifiche alla base di codice, consumando risorse preziose.
Pertanto, seguire la manovra Inverse Conway aiuta a costruire il sistema e l'organizzazione che incoraggiano l'architettura software desiderata. Tuttavia, è degno di nota dire che questo approccio non funzionerà molto bene in architetture e strutture già formate poiché i cambiamenti in questa fase sono prolungati, ma è eccezionalmente performante nelle startup poiché sono veloci a introdurre qualsiasi cambiamento.
Questo schema o "anti-schema" spinge a costruire un sistema senza alcuna architettura. Non ci sono regole, né confini, né strategie su come controllare l'inevitabile crescente complessità. La complessità è il nemico più formidabile nel percorso di costruzione di sistemi software.
Per evitare di costruire un sistema di questo tipo, dobbiamo seguire regole e vincoli specifici.
Esistono innumerevoli definizioni di Architettura Software. Molte di esse mi piacciono perché ne coprono diversi aspetti. Tuttavia, per poter ragionare sull'architettura, abbiamo naturalmente bisogno di formarne alcune nella nostra mente. Ed è degno di nota dire che questa definizione potrebbe evolversi. Quindi, almeno per ora, ho la seguente descrizione per me stesso.
L'architettura software riguarda le decisioni e le scelte che prendi ogni giorno e che hanno un impatto sul sistema sviluppato.
Per prendere decisioni è necessario avere nella propria "borsa" principi e modelli per risolvere i problemi emergenti, è anche essenziale affermare che comprendere i requisiti è la chiave per costruire ciò di cui un'azienda ha bisogno. Tuttavia, a volte i requisiti non sono trasparenti o addirittura non sono definiti, in questo caso, è meglio aspettare di ottenere maggiori chiarimenti o affidarsi alla propria esperienza e fidarsi del proprio intuito. Ma in ogni caso, non è possibile prendere decisioni correttamente se non si hanno principi e modelli su cui fare affidamento. Ecco dove arrivo alla definizione di stile di architettura software.
Lo stile dell'architettura software è un insieme di principi e modelli che stabiliscono come sviluppare un software.
Esistono molti stili architettonici diversi, incentrati su vari aspetti dell'architettura pianificata, e applicarne più di uno contemporaneamente è una situazione normale.
Ad esempio, come:
Architettura monolitica
Progettazione guidata dal dominio
Basato su componenti
Microservizi
Tubo e filtri
Guidato dagli eventi
Microkernel
Orientato al servizio
e così via…
Naturalmente, hanno i loro vantaggi e svantaggi, ma la cosa più importante che ho imparato è che l'architettura si evolve gradualmente, pur dipendendo da problemi reali. Iniziare con l'architettura monolitica è un'ottima scelta per ridurre le complessità operative, molto probabilmente questa architettura soddisferà le tue esigenze anche dopo aver raggiunto la fase Product-market Fit (PMI) della creazione del prodotto. Su larga scala, potresti prendere in considerazione di passare a un approccio event-driven e microservizi per ottenere una distribuzione indipendente, un ambiente di stack tecnologico eterogeneo e un'architettura meno accoppiata (e meno trasparente nel frattempo a causa della natura degli approcci event-driven e pub-sub se questi vengono adottati). Semplicità ed efficienza sono vicine e hanno un grande impatto l'una sull'altra. Di solito, le architetture complicate influenzano la velocità di sviluppo di nuove funzionalità, supportando e mantenendo quelle esistenti e sfidando l'evoluzione naturale del sistema.
Tuttavia, i sistemi complessi richiedono spesso un'architettura complessa e completa, il che è inevitabile.
Abbastanza, questo è un argomento molto molto ampio e ci sono molte idee fantastiche su come strutturare e costruire sistemi per l'evoluzione naturale. Sulla base della mia esperienza, ho elaborato il seguente approccio:
È inoltre fondamentale comprendere numeri e metriche quali DAU (utenti attivi giornalieri), MAU (utenti attivi mensili), RPC (richieste al secondo) e TPC (transazioni al secondo), poiché potrebbero aiutarti a fare delle scelte, in quanto l'architettura per 100 utenti attivi e quella per 100 milioni di utenti attivi sono diverse.
Come nota finale, direi che l'architettura ha un impatto significativo sul successo del prodotto. Un'architettura mal progettata per i prodotti è richiesta nella scalabilità, il che molto probabilmente porta al fallimento poiché i clienti non aspetteranno mentre si scala il sistema, sceglieranno un concorrente, quindi dobbiamo anticipare la potenziale scalabilità. Sebbene ammetta che a volte potrebbe non essere un approccio snello, l'idea è di avere un sistema scalabile ma non già scalabile. D'altra parte, avere un sistema molto complicato e già scalabile senza clienti o piani per ottenerne molti ti costerà soldi per la tua attività per niente.
La scelta di uno stack tecnologico è anche una decisione a livello macro, poiché influenza le assunzioni, le prospettive di evoluzione naturale del sistema, la scalabilità e le prestazioni del sistema.
Ecco l'elenco delle considerazioni di base per la scelta di uno stack tecnologico:
In che modo la presenza di più stack tecnologici può influire sulla crescita aziendale?
Da una prospettiva, introdurre un altro stack potrebbe aumentare le assunzioni, ma dall'altra parte, comporta costi di manutenzione aggiuntivi poiché è necessario supportare entrambi gli stack. Quindi, come ho detto in precedenza, dal mio punto di vista, solo la necessità aggiuntiva dovrebbe essere un argomento per incorporare più stack tecnologici.
Ma qual è il principio che sta alla base della scelta dello strumento migliore per un problema specifico?
A volte non si ha altra scelta che adottare nuovi strumenti per risolvere un problema specifico, basandosi sulle stesse considerazioni sopra menzionate; in questi casi ha senso selezionare la soluzione migliore.
La creazione di sistemi senza un elevato accoppiamento a una tecnologia specifica potrebbe essere una sfida. Tuttavia, è utile impegnarsi per una condizione in cui il sistema non sia strettamente accoppiato alla tecnologia e non morirà se domani un framework o uno strumento specifico diventasse vulnerabile o addirittura deprecato.
Un'altra considerazione importante è legata alle dipendenze del software open source e proprietario. Il software proprietario offre meno flessibilità e la possibilità di essere personalizzato. Tuttavia, il fattore più pericoloso è il vendor lock-in, in cui si diventa dipendenti dai prodotti, dai prezzi, dai termini e dalla roadmap di un fornitore. Ciò può essere rischioso se il fornitore cambia direzione, aumenta i prezzi o interrompe il prodotto. Il software open source riduce questo rischio, poiché non è una singola entità a controllarlo. Eliminare un singolo punto di errore a tutti i livelli è la chiave per costruire sistemi affidabili per la crescita.
Un singolo punto di errore (SPOF) si riferisce a qualsiasi parte di un sistema che, se si guasta, causerà l'interruzione del funzionamento dell'intero sistema. Eliminare gli SPOF a tutti i livelli è fondamentale per qualsiasi sistema che richieda elevata disponibilità. Tutto, tra cui conoscenza, personale, componenti di sistema, provider cloud e cavi Internet, può guastarsi.
Esistono diverse tecniche di base che potremmo applicare per eliminare i singoli punti di errore:
In questo articolo abbiamo trattato diversi aspetti chiave della macroeconomia e come possiamo gestirne la complessità.
Grazie per aver letto! Alla prossima!