Podczas ostatniej rozmowy o pracę nie mogłem odpowiedzieć na pytanie o SOLID - poza podaniem podstawowego znaczenia różnych zasad. Naprawdę mnie to wkurza. Zrobiłem kilka dni, żeby się rozejrzeć i jeszcze nie opracowałem satysfakcjonującego podsumowania.
Pytanie do wywiadu brzmiało:
Jeśli spojrzałbyś na projekt .Net, o którym mówiłem, że ściśle przestrzegasz zasad SOLID, czego byś oczekiwał pod względem projektu i struktury kodu?
Kręciłem się trochę, tak naprawdę nie odpowiedziałem na pytanie, a potem zbombardowałem.
Jak mogłem lepiej poradzić sobie z tym pytaniem?
Odpowiedzi:
S = zasada pojedynczej odpowiedzialności
Spodziewałbym się więc dobrze zorganizowanej struktury folderów / plików i hierarchii obiektów. Każdą klasę / element funkcjonalności należy nazwać, że jego funkcjonalność jest bardzo oczywista i powinna zawierać jedynie logikę do wykonania tego zadania.
Gdybyście zobaczyli ogromne klasy menedżerskie z tysiącem linii kodu, byłby to znak, że pojedyncza odpowiedzialność nie była przestrzegana.
O = zasada otwarta / zamknięta
Jest to w zasadzie pomysł, aby nowa funkcjonalność była dodawana poprzez nowe klasy, które mają minimalny wpływ na / wymagają modyfikacji istniejącej funkcjonalności.
Spodziewałbym się wielu zastosowań dziedziczenia obiektów, podtypów, interfejsów i klas abstrakcyjnych, aby oddzielić projekt elementu funkcjonalności od faktycznej implementacji, umożliwiając innym tworzenie i wdrażanie innych wersji obok, bez wpływu na oryginał.
L = zasada podstawienia Liskowa
Ma to związek z możliwością traktowania podtypów jako typu nadrzędnego. To wychodzi z pudełka w języku C #, jeśli implementujesz odpowiednią dziedziczoną hierarchię obiektów.
Spodziewałbym się zobaczyć kod traktujący wspólne obiekty jako ich typ podstawowy i wywołujące metody w klasach base / abstract zamiast tworzenia instancji i pracy na samych podtypach.
I = zasada segregacji interfejsu
Jest to podobne do SRP. Zasadniczo definiujesz mniejsze podzbiory funkcjonalności jako interfejsy i pracujesz z nimi, aby utrzymać system w stanie oddzielonym (np.
FileManager
Może mieć pojedynczą odpowiedzialność za obsługę plików we / wy, ale może zaimplementowaćIFileReader
a,IFileWriter
który zawiera konkretne definicje metod do odczytu i pisanie plików).D = zasada inwersji zależności.
Ponownie odnosi się to do utrzymania oddzielenia systemu. Być może chcesz być na poszukiwania wykorzystaniem biblioteki .NET Dependency wtrysk, używane w roztworze, takie jak
Unity
lubNinject
czy system ServiceLocator takich jakAutoFacServiceLocator
.źródło
Wiele małych klas i interfejsów z zastrzykiem zależności w każdym miejscu. Prawdopodobnie w dużym projekcie użyłbyś również frameworka IoC, aby pomóc Ci w konstruowaniu i zarządzaniu żywotnością wszystkich tych małych obiektów. Zobacz https://stackoverflow.com/questions/21288/which-net-dependency-injection-frameworks-are-worth-looking-into
Zauważ, że duży projekt .NET, który ŚCISŁO przestrzega zasad SOLID, niekoniecznie oznacza dobrą bazę kodu do współpracy z każdym. W zależności od tego, kim był ankieter, mógł / ona chcieć, abyś wykazał, że rozumiesz, co oznacza SOLID i / lub sprawdź, jak dogmatycznie przestrzegasz zasad projektowania.
Widzisz, aby być SOLIDNYM, musisz przestrzegać:
S Ingle zasada odpowiedzialności, więc trzeba będzie wiele małych grupach każdy z nich robi tylko jedno
O zasada zamkniętego pióra, która w .NET jest zwykle implementowana z iniekcją zależności, która również wymaga I i D poniżej ...
Zasada podstawienia L iskova jest prawdopodobnie niemożliwa do wyjaśnienia w c # za pomocą jednowierszowej. Na szczęście istnieją inne pytania dotyczące tego problemu, np. Https://stackoverflow.com/questions/4428725/can-you-explain-liskov-substitution-principle-with-a-good-c-sharp-example
I nterface Zasada segregacji działa w tandemie z zasadą otwartego i zamkniętego. Gdyby postępować dosłownie, oznaczałoby to preferowanie dużej liczby bardzo małych interfejsów zamiast kilku „dużych” interfejsów
D ependency zasada inwersji zajęcia na wysokim poziomie nie powinno być uzależnione od klasy niskopoziomowych, zarówno powinna zależeć od abstrakcji.
źródło
Kilka podstawowych rzeczy, których spodziewałbym się zobaczyć w bazie kodu sklepu, który promował SOLID w swojej codziennej pracy:
Wiele wzorców adapterów i kompozytów - spodziewałbym się użycia wielu wzorców adapterów (klasa implementująca jeden interfejs poprzez „przejście” do funkcjonalności innego interfejsu) w celu usprawnienia podłączania zależności opracowanej dla jednego celu w nieco różne miejsca, w których jego funkcjonalność jest również potrzebna. Aktualizacje tak proste, jak zastąpienie rejestratora konsoli rejestratorem plików, będą naruszać LSP / ISP / DIP, jeśli interfejs zostanie zaktualizowany, aby udostępnić sposób określania nazwy pliku do użycia; zamiast tego klasa rejestratora plików ujawni dodatkowe elementy, a następnie adapter sprawi, że rejestrator plików będzie wyglądał jak rejestrator konsoli, ukrywając nowe elementy, więc tylko obiekt przyciągający to wszystko musi znać różnicę.
Podobnie, gdy klasa musi dodać zależność interfejsu podobnego do istniejącego, aby uniknąć zmiany obiektu (OCP), zwykle odpowiedzią jest implementacja wzorca Composite / Strategy (klasa implementująca interfejs zależności i zużywająca wiele innych implementacje tego interfejsu, z różną logiką pozwalającą klasie na przekazanie wywołania do jednej, niektórych lub wszystkich implementacji).
źródło
Odciągnij ich uwagę od dyskusji Jona Skeeta o tym, jak „O” w SOLID jest „nieprzydatny i źle zrozumiany”, i poproś ich, aby mówili o „chronionej wariacji” Alistaira Cockburna i „projekcie odziedziczonym przez Josha Blocha” lub zabraniają go.
Krótkie streszczenie artykułu Skeeta (choć nie poleciłbym porzucenia jego nazwiska bez przeczytania oryginalnego posta na blogu!):
OP zapytał: „Jak mógłbym lepiej poradzić sobie z tym pytaniem?” Jako starszy inżynier prowadzący rozmowę byłbym niezmiernie bardziej zainteresowany kandydatem, który potrafi inteligentnie mówić o zaletach i wadach różnych stylów projektowania kodu, niż kimś, kto może wyrzucić listę punktów.
Inną dobrą odpowiedzią byłoby: „Cóż, to zależy od tego, jak dobrze to zrozumieli. Jeśli wszystko, co wiedzą, to modne słowa SOLID, spodziewałbym się nadużycia dziedziczenia, nadużywania struktur wstrzykiwania zależności, miliona małych interfejsów, z których żaden nie odzwierciedlają słownictwo domenowe używane do komunikowania się z zarządzaniem produktem… ”
źródło
Prawdopodobnie istnieje wiele sposobów, na które można na nie odpowiedzieć w różnym czasie. Myślę jednak, że jest to bardziej podobne do „Czy wiesz, co oznacza SOLID?” Zatem odpowiedź na to pytanie prawdopodobnie sprowadza się do trafienia w punkty i wyjaśnienia go w kontekście projektu.
Oczekujesz więc, że:
źródło
To doskonałe pytanie, choć myślę, że jest to trudne pytanie podczas rozmowy kwalifikacyjnej.
Zasady SOLID naprawdę rządzą klasami i interfejsami oraz tym, w jaki sposób są ze sobą powiązane.
To pytanie naprawdę dotyczy bardziej plików, a niekoniecznie klas.
Krótka spostrzeżenie lub odpowiedź, którą chciałbym udzielić, to to, że generalnie zobaczysz pliki, które zawierają tylko interfejs, a często konwencja polega na tym, że zaczynają się od dużej litery. Poza tym wspomnę, że pliki nie miałyby zduplikowanego kodu (szczególnie w module, aplikacji lub bibliotece) i że kod byłby ostrożnie dzielony między pewnymi granicami między modułami, aplikacjami lub bibliotekami.
Robert Martin omawia ten temat w dziedzinie C ++ w projektowaniu aplikacji C ++ zorientowanych zorientowanych za pomocą metody Booch (patrz rozdziały na temat spójności, zamykania i ponownego użycia) oraz w czystym kodzie .
źródło