Obok mnie siedzi kolega, który zaprojektował taki interfejs:
public interface IEventGetter {
public List<FooType> getFooList(String fooName, Date start, Date end)
throws Exception;
....
}
Problem polega na tym, że obecnie nie używamy tego parametru „end” nigdzie w naszym kodzie, po prostu istnieje, ponieważ w przyszłości będziemy musieli go użyć.
Próbujemy go przekonać, że wprowadzanie parametrów do interfejsów, które w tej chwili nie są przydatne, jest kiepskim pomysłem, ale wciąż nalega, aby dużo pracy trzeba było wykonać, jeśli za jakiś czas zastosujemy datę zakończenia. później i wtedy trzeba dostosować cały kod.
Moje pytanie brzmi: czy są jakieś źródła, które zajmują się takim tematem jak „szanowani” guru kodujący, z którymi możemy go połączyć?
end
parametr do tego obiektu, a nawet domyślnie, aby nie łamać kodunull
. Klasy implementujące mogą następnie zastąpić w razie potrzeby.IQueryable
(można przyjmować tylko niektóre wyrażenia) na kod poza DALOdpowiedzi:
Poproś go, aby dowiedział się o YAGNI . Uzasadnienie strony Wikipedii może być szczególnie interesujące tutaj:
Inne możliwe argumenty:
„80% kosztów użytkowania oprogramowania przypada na konserwację” . Napisanie kodu w samą porę obniża koszty utrzymania: trzeba zachować mniej kodu i można skupić się na rzeczywiście potrzebnym kodzie.
Kod źródłowy jest pisany raz, ale czytany dziesiątki razy. Dodatkowy argument, nigdzie nie używany, prowadziłby do zmarnowanego czasu na zrozumienie, dlaczego istnieje argument, który nie jest potrzebny. Biorąc pod uwagę, że jest to interfejs z kilkoma możliwymi implementacjami, wszystko staje się jeszcze trudniejsze.
Oczekuje się, że kod źródłowy sam się dokumentuje. Rzeczywisty podpis jest mylący, ponieważ czytelnik mógłby pomyśleć, że
end
ma to wpływ na wynik lub wykonanie metody.Osoby piszące konkretne implementacje tego interfejsu mogą nie rozumieć, że nie należy używać ostatniego argumentu, co prowadziłoby do różnych podejść:
Nie potrzebuję
end
, więc po prostu zignoruję jego wartość,Nie potrzebuję
end
, więc rzucę wyjątek, jeśli nie jestnull
,Nie potrzebuję
end
, ale spróbuję jakoś z tego skorzystać,Napiszę dużo kodu, który może być później użyty, kiedy
end
będzie potrzebny.Ale pamiętaj, że twój kolega może mieć rację.
Wszystkie poprzednie punkty oparte są na tym, że refaktoryzacja jest łatwa, więc dodanie argumentu później nie będzie wymagało dużego wysiłku. Ale to jest interfejs i jako interfejs może być używany przez kilka zespołów przyczyniających się do innych części twojego produktu. Oznacza to, że zmiana interfejsu może być szczególnie bolesna, w takim przypadku YAGNI tak naprawdę nie ma tutaj zastosowania.
Odpowiedź hjk daje dobre rozwiązanie: dodanie metody do już używanego interfejsu nie jest szczególnie trudne, ale w niektórych przypadkach wiąże się również ze znacznymi kosztami:
Niektóre frameworki nie obsługują przeciążeń. Na przykład i jeśli dobrze pamiętam (popraw mnie, jeśli się mylę), WCF platformy .NET nie obsługuje przeciążeń.
Jeśli interfejs ma wiele konkretnych implementacji, dodanie metody do interfejsu wymagałoby przejrzenia wszystkich implementacji i dodania tam również metody.
źródło
(jakiś czas później)
To wszystko, czego potrzebujesz, przeciążenie metody. Dodatkową metodę w przyszłości można wprowadzić w sposób przejrzysty, bez wpływu na wywołania istniejącej metody.
źródło
end
parametr jest teraz niepotrzebny i nadal korzysta zend
metody „-less” w całym projekcie (projektach), to aktualizacja interfejsu jest najmniejszym zmartwieniem, ponieważ staje się koniecznością aktualizacji klasy implementacyjne. Moja odpowiedź dotyczy konkretnie części „dostosuj cały kod”, ponieważ wygląda na to, że kolega myślał o konieczności zaktualizowania wywołań oryginalnej metody w całym projekcie (ach) w celu wprowadzenia trzeciego parametru domyślnego / zastępczego .Apele do władzy nie są szczególnie przekonujące; lepiej przedstawić argument, który jest ważny bez względu na to, kto to powiedział.
Oto reductio ad absurdum, które powinno przekonać lub wykazać, że twój współpracownik utknął na „racji” niezależnie od wrażliwości:
To, czego naprawdę potrzebujesz
Nigdy nie wiadomo, kiedy trzeba będzie internacjonalizować Klingon, więc lepiej się tym teraz zająć, ponieważ będzie to wymagało dużo pracy, a Klingony nie są znane z ich cierpliwości.
źródło
You never know when you'll have to internationalize for Klingon
. Dlatego powinieneś po prostu przekazaćCalendar
i pozwolić, aby kod klienta zdecydował, czy chce wysłać aGregorianCalendar
lubKlingonCalendar
(założę się, że niektórzy już to zrobili). Duh. :-pStarDate sdStart
iStarDate sdEnd
? W końcu nie możemy zapomnieć o Federacji ...Date
!HebrewDate start
iHebrewDate end
.Z punktu widzenia inżynierii oprogramowania uważam, że właściwym rozwiązaniem tego rodzaju problemów jest wzorzec konstruktora. Jest to zdecydowanie link od autorów „guru” do twojego kolegi http://en.wikipedia.org/wiki/Builder_pattern .
We wzorcu konstruktora użytkownik tworzy obiekt zawierający parametry. Ten parametr kontener zostanie następnie przekazany do metody. Zapobiegnie to wszelkim rozszerzeniom i przeciążeniu parametrów, których kolega będzie potrzebował w przyszłości, a jednocześnie sprawi, że wszystko będzie bardzo stabilne, gdy konieczne będzie wprowadzenie zmian.
Twój przykład stanie się:
źródło
IEventGetter
doISearchFootRequest
. Zamiast tego zasugerowałbym coś takiegopublic IFooFilter
z członkiem,public bool include(FooType item)
który zwraca, czy dołączyć element. Następnie poszczególne implementacje interfejsu mogą zdecydować, w jaki sposób przeprowadzą to filtrowanieNie potrzebujesz go teraz, więc nie dodawaj go. Jeśli będziesz go później potrzebować, rozszerz interfejs:
źródło
Żadna zasada projektowania nie jest absolutna, więc choć w większości zgadzam się z innymi odpowiedziami, pomyślałem, że będę grał w adwokata diabła i omówię niektóre warunki, w których rozważę zaakceptowanie rozwiązania twojego kolegi:
Now()
, to dodanie parametru usuwa efekt uboczny, który ma zalety w buforowaniu i testowaniu jednostkowym. Może pozwala to na prostszą implementację. A może jest bardziej spójny z innymi interfejsami API w twoim kodzie.Biorąc to pod uwagę, z mojego doświadczenia wynika, że największym następstwem YAGNI jest YDKWFYN: Nie wiesz, jakiej formy będziesz potrzebować (tak, właśnie wymyśliłem ten akronim). Nawet jeśli potrzebuje jakiś parametr limit może być stosunkowo przewidywalne, to może przybrać formę limitem strony lub liczbę dni lub logiczną informując korzystania datę zakończenia z tabeli preferencji użytkownika lub dowolną ilość rzeczy.
Ponieważ nie masz jeszcze takiego wymagania, nie możesz wiedzieć, jakiego typu powinien być ten parametr. Często kończy się to albo niezręcznym interfejsem, który nie jest najlepiej dopasowany do twoich wymagań, albo musisz go zmienić.
źródło
Brak wystarczających informacji, aby odpowiedzieć na to pytanie. To zależy od tego, co
getFooList
faktycznie robi i jak to robi.Oto oczywisty przykład metody, która powinna obsługiwać dodatkowy parametr, używany lub nie.
Wdrożenie metody działającej na kolekcji, w której można określić początek, ale nie koniec kolekcji, jest często głupie.
Naprawdę musisz spojrzeć na sam problem i zapytać, czy parametr jest bezsensowny w kontekście całego interfejsu i naprawdę, ile obciążenia narzuca dodatkowy parametr.
źródło
Obawiam się, że twój kolega może mieć bardzo ważny punkt. Chociaż jego rozwiązanie nie jest najlepsze.
Z jego proponowanego interfejsu jasno to wynika
zwraca instancje znalezione w określonym przedziale czasu. Jeśli klienci obecnie nie używają parametru końcowego, nie zmienia to faktu, że oczekują instancji znalezionych w określonym przedziale czasu. Oznacza to po prostu, że obecnie wszyscy klienci używają otwartych interwałów (od początku do wieczności)
Lepszym interfejsem byłoby więc:
Jeśli podajesz interwał za pomocą statycznej metody fabrycznej:
wtedy klienci nie będą nawet odczuwać potrzeby określania czasu zakończenia.
Jednocześnie twój interfejs bardziej poprawnie przekazuje to, co robi, ponieważ
getFooList(String, Date)
nie komunikuje, że dotyczy to interwału.Zauważ, że moja sugestia wynika z tego, co obecnie robi metoda, a nie z tego, co powinna lub może zrobić w przyszłości, i dlatego zasada YAGNI (która jest naprawdę bardzo ważna) nie ma tutaj zastosowania.
źródło
Dodanie nieużywanego parametru jest mylące. Ludzie mogą nazwać tę metodę, zakładając, że ta funkcja będzie działać.
Nie dodałbym tego. Późniejsze dodanie go za pomocą refaktoryzacji i mechanicznej naprawy stron wywoławczych jest banalne. W statycznym języku jest to łatwe do zrobienia. Nie trzeba go chętnie dodawać.
Jeśli nie jest to powód, aby tego parametru można uniknąć nieporozumień: Dodawanie dochodzić w realizacji tego interfejsu do wyegzekwowania, że ten parametr jest przekazywana jako wartość domyślną. Jeśli ktoś przypadkowo użyje tego parametru, przynajmniej natychmiast zauważy podczas testowania, że ta funkcja nie jest zaimplementowana. To eliminuje ryzyko wrzucenia błędu do produkcji.
źródło