Porównując strukturę REST [api] z modelem OO, widzę następujące podobieństwa:
Obie:
Są zorientowane na dane
- REST = zasoby
- OO = Przedmioty
Operacja surround wokół danych
- REST = otaczaj VERBS (Get, Post, ...) wokół zasobów
- OO = promuj działanie wokół obiektów przez enkapsulację
Jednak dobre praktyki OO nie zawsze stoją na apelach REST podczas próby zastosowania wzoru fasady, na przykład: w REST nie masz 1 kontrolera do obsługi wszystkich żądań ORAZ nie ukrywasz złożoności obiektów wewnętrznych.
Przeciwnie, REST promuje publikowanie zasobów wszystkich relacji z zasobem i innymi w co najmniej dwóch formach:
poprzez relacje hierarchii zasobów (kontakt o identyfikatorze 43 składa się z adresu 453):
/api/contacts/43/addresses/453
za pośrednictwem łączy w odpowiedzi json REST:
>> GET /api/contacts/43 << HTTP Response { id: 43, ... addresses: [{ id: 453, ... }], links: [{ favoriteAddress: { id: 453 } }] }
Wracając do OO, wzór projektowania elewacji szanuje Low Coupling
między obiektem A i jego „ klientem objectB ”, a High Cohesion
dla tego obiektu A i jego składu wewnętrznego obiektu ( objectC , objectD ). Z objectA interfejs, pozwala to deweloper, aby ograniczyć wpływ na objectB z objectA zmian wewnętrznych (w objectC i objectD ), tak długo, jak objectA API (operacji) są nadal przestrzegane.
W usłudze REST dane (zasoby), relacje (łącza) i zachowanie (czasowniki) są rozbite na różne elementy i dostępne w Internecie.
Korzystając z usługi REST, zawsze mam wpływ na zmiany kodu między moim klientem a serwerem: ponieważ mam High Coupling
między swoimi Backbone.js
żądaniami i Low Cohesion
między zasobami.
Nigdy nie zastanawiałem się, jak pozwolić Backbone.js javascript application
sobie na odkrycie „ zasobów i funkcji REST ” promowanych przez linki REST. Rozumiem, że WWW ma być obsługiwane przez wiele serwerów i że elementy OO musiały zostać rozbite, aby mogły być obsługiwane przez wiele hostów, ale w prostym scenariuszu, takim jak „zapisanie” strony pokazującej kontakt z jej adresami, Kończę z:
GET /api/contacts/43?embed=(addresses) [save button pressed] PUT /api/contacts/43 PUT /api/contacts/43/addresses/453
które skłoniły mnie do przeniesienia odpowiedzialności za transakcję atomową na transakcje atomowe na aplikacjach przeglądarki (ponieważ dwa zasoby można rozwiązać osobno).
Mając to na uwadze, jeśli nie mogę uprościć rozwoju (wzorce projektowania fasad nie mają zastosowania) i jeśli przyniosę więcej złożoności mojemu klientowi (obsługa transakcyjnego zapisu atomowego), to gdzie jest korzyść z ODPOWIEDZIALNOŚCI?
źródło
PUT /api/contacts/43
kaskadowych aktualizacji wewnętrznych obiektów? Miałem wiele interfejsów API zaprojektowanych w ten sposób (główny adres URL odczytuje / tworzy / aktualizuje „całość”, a adresy URL aktualizują elementy). Tylko upewnij się, że nie aktualizujesz adresu, gdy nie są wymagane żadne zmiany (ze względu na wydajność).Odpowiedzi:
Myślę, że obiekty są budowane poprawnie tylko wokół spójnych zachowań, a nie wokół danych. Sprowokuję i powiem, że dane są prawie nieistotne w świecie zorientowanym obiektowo. W rzeczywistości jest możliwe i czasami powszechne posiadanie obiektów, które nigdy nie zwracają danych, na przykład „zatapianie logów” lub obiektów, które nigdy nie zwracają danych, które są przekazywane, na przykład jeśli obliczają właściwości statystyczne.
Nie pomylmy PODS (które są niewiele więcej niż strukturami) i rzeczywistych obiektów, które mają zachowania (takie jak
Contacts
klasa w twoim przykładzie) 1 .PODS to w zasadzie wygoda używana do rozmowy z repozytoriami i obiektami biznesowymi. Pozwalają na bezpieczny kod. Nie więcej nie mniej. Z drugiej strony obiekty biznesowe zapewniają konkretne zachowania , takie jak sprawdzanie poprawności danych, przechowywanie ich lub używanie ich do wykonywania obliczeń.
Zachowania są więc tym, czego używamy do mierzenia „kohezji” 2 , i łatwo jest zauważyć, że w twoim przykładzie obiektu istnieje pewna spójność, nawet jeśli pokazujesz tylko metody manipulowania kontaktami najwyższego poziomu, a nie metody manipulowania adresami.
Jeśli chodzi o REST, możesz zobaczyć usługi REST jako repozytoria danych. Duża różnica w stosunku do projektowania obiektowego polega na tym, że istnieje (prawie) tylko jeden wybór projektu: masz cztery podstawowe metody (więcej, jeśli
HEAD
na przykład liczysz ) i oczywiście masz dużo swobody dzięki identyfikatorom URI, dzięki czemu możesz zrobić sprytne takie jak przekazywanie wielu identyfikatorów i odzyskiwanie większej struktury. Nie należy mylić przekazywanych danych z wykonywanymi operacjami . Spójność i sprzężenie dotyczą kodu, a nie danych .Oczywiście usługi REST mają wysoką spójność (każdy sposób interakcji z zasobem znajduje się w tym samym miejscu) i niskie połączenie (każde repozytorium zasobów nie wymaga wiedzy o innych).
Podstawowym faktem pozostaje jednak, REST jest w zasadzie pojedynczym wzorcem repozytorium dla twoich danych. Ma to konsekwencje, ponieważ jest to paradygmat oparty na łatwej dostępności na wolnym nośniku, gdzie koszty „chattiness” są wysokie: klienci zazwyczaj chcą wykonać jak najmniej operacji, ale jednocześnie otrzymują tylko te dane, których potrzebują . Określa to, jak głęboko drzewo danych zamierzasz odesłać.
W (poprawnym) projektowaniu obiektowym każda nietrywialna aplikacja będzie wykonywać znacznie bardziej złożone operacje, na przykład poprzez kompozycję. Mogą istnieć metody wykonywania bardziej wyspecjalizowanych operacji na danych - tak musi być, ponieważ podczas gdy REST jest protokołem API, OOD służy do budowania aplikacji zorientowanych na użytkownika! Właśnie dlatego pomiar kohezji i sprzężenia ma podstawowe znaczenie w OOD, ale prawie nie ma znaczenia w REST.
Do tej pory powinno być oczywiste, że analiza projektu danych za pomocą koncepcji OO nie jest niezawodnym sposobem na zmierzenie go: przypomina porównywanie jabłek i pomarańczy!
W rzeczywistości okazuje się, że korzyści z RESTful są (głównie) te przedstawione powyżej: to dobry wzór dla prostych interfejsów API na wolnym medium. Jest bardzo buforowalny i możliwy do podzielenia. Ma drobnoziarnistą kontrolę nad spoceniem itp.
Mam nadzieję, że to odpowiada na twoje (dość wieloaspektowe) pytanie :-)
1 Ten problem jest częścią większego zestawu problemów znanych jako niedopasowanie impedancji obiektowo-relacyjnej . Zwolennicy ORM są na ogół w obozie, który bada podobieństwa między analizą danych a analizą zachowania, ale ORM są ostatnio krytykowane, ponieważ wydaje się, że tak naprawdę nie rozwiązują niedopasowania impedancji i są uważane za nieszczelne abstrakcje .
2 http://en.wikipedia.org/wiki/Coicity_(computer_science)
źródło
Odpowiedź na „gdzie jest korzyść z RESTful?” jest dokładnie przeanalizowane i wyjaśnione tutaj: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
Problem w tym pytaniu polega jednak na tym, że nie chodzi o charakterystykę REST i sposobu radzenia sobie z nimi, ale założenie, że adresy URL, które wymyśliłeś dla swojego przykładowego systemu, ma coś wspólnego z byciem RESTful. W końcu REST stwierdza, że istnieją rzeczy zwane zasobami i należy podać identyfikator dla tych, do których należy się odwoływać, ale nie dyktuje to, że, powiedzmy, jednostki w twoim modelu ER powinny mieć 1-1 korespondencję z utworzonymi adresami URL (ani że adresy URL powinny kodować liczność relacji ER w modelu).
W przypadku kontaktów i adresów mógłbyś zdefiniować zasób, który wspólnie reprezentuje te informacje jako jedną jednostkę, nawet jeśli możesz chcieć wyodrębnić i zapisać te informacje, powiedzmy, w różnych relacyjnych tabelach DB, zawsze, gdy są PUT lub POSTed .
źródło
Dzieje się tak, ponieważ fasady są „kludge”; powinieneś spojrzeć na „abstrakcję API” i „tworzenie łańcuchów API”. Interfejs API to połączenie dwóch zestawów funkcji: We / Wy i zarządzania zasobami. Lokalnie we / wy jest w porządku, ale w architekturze rozproszonej (tj. Proxy, brama API, kolejka komunikatów itp.) We / wy jest współużytkowane, a zatem dane i funkcje zostają zduplikowane i uwikłane. Prowadzi to do architektonicznych problemów przekrojowych. To plaga WSZYSTKIE istniejące api.
Jedynym sposobem na rozwiązanie tego jest streszczenie funkcji we / wy interfejsu API dla modułu obsługi przed / po (takiego jak interfejs programu obsługi w Spring / Grails lub filtr w Railsach), dzięki czemu można go używać jako monady i współdzielić między instancjami i zewnętrznie obróbka. Dane do żądania / odpowiedzi również muszą być eksternalizowane w obiekcie, aby można je było również udostępniać i ładować ponownie.
http://www.slideshare.net/bobdobbes/api-abstraction-api-chaining
źródło
Jeśli rozumiesz swoją usługę REST lub ogólnie dowolny interfejs API, podobnie jak dodatkowy interfejs udostępniony klientom, dzięki któremu mogą oni programować kontrolery przez niego, nagle staje się to łatwe. Ta usługa to nic innego jak dodatkowa warstwa nad twoją logiką biz.
Innymi słowy, nie musisz dzielić logiki dziwnej na wiele kontrolerów, jak na powyższym obrazku, a co ważniejsze, nie powinieneś. Struktury danych używane do wymiany danych nie muszą pasować do struktur danych używanych wewnętrznie, mogą być zupełnie inne.
Jest to stan techniki i powszechnie akceptowane, że umieszczanie dowolnej logiki biz w kodzie interfejsu użytkownika jest złym pomysłem. Ale każdy interfejs użytkownika jest tylko rodzajem interfejsu (I w interfejsie użytkownika) do sterowania logiką biz. W związku z tym wydaje się oczywiste, że złym pomysłem jest umieszczenie dowolnej logiki biz w warstwie usługi REST lub jakiejkolwiek innej warstwie API.
Pod względem koncepcyjnym nie ma aż tak dużej różnicy między interfejsem użytkownika a interfejsem API usługi.
źródło