Attenzione: grande post, alcune opinioni, vaga conclusione "fai ciò che funziona meglio per te"
Generalmente, ciò viene fatto come mezzo per implementare "architettura esagonale" attorno al database. Puoi avere applicazioni web, applicazioni mobili, applicazioni desktop, importatori di massa ed elaborazione in background che consumano il tuo database in modo uniforme. Certamente potresti ottenere la stessa cosa in una certa misura scrivendo una ricca libreria per accedere al tuo database e facendo in modo che tutti i tuoi processi utilizzino quella libreria. E in effetti, se sei in un piccolo negozio con un sistema molto semplice, è probabilmente una strada migliore da percorrere; È un approccio più semplice e se non hai bisogno delle funzionalità avanzate di un sistema più complicato, perché pagare per la complessità? Tuttavia, se stai lavorando con un insieme ampio e sofisticato di sistemi che devono tutti interagire con il tuo database su larga scala, lì "
Indipendenza e manutenzione della piattaforma
Se si dispone di un database e si scrive una libreria Python per interagire con quel database e tutti inseriscono quella libreria per interagire con il database, è fantastico. Ma diciamo improvvisamente che devi scrivere un'app mobile e che ora l'app mobile deve parlare anche con il database. E i tuoi ingegneri iOS non usano Python, e i tuoi ingegneri Android non usano Python. Forse i ragazzi iOS vogliono usare le lingue di Apple e gli ingegneri Android vogliono usare Java. Quindi rimarrai bloccato a scrivere e gestire la tua libreria di accesso ai dati in 3 lingue diverse. Forse gli sviluppatori iOS e Android decidono di usare qualcosa come Xamarin per massimizzare il codice che possono condividere. Perfetto, tranne che probabilmente dovrai ancora trasferire la tua libreria di accesso ai dati su .NET. E poi la tua azienda ha appena acquistato un'altra società che " L'applicazione Web è un prodotto disparato ma correlato e l'azienda desidera integrare alcuni dei dati dalla piattaforma della propria azienda nella piattaforma della filiale appena acquisita. C'è solo un problema: la filiale era una start-up e ha deciso di scrivere la maggior parte della sua applicazione in Dart. Inoltre, per qualsiasi motivo (ragioni probabilmente al di fuori del tuo controllo) il team mobile che stava pilotando Xamarin ha deciso che non faceva per loro e che avrebbero preferito usare gli strumenti e le lingue specifici dei dispositivi mobili per i quali svilupperanno. Ma mentre eri in quella fase, il tuo team aveva già distribuito gran parte della tua libreria di accesso ai dati in .NET, e un altro team della società stava scrivendo alcune cose folli sull'integrazione di Salesforce e ha deciso di fare tutto ciò in .NET da lì era già una libreria di accesso ai dati per.
Quindi ora, a causa di una svolta molto realistica degli eventi, hai la tua libreria di accesso ai dati scritta in Python, .NET, Swift, Java e Dart. Non sono neanche belli come vorresti che fossero. Non puoi usare un ORM nel modo più efficace che desideri, perché ogni lingua ha strumenti ORM diversi, quindi hai dovuto scrivere più codice di quanto ti sarebbe piaciuto. E non sei stato in grado di dedicare tanto tempo a ciascuna incarnazione come avresti voluto, perché ce ne sono 5. E la versione Dart della libreria è particolarmente pelosa perché per alcuni di essi è stato necessario creare il proprio materiale transazionale perché le librerie e il supporto non erano proprio lì. Hai provato a sostenere che, a causa di ciò, l'applicazione Dart avrebbe dovuto avere solo funzionalità di sola lettura per il tuo database, ma l'azienda aveva già deciso che qualunque caratteristica stessero pianificando valeva lo sforzo extra. E si scopre che c'è un bug in alcune delle logiche di validazione che esistono in tutte queste incarnazioni della tua libreria di accesso ai dati. Ora devi scrivere test e codice per correggere questo errore in tutte queste librerie, ottenere revisioni del codice per le modifiche apportate a tutte queste librerie, ottenere QA su tutte queste librerie e rilasciare le modifiche a tutti i sistemi utilizzando tutti i queste biblioteche. Nel frattempo, i tuoi clienti sono scontenti e si sono rivolti a Twitter, mettendo insieme combinazioni di volgarità che non avresti mai immaginato possano essere concepite, per non parlare del prodotto di punta della tua azienda. E il proprietario del prodotto decide di non capire bene la situazione.
Si prega di comprendere che in alcuni ambienti, l'esempio sopra è tutt'altro che inventato. Considera anche che questa sequenza di eventi potrebbe svolgersi nel corso di pochi anni. Generalmente, quando arrivi al punto in cui architetti e uomini d'affari iniziano a parlare di collegare altri sistemi al tuo database, è allora che vorrai "mettere un'API REST davanti al database" nella tua tabella di marcia. Considerare se all'inizio, quando era chiaro che questo database stava per iniziare a essere condiviso da alcuni sistemi, un servizio web / API REST è stato messo di fronte ad esso. Correggere il tuo bug di validazione sarebbe molto più semplice e veloce perché lo stai facendo una volta invece di 5 volte. Rilasciare la correzione sarebbe molto più facile da coordinare, perché
TLDR; È più semplice centralizzare la logica di accesso ai dati e mantenere client HTTP molto sottili piuttosto che distribuire la logica di accesso ai dati a ciascuna applicazione che deve accedere ai dati. In effetti, il tuo client HTTP potrebbe persino essere generato da metadati. Nei sistemi di grandi dimensioni, l'API REST consente di mantenere meno codice
Prestazioni e scalabilità
Alcune persone potrebbero credere che parlare direttamente con il database invece di passare prima attraverso un servizio web sia più veloce. Se hai una sola applicazione, è certamente vero. Ma nei sistemi più grandi, non sono d'accordo con il sentimento. Alla fine, a un certo livello di scala, sarà molto utile mettere un qualche tipo di cache davanti al database. Forse stai usando Hibernate e vuoi installare una griglia Infinispan come cache L2. Se hai un cluster di 4 server robusti per ospitare il tuo servizio web separato dalle tue applicazioni, puoi permetterti di avere una topologia integrata con la replica sincrona attivata. Se provi a inserirlo in un cluster di 30 server applicazioni, il sovraccarico di attivare la replica in quella configurazione sarà troppo, quindi " O dovrò eseguire Infinispan in una modalità distribuita o in una sorta di topologia dedicata, e improvvisamente Hibernate deve uscire dalla rete per poter leggere dalla cache. Inoltre, Infinispan funziona solo in Java. Se hai altre lingue, avrai bisogno di altre soluzioni di memorizzazione nella cache. Il sovraccarico della rete di dover passare dall'applicazione al servizio Web prima di raggiungere il database è rapidamente compensato dalla necessità di utilizzare soluzioni di cache molto più complicate che generalmente vengono fornite con un sovraccarico.
Inoltre, quel livello HTTP dell'API REST fornisce un altro prezioso meccanismo di memorizzazione nella cache. I server per l'API REST possono mettere le intestazioni di memorizzazione nella cache sulle loro risposte e queste risposte possono essere memorizzate nella cache a livello di rete, che si adatta in modo eccezionalmente buono. In una configurazione di piccole dimensioni, con uno o due server, la soluzione migliore è utilizzare una cache di memoria nell'applicazione quando si parla al database, ma in una piattaforma di grandi dimensioni con molte applicazioni in esecuzione su molti server, si desidera sfruttare il rete per gestire la memorizzazione nella cache, perché quando configurato correttamente qualcosa come calamari o vernici o nginx può ridimensionarsi a livelli folli su hardware relativamente piccolo. Centinaia di migliaia o milioni di richieste al secondo di throughput sono molto più economiche da eseguire da una cache HTTP che da un server delle applicazioni o di un database.
Inoltre, avere un sacco di client tutti puntati sul tuo database, invece di averli tutti puntati su alcuni server che a loro volta puntano sul database, può rendere molto più difficile l'ottimizzazione del database e del pool di connessioni. In generale, la maggior parte del carico di lavoro effettivo su un server delle applicazioni è roba dell'applicazione; attendere che i dati tornino dal database richiede spesso tempo, ma generalmente non è molto costoso dal punto di vista computazionale. Potrebbero essere necessari 40 server per gestire il carico di lavoro dell'applicazione, ma probabilmente non sono necessari 40 server per orchestrare il recupero dei dati dal database. Se si dedica tale attività a un servizio Web, il servizio Web sarà probabilmente in esecuzione su molti meno server rispetto al resto dell'applicazione, il che significa che saranno necessarie molte meno connessioni al database. Il che è importante perché i database generalmente non
TLDR; È più facile ottimizzare, ridimensionare e memorizzare nella cache l'accesso ai dati quando si verifica qualcosa all'interno di un singolo servizio Web dedicato rispetto a quando accade in molte applicazioni diverse utilizzando lingue e tecnologie diverse
Pensieri finali
Per favore, non allontanarti da questo pensiero "Oh wow, dovrei sempre usare le API REST per ottenere i miei dati" o "Questo idiota sta cercando di dire che stiamo sbagliando perché la nostra app web parla direttamente al database, ma la nostra roba funziona benissimo! " . Il punto principale che sto cercando di sottolineare è che sistemi diversi e aziende diverse hanno requisiti diversi; In molti casi, mettere un'API REST davanti al tuo database non ha davvero senso. È un'architettura più complicata che richiede di giustificare quella complessità. Ma quando la complessità è garantita, ci sono molti vantaggi nell'avere l'API REST. Essere in grado di soppesare le diverse preoccupazioni e scegliere l'approccio giusto per il tuo sistema è ciò che rende un buon ingegnere.
Inoltre, se l'API REST sta ostacolando il debug delle cose, probabilmente c'è qualcosa di sbagliato o mancante in quell'immagine. Non credo che avere quel livello di astrazione aggiunto intrinsecamente renda più difficile il debug. Quando lavoro con grandi sistemi di livello n, mi piace assicurarmi di avere un contesto di registrazione distribuito. Forse quando un utente avvia una richiesta, genera un GUID per quella richiesta e registra il nome utente dell'utente e la richiesta che ha effettuato. Quindi, passa quel GUID mentre l'applicazione comunica con altri sistemi. Con un'adeguata aggregazione e indicizzazione dei registri, è possibile eseguire una query dell'intera piattaforma per l'utente che segnala il problema e avere visibilità su tutte le loro azioni e scorrere attraverso il sistema per identificare rapidamente dove sono andate le cose. Ancora una volta, è un'architettura più complicata,
Fonti:
http://alistair.cockburn.us/Hexagonal+architecture
https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing