Czy powinienem napisać interfejs API przed implementacją?

14

Ostatnio zajmuję się bardziej „zorganizowanym” programowaniem i dowiaduję się, że powinienem programować interfejs, a nie implementację. Mając to na uwadze, czy lepiej byłoby „naszkicować” projekt w interfejsach przed napisaniem implementacji, jeśli to możliwe?

A jeśli tak jest, to w przypadku korzystania z bibliotek stron trzecich (tj. Lidgren), czy powinienem owijać je również w interfejsy i rozwiązywać je za pomocą kontenerów IOC, czy też jest w porządku, aby udostępnić je interfejsom?

Dan Pantry
źródło
Z mojego osobistego doświadczenia - dobrze jest najpierw zaprojektować architekturę - odpowiedzialność każdej klasy. Nie musisz go zapisywać, tylko pomyśl o tym lub naszkicuj na papierze. Potem chodzi o osobiste preferencje, ale zalecam najpierw napisać komentarz do dokumentu dla każdej metody, którą zaczniesz wdrażać. Pisanie dokumentów naprawdę sprawia, że ​​musisz pomyśleć o funkcjonalności, zanim zaczniesz pisać kod.
Sulthan,
Tak i zaprogramuj interfejsy (lub klasy abstrakcyjne w tym przypadku) przed ich wdrożeniem. Pomaga uzyskać przepływ komunikatów między klientem a serwerem i odwrotnie „w prawo”, zanim zostaną ugrzęznięte (i zainwestowane) w implementacje. Bardzo dobry pokaz slajdów na ten temat: Jak zaprojektować dobry interfejs API i dlaczego to ma znaczenie
Marjan Venema

Odpowiedzi:

8

Niestety, często sprowadza się to do osobistych preferencji.

To, co do tej pory opisałeś, wydaje się dobre. W rzeczywistości, jeśli chcesz (i polecam), możesz zastosować następujące podejście:

  1. Napisz szkielet aplikacji jako interfejsy, klasy abstrakcyjne (skrótowe) i klasy (również skrótowe)
  2. Napisz swoje testy w stosunku do tych interfejsów i kodów pośredniczących (na razie zawiodą)
  3. Napisz swoje implementacje (testy zaczną się powieść po zakończeniu implementacji)

Koncentrujesz się na próbie napisania bardziej „zorganizowanego” kodu. Śledzenie TDD pomoże ci w tym.

Niektóre dodatkowe punkty:

  • Pojemniki IoC są wygodne. Używaj ich i DI jak najwięcej.
  • Czy owinąć bibliotek 3rd party. Spowoduje to poluzowanie sprzężenia między Twoim kodem (kod, który kontrolujesz) a kodem strony trzeciej (kod, którego nie kontrolujesz)
