WCF / SOA - Dlaczego powinienem tworzyć obiekty parametrów dla prostych żądań

12

Nasza firma rozpoczyna dość dużą inicjatywę SOA. Robimy wiele rzeczy, dobrze: dobra komunikacja; pieniądze na narzędzia, w stosownych przypadkach; i przynieśliśmy trochę dobrej wiedzy, aby pomóc nam w przejściu.

Staramy się opracowywać standardy, które możemy stosować jako grupa, a jeden z proponowanych standardów mnie trochę niepokoi:

Standaryzowaliśmy wzorzec, w którym każda operacja pobiera obiekt żądania i zwraca obiekt odpowiedzi.

Zdaję sobie sprawę, że dla wielu ludzi jest to standardowe podejście, ale pytam, dlaczego mam się tym przejmować? (Nie jestem tak dobry z otrzymaną mądrością, potrzebuję trochę powodu).

Większość usług, które będę świadczyć, to proste wyszukiwanie metadanych organizacyjnych. Na przykład znajdź zasady bezpieczeństwa dla konkretnego użytkownika. Wymaga to identyfikatora użytkownika i nic więcej. Standard mówi mi, że powinienem zawinąć to żądanie w obiekt, a zwiniętą zasadę w obiekt odpowiedzi.

Mój niepokój potęguje spojrzenie na WSDL generowany z naszych kontraktów. WCF automatycznie generuje komunikaty żądań i odpowiedzi i otacza nawet obiekt żądania / odpowiedzi.

W pełni rozumiem, że jeśli składasz złożone żądanie, wówczas złożony obiekt wejściowy jest uzasadniony. Tak byś zrobił, nawet gdyby usługi nie były zaangażowane.

Moje pytanie brzmi: dlaczego powinienem automatycznie zawijać wnioski i odpowiedzi, gdy:

  • Sprawia, że ​​proste usługi stają się mniej wyraziste
  • Zrobiłbyś to mimo wszystko dla złożonej usługi
  • WCF i tak tworzy komunikat żądania / odpowiedzi

Znalazłem następujące argumenty za tym podejściem:

Obsługuje wersjonowanie, umożliwiając wstawianie opcjonalnych parametrów do obiektu żądania.

Wcześniej zrobiłem sporo COM i uważam to za prawie anty-wzorzec dla wersji. W niektórych przypadkach przypuszczam, że to pomogłoby, ale spodziewam się, że tam, gdzie to by pomogło, i tak masz już obiekt parametru.

Umożliwia izolowanie wspólnych danych i zachowań do klasy podstawowej

Ten niesie ze sobą trochę wagi.

Odwraca ludzi od zachowań w stylu RPC i kieruje się w stronę komunikatorów

Przeczytałem to na stronie Microsoftu i usłyszałem od naszego guru, ale wciąż nie mam jasnego pojęcia, co one oznaczają i dlaczego jest to cenne. Czy to naturalnie wyglądające interfejsy sprawiają, że ludzie często zapominają, że dzwonią do zdalnej usługi?

Patrzę na refaktoryzację podpisów być może 300 metod, więc jest to trywialna ilość bólu. Jestem wielkim fanem konsekwencji we wdrożeniach, więc jestem gotów wziąć na siebie ból, to po prostu pomoże wiedzieć, że ostatecznie wszystko będzie tego warte.

Andy Davis
źródło

Odpowiedzi:

3

Myślę, że wersjonowanie jest prawdopodobnie najlepszym argumentem. Gdy masz istniejącą umowę na obsługę, taką jak

int GetPersons(int countryId);

które chcesz ulepszyć, np. później przez inny filtr

int GetPersons(int countryId, int age);

Będziesz musiał napisać nową umowę operacyjną i nową nazwę, ponieważ musi być unikalna. Lub zachowaj nazwę i opublikuj nową wersję 2 swojej usługi, przy czym stara wersja 1 wciąż będzie dostępna dla kompatybilności wstecznej.

Jeśli owiniesz parametr w obiekt, zawsze możesz go rozszerzyć o parametry domyślne / opcjonalne, a wszyscy istniejący klienci pozostaną nienaruszeni, gdy ponownie użyjesz tej samej umowy operacyjnej.

Chciałbym jednak również odpowiednio nazwać twoje obiekty. Nawet jeśli po prostu otacza int, jeśli zaczynasz IntMessagelub coś podobnego, nie robisz sobie przysługi przedłużającej go. Trzeba by to nazwać np. PersonFilterOd samego początku, co oznacza, że ​​trzeba się trochę zastanowić nad tym, czego to wywołanie usługi powinno oczekiwać jako parametr semantycznie, a zatem co ma zrobić. Może (a może to bardzo niejasne) pomoże to w opracowaniu odpowiednich usług i utrzymaniu interfejsu API przyzwoitej wielkości.

Umożliwia izolowanie wspólnych danych i zachowań do klasy podstawowej

