Perché REST Api non segue il modello di progettazione della facciata

9

Nel confrontare la struttura REST [api] con un modello OO, vedo queste somiglianze:

Entrambi:

  • Sono orientati ai dati

    • REST = Risorse
    • OO = Oggetti
  • Funzionamento surround intorno ai dati

    • REST = surround VERBS (Get, Post, ...) attorno alle risorse
    • OO = promuove l'operazione intorno agli oggetti mediante l'incapsulamento

Tuttavia, le buone pratiche OO non si trovano sempre nelle apis REST quando si tenta di applicare il modello di facciata, ad esempio:    in REST, non hai 1 controller per gestire tutte le richieste E non nascondi la complessità dell'oggetto interno.

Al contrario, REST promuove la pubblicazione di risorse di tutte le relazioni con una risorsa e altre su almeno due forme:

  1. tramite le relazioni di gerarchia delle risorse (un contatto di id 43 è composto da un indirizzo 453): /api/contacts/43/addresses/453

  2. tramite link in una risposta JSON di REST:

>> GET /api/contacts/43
<< HTTP Response {
   id: 43, ...
   addresses: [{
      id: 453, ...
   }],
   links: [{
      favoriteAddress: {
          id: 453
      }
   }]
}

TornandoaOO,loschemadiprogettazionedellafacciatarispettaunaLowCouplingtraunoggettoAeilsuo'oggettoBclient'eHighCohesionperquestooggettoAelasuacomposizionedioggettiinterna(objectC,objectD).Conl'interfacciaobjectA,questoconsenteaunosviluppatoredilimitarel'impattosuoggettoBdelleobjectAmodificheinterne(inobjectCeoggettoD),purchél'oggettoAapi(operazioni)siaancorarispettato.

InREST,idati(risorse),lerelazioni(collegamenti)eilcomportamento(verbi)sonoesplosiinelementidiversiedisponibiliperilweb.

GiocandoconREST,hosempreunimpattosullemodifichealcodicetrailmioclienteilmioserver:perchéhoHighCouplingtralemierichiestediBackbone.jseLowCohesiontralerisorse.

NonhomaicapitocomeconsentirealmioBackbone.jsjavascriptapplicationdigestire" risorse e funzionalità REST " discovery promosse dai link REST. Capisco che il WWW è destinato ad essere servito da più server, e che gli elementi OO dovevano essere esplosi per essere serviti da molti host, ma per uno scenario semplice come "salvare" una pagina che mostra un contatto con i suoi indirizzi, Finisco con:

GET /api/contacts/43?embed=(addresses)
[save button pressed]
PUT /api/contacts/43
PUT /api/contacts/43/addresses/453

che mi portano a spostare la responsabilità transazionale atomica dell'azione di salvataggio nelle applicazioni del browser (poiché due risorse possono essere indirizzate separatamente).

Tenendo questo a mente, se non riesco a semplificare il mio sviluppo (modelli di facciate non applicabili), e se porto più complessità al mio cliente (gestendo il salvataggio atomico transazionale), qual è il vantaggio di essere RESTful?

    
posta Alain 28.11.2013 - 18:23
fonte

4 risposte

6

Penso che gli oggetti siano costruiti correttamente solo attorno a comportamenti coerenti e non attorno ai dati. Provocherò e dirò che i dati sono quasi irrilevanti nel mondo orientato agli oggetti. In effetti, è possibile e talvolta comune disporre di oggetti che non restituiscono mai dati, ad esempio "sink di log" o oggetti che non restituiscono mai i dati che vengono trasmessi, ad esempio se calcolano le proprietà statistiche.

Non confondiamo le PODS , (che sono poco più delle strutture) e gli oggetti reali che hanno comportamenti (come la classe Contacts nel tuo esempio) 1 .

I POD sono fondamentalmente una comodità usata per parlare con repository e oggetti di business. Consentono al codice di essere sicuri. Ne più ne meno. Gli oggetti business, d'altra parte, forniscono comportamenti concreti , come la convalida dei dati, o la memorizzazione, o il loro utilizzo per eseguire un calcolo.

Quindi, i comportamenti sono ciò che usiamo per misurare la "coesione" 2 , ed è abbastanza facile vedere che nell'esempio dell'oggetto c'è una certa coesione, anche se mostri solo i metodi per manipolare il livello più alto contatti e nessun metodo per manipolare gli indirizzi.

Riguardo a REST, è possibile visualizzare i servizi REST come archivi di dati. La grande differenza con il design orientato agli oggetti è che c'è (quasi) solo una scelta di design: hai quattro metodi di base (più se contiamo HEAD , ad esempio) e ovviamente hai molto margine di manovra con gli URI in modo da può fare cose belle come passare molti id e recuperare una struttura più grande. Non confondere i dati che passano con le operazioni che eseguono. Coesione e accoppiamento riguardano codice e non dati .

Chiaramente, i servizi REST hanno un'elevata coesione (ogni modo di interagire con una risorsa è nello stesso posto) e un basso accoppiamento (ogni repository di risorse non richiede la conoscenza delle altre).