MetaFight
źródło
1
Tak pierwotnie myślałem, ale powiedziano mi, że naruszy zasadę YAGNI. Problem z wieloma projektami, które nigdy się nie kończą, polega na tym, że szybko stają się one niemożliwe do utrzymania dzięki ilości napisanego przeze mnie kodu blob, ponieważ nie organizuję go właściwie ani nie planuję mojego planu ataku.
Dan Pantry
która część narusza YAGNI?
MetaFight,
Zawijanie bibliotek stron trzecich.
Dan Pantry
2
Wydaje mi się, że sprowadza się to do: Jakie są szanse na zmianę biblioteki innej firmy? Jeśli jest na to 0% szansy, to na pewno YAGNI. Ale tak rzadko jest. Również zawijanie bibliotek stron trzecich może sprawić, że Twój inny kod będzie łatwiejszy do przetestowania jednostkowego (jeśli na przykład nie możesz
wykpić
1
@ DanPantry: Zawijanie bibliotek stron trzecich nie jest naruszeniem YAGNI, ale bardzo potrzebną ochroną przed „zainfekowaniem własnego kodu przez biblioteki stron trzecich”. Nie chodzi tylko o możliwość wymiany biblioteki, ale jak MetaFight mówi również o obronie przed zmianami w nowszych wersjach biblioteki, które w innym przypadku wymagałyby zmian w całym twoim kodzie. Otaczając bibliotekę (a zwłaszcza jej określone typy: klasy, wyliczenia, struktury itp.) Izolujesz własny kod i masz jeden punkt do zmiany, gdy zmienia się biblioteka (z dowolnego powodu).
Marjan Venema,
13

Tak, powinieneś kodować interfejsy zamiast znanych implementacji i tak, powinieneś najpierw zbudować interfejsy, a nie wymyślać je z własnego kodu.

Przyczyny obu zaleceń są w dużej mierze takie same: programowanie komputerowe dotyczy głównie czynników ludzkich. Wielu uważa to za zaskakujące, ale zastanów się: istnieje prawie nieskończona liczba różnych sposobów rozwiązania tego samego problemu komputerowego, które działają równie dobrze. Prawie wszystkie z nich są całkowicie niemożliwe do zrozumienia dla każdego, kto ich nie napisał (lub w rzeczywistości autorowi wkrótce).

Wynika z tego, że dobra inżynieria oprogramowania polega w dużej mierze na tym, jak osiągnąć pożądany efekt (poprawne obliczenia z rozsądną wydajnością) w sposób, który pozwala na późniejszą obróbkę kodu źródłowego. Interfejsy i interfejsy API są kluczową częścią tej dyscypliny: pozwalają myśleć o problemie na jednym poziomie opisu na raz. Jest to o wiele łatwiejsze niż jednoczesne myślenie o regułach spójności biznesowej i implementacjach list połączonych, dlatego wymuszenie takiego oddzielenia obaw jest lepsze niż pozwolenie programistom klienckim na użycie twojego kodu w dowolny sposób.

Trudno w to uwierzyć wielu kowbojskim programistom, którzy są przekonani, że rozumieją wszystko, co piszą, są znacznie lepsi niż przeciętni myśliciele i potrafią poradzić sobie z całą złożonością, która sprawia kłopoty „mniejszym” programistom. Nieznajomość własnych ograniczeń poznawczych jest niezwykle powszechnym zjawiskiem - dlatego najlepsze praktyki w organizacji kodu są tak niezwykle ważne (i tak często ignorowane).

Powtarzając, interfejsy i bariery API są w dużej mierze dobre , nawet jeśli współpracujesz tylko ze sobą. Jeśli chodzi o biblioteki zewnętrzne, jeśli mają ze sobą dobrze przemyślany interfejs API, nie widzę problemu w korzystaniu z niego, ponieważ jest tak długo, jak długo nie przewiduje się zamiany tej biblioteki na inną. W przeciwnym razie owijka lub warstwa antykorupcyjna może być bardzo dobrym pomysłem.

Kilian Foth
źródło
Podoba mi się twój pogląd, że SE polega głównie na osiągnięciu pożądanego efektu w sposób, który pozwala na późniejszą obróbkę kodu źródłowego. Chciałbym móc tak dobrze to sformułować w mojej ostatniej pracy, w której zawsze walczyłem o czysty kod!
MetaFight,
Czy istnieje konwencja nazewnictwa dla interfejsów API, które są tylko interfejsami, których będę używać wszędzie? Na przykład, jeśli wykonuję wzorzec poleceń, czy nazywam go „dowództwem”?
Snoop
@StevieV Istnieją różne, np. IBlahZaimplementowane przez Blahlub Blahzaimplementowane przez BlahImpl. Nie podoba mi się oba, i zwykle używają Blahzaimplementowane przez OralBlah, WrittenBlahlub ASLBlah. Ale jak zwykle ważniejsze jest dostosowanie się do istniejącej bazy kodu i oczekiwań niż do jakiegokolwiek ogólnego standardu.
Kilian Foth
4

Zamiast niewolniczego programowania tylko interfejsów, może warto przyjrzeć się rozwojowi / projektowaniu testowemu (TDD)?

Wiele osób uważa TDD za praktykę testowania, ale w rzeczywistości jest to podejście projektowe, w którym pozwalasz testom ujawnić, w jaki sposób twój kod będzie używany za pomocą testów (początkowo za pomocą testów jednostkowych, ale może być również przez testy integracyjne).

Programowanie interfejsów jest ważną bronią w twoim zestawie narzędzi, ale jak większość rzeczy, nie zawsze jest to odpowiednie rozwiązanie / technika / praktyka, ponieważ nie zawsze jest potrzebne. Powinieneś zaprogramować interfejsy tam, gdzie potrzebujesz.

Korzystanie z TDD zmusi cię do zbadania, gdzie takie interfejsy są ważne i gdzie, szczerze mówiąc, nie ma to znaczenia. Na koniec powinieneś mieć całkiem niezły zestaw testów jednostkowych w całej bazie kodu.

Jeśli chodzi o korzystanie z bibliotek stron trzecich, zdecydowanie polecam owijanie ich we własne abstrakty, tam gdzie to właściwe; i nie pozwól klientom Twojego interfejsu API „wiedzieć” o nich.

Powodzenia!

[edytuj: zobaczyłem odpowiedź megaflight - całkowicie się zgadzam]

rupjones
źródło
2
TDD niejawnie ma na myśli raczej interfejs niż implementację, chociaż może to nie być formalna deklaracja „interfejsu”.
DougM,
1
To świetna odpowiedź. +1 za zasugerowanie TDD, które moim zdaniem jest rozwiązaniem prawdziwego problemu PO, od czego zacząć przy pracy nad nowym projektem, i dałbym +1 ponownie, gdybym mógł za „Używanie TDD zmusi cię do zbadania, gdzie takie interfejsy są ważne i gdzie, szczerze mówiąc, nie ma to znaczenia ”.
Benjamin Hodgson,
2

Myślę, że to przesada. Jeśli użytkownik twojego API nie musi być zmuszany do implementacji / używania czegoś w określony sposób, to bym to pominął. Interfejsy to umowy, jeśli ich nie potrzebuję, to po co mi je dawać?

Myślę, że ludzie nadużywają interfejsów. Dodajesz warstwę złożoności, która w większości przypadków nie jest potrzebna.

Kyle Johnson
źródło
Myślę, że ludzie pod -Za pomocą interfejsów. Jeśli chcesz tworzyć elementy wielokrotnego użytku, interfejs jest nie tylko dodatkiem „miłym do posiadania”, ale najważniejszą rzeczą do załatwienia. Oprócz faktycznej realizacji oczywiście.
JensG,
1

Programowanie wbrew umowie jest prawie zawsze dobrym pomysłem. Umowa ta nie musi być interfejsem, może być wypełniona przez klasę. Moim zdaniem interfejsy stały się nieco nadużywane wraz z DI ze względu na obawy związane z testowaniem jednostkowym i szydzącymi ramami.

Osobiście wolę wprowadzać interfejsy tylko wtedy, gdy najprawdopodobniej mogę mieć lub mam więcej niż 1 realizację umowy. Interfejsy są świetne dla repozytoriów, w których chcę abstrahować dostęp do danych, ale prawdopodobnie mniej dla mojej standardowej logiki biznesowej, która prawdopodobnie będzie stosunkowo mało elastyczna.

Teraz brak interfejsu może powodować problemy z testowaniem jednostek, szczególnie dla purystów. Ale jestem zainteresowany wyśmiewaniem zewnętrznych zależności moich programów, a nie wewnętrznych zależności. Chcę, aby moje testy przeprowadzały sprawdzanie poprawności kodu, a nie echo struktury kodu.

Peter Smith
źródło