Trochę tła: Jako lider zespołu używam NDepend raz w tygodniu, aby sprawdzić jakość naszego kodu. Szczególnie nieocenione jest dla mnie pokrycie testu, wiersze kodu i wskaźniki złożoności cyklicznej. Ale jeśli chodzi o cykle wyrównywania i zależności, jestem trochę ... bardzo zaniepokojony. Patrick Smacchia ma fajny post na blogu, który opisuje cel wyrównania.
Żeby było jasne: w „cyklu zależności” rozumiem cykliczne odniesienia między dwiema przestrzeniami nazw.
Obecnie pracuję nad strukturą GUI opartą na systemie Windows CE dla wbudowanych instrumentów - pomyśl tylko o platformie graficznej dla Androida, ale dla bardzo niskich instrumentów. Framework jest pojedynczym zestawem zawierającym około 50 000 linii kodu (bez testów). Struktura jest podzielona na następujące przestrzenie nazw:
- Podstawowy podsystem nawigacji i menu
- Podsystem ekranu (Prezenterzy / Widoki / ...)
- Warstwa kontrolna / warstwa widgetu
Dzisiaj spędziłem pół dnia, próbując doprowadzić kod do właściwego poziomu [dzięki Resharperowi nie ma problemu w ogóle], ale we wszystkich przypadkach istnieją pewne cykle zależności.
Więc moje pytanie: jak ściśle przestrzegasz zasady „Brak cyklu zależności”? Czy wyrównanie naprawdę jest tak ważne?
źródło
Odpowiedzi:
Niedawno napisałem 2 białe książki, opublikowane na Simple-Talk na temat architektury kodu .NET (pierwsza książka dotyczy zespołów .NET, druga - przestrzeni nazw i poziomowania):
Partycjonowanie bazy kodu za pomocą zespołów .NET i projektów Visual Studio
Definiowanie komponentów .NET z przestrzeniami nazw
Tak to jest!
Cytat z drugiej białej księgi:
(...)
źródło
Nigdy nie dopuszczam okrągłych zależności między klasami lub przestrzeniami nazw. W języku C #, Java i C ++ zawsze możesz przerwać zależność od klasy okrągłej, wprowadzając interfejs.
Kodowanie w pierwszej kolejności utrudnia wprowadzenie zależności cyklicznych.
źródło
To zawsze zawód: musisz zrozumieć koszt zależności, aby zrozumieć, dlaczego należy unikać zależności. W ten sam sposób, jeśli rozumiesz koszt zależności, możesz lepiej zdecydować, czy jest ona warta w konkretnym przypadku.
Na przykład w grach konsolowych często polegamy na zależnościach, w których potrzebne są bliskie relacje informacji, głównie ze względu na wydajność. W porządku, o ile nie musimy być tak elastyczni jak na przykład narzędzie do edycji.
Jeśli rozumiesz ograniczenia związane z uruchomieniem oprogramowania (sprzęt, system operacyjny lub po prostu projektowanie (np. „Łatwiejszy interfejs użytkownika”)), łatwo jest wybrać, które zależności nie powinny zostać wykonane, a które ok.
Ale jeśli nie masz dobrego i jasnego powodu, unikaj jakiejkolwiek zależności. Kod zależny to piekło sesji debugowania.
źródło
Za każdym razem, gdy omawiany jest ten temat, uczestnicy zwykle tracą rozróżnienie między cyklami kompilacji i cykli wykonawczych. To pierwsze jest tym, co John Lakos nazwał „fizycznym projektem”, podczas gdy drugie jest w zasadzie nieistotne w dyskusji (nie rozłączaj się z cyklami czasu wykonywania, takimi jak te wywołane wywołaniami zwrotnymi).
To powiedziawszy, John Lakos był bardzo surowy w eliminowaniu wszystkich cykli (czasu kompilacji). Jednak Bob Martin przyjął postawę, że tylko cykle między plikami binarnymi (np. DLL, pliki wykonywalne) są znaczące i należy ich unikać; uważał, że cykle między klasami w pliku binarnym nie są strasznie ważne.
Osobiście uważam pogląd Boba Martina na ten temat. Nadal jednak zwracam uwagę na cykle między klasami, ponieważ brak takich cykli ułatwia innym czytanie i uczenie się kodu.
Należy jednak zauważyć, że żaden kod tworzony za pomocą programu Visual Studio nie może mieć cyklicznych zależności między plikami binarnymi (kod macierzysty lub zarządzany). Zatem najpoważniejszy problem z cyklami został dla ciebie rozwiązany. :)
źródło
Niemal całkowicie, ponieważ cykle zależności typu kompilacji są niewygodne w Haskell, a niemożliwe w Agdzie i Coq, i są to języki, których zwykle używam.
źródło