Il fatto fondamentale rimane, tuttavia, che REST è essenzialmente un modello di repository singolo per i tuoi dati. Ciò ha delle conseguenze, perché è un paradigma costruito attorno ad una facile accessibilità su un mezzo lento, dove c'è un alto costo per "chattiness": i clienti in genere vogliono eseguire il minor numero possibile di operazioni, ma allo stesso tempo ricevono solo i dati di cui hanno bisogno . Questo determina la profondità di un albero di dati che stai per inviare indietro.

Nella (corretta) progettazione orientata agli oggetti, qualsiasi applicazione non banale eseguirà operazioni molto più complesse, ad esempio attraverso la composizione. Potresti avere metodi per eseguire operazioni più specializzate con i dati, il che deve essere così, perché mentre REST è un protocollo API, OOD viene utilizzato per costruire applicazioni complete per utenti! Questo è il motivo per cui la misurazione della coesione e dell'accoppiamento è fondamentale in OOD, ma quasi insignificante in REST.

A questo punto dovrebbe essere ovvio che analizzare un progetto di dati con concetti OO non è un modo affidabile per misurarlo: è come paragonare mele e arance!

In realtà, si scopre che i benefici di essere RESTful sono (soprattutto) quelli delineati sopra: è un buon modello per le API semplici su un supporto lento. È molto memorizzabile nella cache e può essere diviso in due. Ha un controllo a grana fine su chattiness, ecc.

Spero che questo risponda alla tua (abbastanza complessa) domanda: -)

1 Questo problema fa parte di un insieme più ampio di problemi noti come Object- Mancata corrispondenza dell'impedenza relazionale . I fautori di ORM sono generalmente nel campo che esplora le somiglianze tra analisi dei dati e analisi del comportamento, ma gli ORM sono caduti criticati tardi perché sembrano non risolvere veramente il disadattamento di impedenza e sono astrazioni leaky considerate .

2 link

    
risposta data 29.11.2013 - 22:19
fonte
1

With this in mind, if I cannot simplify my development (Facade design patterns not applicable), and if I bring more complexity to my client (handling transactional atomic save), where is the benefit of being RESTful ?

La risposta a "dove è il vantaggio di essere RESTful?" è accuratamente analizzato e spiegato qui: link

La confusione in questa domanda però è che non si tratta delle caratteristiche di REST e di come affrontarle, ma assumendo che il design degli URL che hai trovato per il tuo sistema di esempio abbia qualcosa a che fare con l'essere RESTful. Dopotutto, REST afferma che ci sono cose chiamate risorse e dovrebbe essere fornito un identificatore per quelle che devono essere referenziate, ma ciò non significa che, per esempio, le entità nel tuo modello ER dovrebbero avere la corrispondenza 1-1 con gli URL che hai creato (né che gli URL debbano codificare la cardinalità delle relazioni ER nel modello).

Nel caso di contatti e indirizzi, potresti aver definito una risorsa che rappresenta congiuntamente queste informazioni come una singola unità, anche se potresti voler estrarre e salvare queste informazioni in, diciamo, diverse tabelle di DB relazionali, ogni volta che sono PUT o POSTed.

    
risposta data 30.11.2013 - 20:15
fonte
1

Questo perché le facciate sono un "kludge"; dovresti dare un'occhiata a 'api astrazione' e 'api concatenare'. L'API è una combinazione di due set di funzionalità: I / O e gestione delle risorse. A livello locale, l'I / O è a posto ma all'interno di un'architettura distribuita (ad es. Proxy, gate api, coda messaggi, ecc.) L'I / O è condiviso e quindi i dati e le funzionalità vengono duplicati e impigliati. Questo porta a preoccupazioni architettoniche trasversali. Questo affligge TUTTE le apis esistenti.

L'unico modo per risolvere questo problema è astrarre le funzionalità I / O dell'API su un gestore pre / post (come un handlerIntercepter in Spring / Grails o un filtro in Rails) in modo che la funzionalità possa essere utilizzata come monade e condivisa da istanze e strumenti esterni. Anche i dati per richiesta / risposta devono essere esternalizzati in un oggetto in modo che possano essere condivisi e ricaricati.

link

    
risposta data 01.11.2014 - 16:23
fonte
0

Se comprendi il tuo servizio REST, o in generale qualsiasi tipo di API, proprio come un'interfaccia aggiuntiva esposta ai client in modo che possano programmare il / i controller / i attraverso di essa, diventa improvvisamente facile. Il servizio non è altro che un ulteriore livello in cima alla tua logica di biz.

In altre parole, non è necessario dividere la logica biz tra più controller, come è stato fatto nella foto sopra e, cosa più importante, non si dovrebbe. Le strutture dati utilizzate per l'interscambio dei dati non devono necessariamente corrispondere alle strutture di dati che si utilizzano internamente, possono essere piuttosto diverse.

È uno stato dell'arte, e ampiamente accettato, che è una cattiva idea mettere qualsiasi logica biz nel codice dell'interfaccia utente. Ma ogni interfaccia utente è solo una sorta di interfaccia (I in IU) per controllare la logica biz dietro. Di conseguenza, sembra ovvio che sia anche una cattiva idea mettere qualsiasi logica biz nel livello di servizio REST o in qualsiasi altro livello API.

Concettualmente, non c'è molta differenza tra interfaccia utente e API di servizio.

    
risposta data 29.11.2013 - 23:04
fonte

Leggi altre domande sui tag