Ostatnio opracowuję własny interfejs API i dzięki temu zainwestowanemu zainteresowaniu projektowaniem interfejsu API byłem bardzo zainteresowany, jak mogę ulepszyć swój interfejs API.
Jednym z aspektów, który pojawiał się kilka razy jest (nie przez użytkowników mojego API, ale podczas mojej dyskusji na ten temat): należy wiedzieć, patrząc na kod wywołujący API, co robi .
Na przykład zobacz tę dyskusję na GitHub dla repozytorium dyskursu , wygląda to tak:
foo.update_pinned(true, true);
Patrząc na kod (nie znając nazw parametrów, dokumentacji itp.) Nie można zgadnąć, co zamierza zrobić - co oznacza drugi argument? Sugerowana poprawa to mieć coś takiego:
foo.pin()
foo.unpin()
foo.pin_globally()
I to wyjaśnia wszystko (przypuszczam, że drugi argument dotyczy tego, czy przypiąć foo globalnie), i zgadzam się w tym przypadku, że później z pewnością byłaby poprawa.
Jednak uważam, że mogą istnieć przypadki, w których metody ustawiania innego, ale logicznie powiązanego stanu byłyby lepiej widoczne jako jedno wywołanie metody niż osobne, nawet jeśli nie wiedziałbyś, co robi po prostu patrząc na kod . (Aby dowiedzieć się, musiałbyś sięgnąć do nazw parametrów i dokumentacji - które osobiście zawsze bym zrobił, bez względu na to, czy nie jestem zaznajomiony z API).
Na przykład ujawniam jedną metodę SetVisibility(bool, string, bool)
na FalconPeer i potwierdzam, że patrzę na linię:
falconPeer.SetVisibility(true, "aerw3", true);
Nie miałbyś pojęcia, co on robi. Ustawia 3 różne wartości, które kontrolują „widoczność” falconPeer
w sensie logicznym: akceptuj prośby o dołączenie, tylko z hasłem i odpowiedz na prośby o wykrycie. Podział tego na 3 wywołania metod może spowodować, że użytkownik interfejsu API ustawi jeden aspekt „widoczności”, zapominając o ustawieniu innych, o których zmuszam ich do myślenia, ujawniając tylko jedną metodę ustawiania wszystkich aspektów „widoczności” . Ponadto, gdy użytkownik chce zmienić jeden aspekt, prawie zawsze będzie chciał zmienić inny aspekt i może teraz to zrobić za jednym razem.
setSize(10, 20)
nie jest tak czytelny jak setSize(width=10, height=20)
lub random(distribution='gaussian', mean=0.5, deviation=1)
. W językach z wymuszonymi nazwanymi parametrami logiczne mogą przekazywać dokładnie taką samą ilość informacji, jak przy użyciu wyliczeń / nazwanych stałych, więc mogą być dobre w interfejsach API.
update
sposób:foo.update(pinned=true, globally=true)
. Lub:foo.update_pinned(true, globally=true)
. Tak więc odpowiedź na twoje pytanie powinna uwzględniać także funkcje językowe, ponieważ dobre API dla języka X może nie być dobre dla języka Y i odwrotnie.