Podczas omawiania interfejsów API między systemami (na poziomie biznesowym) w naszym zespole często występują dwa różne punkty widzenia: niektórzy wolą bardziej - powiedzmy - ogólne podejście abstrakcyjne, a inne proste „konkretne” podejście.
Przykład: projekt prostego interfejsu API „wyszukiwania osoby”. konkretna wersja byłaby
searchPerson(String name, boolean soundEx,
String firstName, boolean soundEx,
String dateOfBirth)
Ludzie opowiadający się za konkretną wersją mówią:
- interfejs API jest samodokumentujący
- łatwo to zrozumieć
- łatwa do sprawdzenia (kompilator lub jako usługa internetowa: sprawdzanie poprawności schematu)
- POCAŁUNEK
Druga grupa ludzi w naszym zespole powiedziałaby „To tylko lista kryteriów wyszukiwania”
searchPerson(List<SearchCriteria> criteria)
z
SearchCritera {
String parameter,
String value,
Map<String, String> options
}
z możliwym utworzeniem „parametru” jakiegoś typu wyliczenia.
Zwolennicy mówią:
- bez zmiany (deklaracji) interfejsu API implementacja może się zmienić, np. dodając więcej kryteriów lub więcej opcji. Nawet bez synchronizacji takiej zmiany w czasie wdrażania.
- dokumentacja jest konieczna nawet w przypadku konkretnego wariantu
- sprawdzanie poprawności schematu jest przereklamowane, często trzeba dokonać dalszej weryfikacji, schemat nie obsługuje wszystkich przypadków
- mamy już podobny interfejs API z innym systemem - ponowne użycie
Kontrargumentem jest
- dużo dokumentacji na temat prawidłowych parametrów i prawidłowych kombinacji parametrów
- większy wysiłek komunikacyjny, ponieważ trudniej jest zrozumieć dla innych zespołów
Czy są jakieś najlepsze praktyki? Literatura?
api
web-services
api-design
erik
źródło
źródło
Odpowiedzi:
To zależy od tego, ile pól mówisz i jak są one używane. Beton jest preferowany w przypadku wysoce ustrukturyzowanych zapytań zawierających tylko kilka pól, ale jeśli zapytania mają zazwyczaj bardzo swobodną formę, wówczas konkretne podejście szybko staje się niewygodne z więcej niż trzema lub czterema polami.
Z drugiej strony bardzo trudno jest utrzymać ogólny interfejs API w czystości. Jeśli wykonasz proste wyszukiwanie nazw w wielu miejscach, w końcu ktoś będzie się męczył powtarzaniem tych samych pięciu wierszy kodu i zawinie go w funkcję. Taki interfejs API niezmiennie ewoluuje w hybrydę ogólnego zapytania wraz z konkretnymi opakowaniami dla najczęściej używanych zapytań. I nie widzę w tym nic złego. Daje to, co najlepsze z obu światów.
źródło
Projektowanie dobrego API to sztuka. Dobre API jest doceniane nawet po upływie czasu. Moim zdaniem nie powinno być ogólnego nastawienia na abstrakcyjno-konkretnej linii. Niektóre parametry mogą być tak konkretne, jak dni tygodnia, niektóre wymagają zaprojektowania pod kątem rozszerzalności (i jest dość głupie, aby były konkretne, np. Część nazw funkcji), jeszcze inne mogą pójść jeszcze dalej i aby mieć elegancki Interfejs API, który należy udostępnić, może nawet wywoływać połączenia zwrotne, a nawet język specyficzny dla domeny.
Rzadko zdarzają się nowe rzeczy pod Księżycem. Spójrz na stan techniki, szczególnie ustalone standardy i formaty (np. Wiele rzeczy można modelować po kanałach, opisy zdarzeń zostały opracowane w ical / vcal). Uczyń swój interfejs API łatwym do dodawania, gdy częste i wszechobecne byty są konkretne, a przewidywane rozszerzenia to słowniki. Istnieją również pewne ugruntowane wzorce postępowania w określonych sytuacjach. Na przykład obsługa żądania HTTP (i podobnego) może być modelowana w interfejsie API za pomocą obiektów Request i Response.
Przed zaprojektowaniem interfejsu API przeprowadź burzę mózgów na temat aspektów, w tym tych, które nie zostaną uwzględnione, ale musisz o tym wiedzieć. Przykładami takich są język, kierunek pisania, kodowanie, ustawienia regionalne, informacje o strefie czasowej i tym podobne. Zwróć uwagę na miejsca, w których mogą występować wielokrotności: użyj listy, a nie pojedynczej wartości dla nich. Na przykład, jeśli planujesz API dla systemu wideo, twój API będzie znacznie bardziej użyteczny, jeśli przyjmiesz N uczestników, a nie tylko dwóch (nawet jeśli Twoje specyfikacje są w tej chwili).
Czasami bycie abstrakcyjnym pomaga drastycznie zmniejszyć złożoność: nawet jeśli zaprojektujesz kalkulator do dodawania tylko 3 + 4, 2 + 2 i 7 + 6, wdrożenie X + Y może być znacznie prostsze (z technicznie wykonalnymi granicami dla X i Y i dołącz ADD (X, Y) do interfejsu API zamiast ADD_3_4 (), ADD_2_2 (), ...
Podsumowując, wybór w ten czy inny sposób jest tylko szczegółem technicznym. Twoja dokumentacja powinna opisywać przypadki częstego użytkowania w konkretny sposób.
Cokolwiek zrobisz po stronie struktury danych, podaj pole dla wersji interfejsu API.
Podsumowując, interfejs API powinien minimalizować złożoność podczas obsługi oprogramowania. Aby docenić API, poziom ujawnionej złożoności powinien być odpowiedni. Wybór formy interfejsu API zależy w dużej mierze od stabilności domeny problemowej. Dlatego należy oszacować, w jakim kierunku będzie rosło oprogramowanie i jego interfejs API, ponieważ informacje te mogą wpływać na równanie złożoności. Również projektowanie interfejsu API jest dostępne dla ludzi do zrozumienia. Jeśli istnieją jakieś dobre tradycje w dziedzinie technologii oprogramowania, w której się znajdujesz, staraj się nie odbiegać od nich zbytnio, ponieważ pomoże to zrozumieć. Weź pod uwagę, dla którego piszesz. Bardziej zaawansowani użytkownicy docenią ogólność i elastyczność, a ci z mniejszym doświadczeniem mogą czuć się bardziej komfortowo z konkretami. Jednak dbaj o większość użytkowników interfejsu API,
Jeśli chodzi o literaturę, mogę polecić wiodącym programistom „Piękny kod”, wyjaśniającym, jak myślą Andy Oram, Greg Wilson, ponieważ uważam, że piękno polega na postrzeganiu ukrytej optymalności (i przydatności do określonego celu).
źródło
Moją osobistą preferencją jest abstrahowanie, ale zasady mojej firmy blokują mi konkretność. To dla mnie koniec debaty :)
Zrobiłeś dobrą robotę, wymieniając zalety i wady obu podejść, a jeśli będziesz dalej kopać, znajdziesz mnóstwo argumentów na korzyść obu stron. Tak długo, jak architektura interfejsu API jest prawidłowo opracowana - co oznacza, że zastanawiałeś się, w jaki sposób będzie on używany dzisiaj i jak może ewoluować i rozwijać się w przyszłości - to i tak powinno być dobrze.
Oto dwie zakładki, które miałem z przeciwnymi punktami widzenia:
Preferowanie klas abstrakcyjnych
Preferowanie interfejsów
Zadaj sobie pytanie: „Czy interfejs API spełnia moje wymagania biznesowe? Czy mam dobrze zdefiniowane kryteria sukcesu? Czy można go skalować?”. Wydaje się, że są to proste proste praktyki, ale szczerze mówiąc, są one o wiele ważniejsze niż konkretne kontra ogólne.
źródło
Nie powiedziałbym, że abstrakcyjne API jest trudniejsze do zweryfikowania. Jeśli parametry kryteriów są wystarczająco proste i mają niewielkie zależności między sobą, nie ma znaczenia, czy parametry są przekazywane osobno, czy w tablicy. Nadal musisz je wszystkie zweryfikować. Ale to zależy od projektu parametrów kryteriów i samych obiektów.
Jeśli interfejs API jest wystarczająco złożony, posiadanie konkretnych metod nie jest opcją. W pewnym momencie prawdopodobnie skończysz z metodami o zbyt dużej liczbie parametrów lub zbyt wieloma prostymi metodami, które nie będą obejmować wszystkich wymaganych przypadków użycia. Jeśli chodzi o moje osobiste doświadczenie w projektowaniu zużywających się interfejsów API, lepiej jest mieć bardziej ogólne metody na poziomie interfejsu API i implementować określone wymagane opakowania na poziomie aplikacji.
źródło
Argument zmiany należy odrzucić za pomocą YAGNI. Zasadniczo, chyba że faktycznie masz co najmniej 3 różne przypadki użycia, które używają ogólnego interfejsu API w inny sposób, szanse są dość niskie, projektujesz go, aby nie musiał się zmieniać, gdy pojawi się następny przypadek użycia (i gdy masz użycie przypadki, oczywiście potrzebujesz ogólnego interfejsu, kropki). Więc nie próbuj i bądź gotowy na zmianę.
W obu przypadkach zmiana nie musi być synchronizowana w celu wdrożenia. Kiedy uogólniasz interfejs później, zawsze możesz zapewnić bardziej szczegółowy interfejs dla kompatybilności wstecznej. Ale w praktyce każde wdrożenie będzie miało tak wiele zmian, że i tak je zsynchronizujesz, więc nie będziesz musiał testować stanów pośrednich. Nie uważałbym tego również za argument.
Jeśli chodzi o dokumentację, każde rozwiązanie może być łatwe w użyciu i oczywiste. Ale jest to ważny argument. Zaimplementuj interfejs, aby był łatwy w użyciu w rzeczywistych przypadkach. Czasami konkretne mogą być lepsze, a czasem ogólne.
źródło
Wolę podejście oparte na abstrakcyjnym interfejsie. Wysłanie zapytania do tego rodzaju usługi (wyszukiwania) jest częstym problemem i prawdopodobnie wystąpi ponownie. Ponadto prawdopodobnie znajdziesz więcej kandydatów do obsługi, którzy nadają się do ponownego użycia bardziej ogólnego interfejsu. Aby móc zapewnić spójny wspólny interfejs dla tych usług, nie wyliczyłem obecnie zidentyfikowanych parametrów zapytania w definicji interfejsu.
Jak już wcześniej wspomniano - podoba mi się możliwość zmiany lub rozszerzenia implementacji bez modyfikowania interfejsu. Dodanie kolejnych kryteriów wyszukiwania nie musi być odzwierciedlone w definicji usługi.
Chociaż zaprojektowanie dobrze zdefiniowanych, zwięzłych i ekspresyjnych interfejsów nie jest żadnym problemem, zawsze będziesz musiał dodatkowo dostarczyć dokumentację. Dodanie zakresu definicji dla prawidłowych kryteriów wyszukiwania nie stanowi takiego obciążenia.
źródło
Najlepsze podsumowanie, jakie kiedykolwiek widziałem, to skala Rusty'ego, teraz nazywana manifestem Rusty API Design . Mogę tylko mocno to polecić. Dla kompletności przytaczam podsumowanie skali z pierwszego linku (im lepiej u góry, tym gorzej poniżej):
Dobre API
Złe interfejsy API
Obie strony ze szczegółowymi informacjami tutaj i tutaj zawierają szczegółowe omówienie każdego punktu. Jest to naprawdę obowiązkowa lektura dla projektantów API. Dzięki Rusty, jeśli kiedykolwiek to przeczytasz.
źródło
Słowami laika:
źródło
Jeśli rozszerzysz
SearchCriteria
pomysł trochę, może to daje elastyczność takich jak tworzenieAND
,OR
itp kryteria. Jeśli potrzebujesz takiej funkcjonalności, byłoby to lepsze podejście.W przeciwnym razie zaprojektuj go pod kątem użyteczności. Ułatw interfejs API osobom, które go używają. Jeśli masz kilka podstawowych funkcji, które są często potrzebne (np. Wyszukiwanie osoby według jej nazwy), podaj je bezpośrednio. Jeśli zaawansowani użytkownicy potrzebują zaawansowanych wyszukiwań, mogą nadal korzystać z
SearchCriteria
.źródło
Co robi kod API? Jeśli jest to coś elastycznego, to elastyczny interfejs API jest dobry. Jeśli kod stojący za interfejsem API jest bardzo konkretny, to umieszczenie na nim elastycznej twarzy oznacza po prostu, że użytkownicy interfejsu API będą sfrustrowani i zirytowani tym, co udaje, że interfejs API jest możliwy, ale w rzeczywistości nie można go osiągnąć.
W przypadku Twojego wyszukiwania osoby wymagane są wszystkie trzy pola? Jeśli tak, to lista kryteriów jest zła, ponieważ pozwala na wiele zastosowań, które po prostu nie działają. Jeśli nie, wymaganie od użytkownika podania niepotrzebnych danych wejściowych jest złe. Jakie jest prawdopodobieństwo wyszukiwania według adresu w wersji V2? Elastyczny interfejs ułatwia dodawanie niż nieelastyczny.
Nie każdy system musi być bardzo elastyczny, starając się zrobić wszystko, podobnie jak architektura astronautyczna. Elastyczny łuk strzela strzałami. Elastyczny miecz jest równie przydatny jak gumowy kurczak.
źródło