Z tym należy być ostrożnym. Umowy dziedziczenia i danych nie idą tak dobrze razem. Działa, ale musisz określić wszystkie znane podtypy kontraktu, które mogłyby przejść przez sieć, w przeciwnym razie serializator kontraktu danych nie narzeka na nieznane typy.

Ale to, co mogłoby zrobić (ale jeszcze chyba nie powinno, nadal jestem niezdecydowany na ten temat) jest ponowne wykorzystanie tych samych komunikatów między różnymi usługami. Jeśli umieścisz kontrakty danych w osobnej bibliotece DLL, możesz udostępnić je między klientem a usługą i nie musisz konwertować między typami, gdy wywołujesz różne usługi, które oczekują zasadniczo tej samej wiadomości. Na przykład tworzysz filtr PersonFilter i przekazujesz go do jednej usługi, aby uzyskać listę filtrów osób, a następnie do innej usługi i mieć te same obiekty na kliencie. Nie mogę jednak znaleźć na to dobrego przykładu w świecie rzeczywistym i istnieje niebezpieczeństwo, że rozszerzenie umów o dane nie jest wystarczająco ogólne dla wszystkich usług korzystających z tej umowy.

Ogólnie rzecz biorąc, oprócz wersji, nie mogę znaleźć naprawdę zabójczego powodu, aby zrobić to w ten sposób.

Andreas
źródło
Myślę, że powód, dla którego biorę
Andy Davis
(przepraszam, interfejs komentowania wywołuje u mnie żal) Dziękuję za odpowiedź. Myślę, że powód, dla którego biorę argument wersji z takim ziarnem soli, jest taki, że jeśli dodałeś nowy argument, prawdopodobnie zmieniłeś semantykę. Jeśli (jak w twoim przykładzie) właśnie dodałeś wiek, to semantyka prawdopodobnie dotyczyła wyszukiwania i na początku miałeś „obiekt wyszukiwania”.
Andy Davis
Teraz rozważ mój przykład polityki bezpieczeństwa. Być może zdecydujemy, że aby właściwie dostarczyć politykę bezpieczeństwa, musimy znać nie tylko użytkownika, ale także narzędzie, w którym pracują. To znacznie więcej niż dodanie argumentu, zmieniliśmy semantykę wywołania. Zakładając, że w jakiś sposób jesteśmy w stanie dostarczyć te informacje dla osoby dzwoniącej z poprzedniej wersji, myślę, że bardziej sensowne jest zaktualizowanie umowy serwisowej. Następnie implementacja dla starej wersji może być izolowana i nie kończy się mieszaniem starej semantyki z nową.
Andy Davis,
0

Myślę, że notatki Martina Fowlera na temat obiektu transferu danych są tutaj odpowiednie.

Podczas pracy z interfejsem zdalnym, takim jak Remote Facade (388), każde połączenie z nim jest kosztowne. W rezultacie musisz zmniejszyć liczbę połączeń, a to oznacza, że ​​musisz przesyłać więcej danych przy każdym połączeniu. Jednym ze sposobów na to jest użycie wielu parametrów. Jest to jednak często niewygodne w programowaniu - w rzeczywistości jest często niemożliwe w przypadku języków takich jak Java, które zwracają tylko jedną wartość.

Rozwiązaniem jest utworzenie obiektu przenoszenia danych, który może przechowywać wszystkie dane dla połączenia. Aby przejść przez połączenie, musi być możliwy do serializacji. Zwykle asembler jest używany po stronie serwera do przesyłania danych między DTO a dowolnymi obiektami domeny.

To samo może dotyczyć wniosków. Co do RPC i dlaczego jest zły:

Czy to naturalnie wyglądające interfejsy sprawiają, że ludzie często zapominają, że dzwonią do zdalnej usługi?

Myślę, że to prawda, ale nie główny powód. Innym powodem do uniknięcia RPC jest to, że może zachęcać ściśle powiązanych klientów i usług.

Kyle Hodgson
źródło
Dzięki za wkład, ale nie sądzę, że dyskusja DTO jest tak istotna. Jest to ta sama liczba wywołań, a jeśli spojrzysz na WSDL, wszystko jest automatycznie pakowane w obiekt żądania i odpowiedzi. Konwencja dotyczy widocznej semantyki, tzn. Ludzie powinni traktować to jako żądanie i odpowiedź w przeciwieństwie do zdalnego wywołania metody.
Andy Davis
Czy chciałbyś opracować RPC zachęcające ściśle powiązanych klientów i usługi? Nie widzę, żeby miało to w ogóle wpływ na usługę. Dla klienta tak naprawdę nie widzę, jak coś się naprawdę zmienia. W obu przypadkach klient ma serwer proxy, który opisuje szereg operacji świadczonych przez usługę. W każdym razie to, kto faktycznie wdraża drugą stronę usługi, nie jest sprawą klienta.
Andy Davis