Jak zwykle podchodzisz do problemów zależności przechodnich, które występują w czasie wykonywania w dużych projektach oprogramowania?
Przez ostatnie trzy tygodnie próbowałem uruchomić komponent dużego oprogramowania w innym komponencie oprogramowania, ale okresowo umiera z powodu problemów z przechodnią, które są znane tylko w czasie wykonywania.
Przez problemy zależności przechodnich rozumiem, że niektóre zależności zależności danego projektu kolidują z innymi zależnościami w czasie wykonywania, powodując niestabilność lub natychmiastową awarię.
Istnieją setki zależności od setek zależności i istnieje około 50 podprojektów związanych z narzędziem, nad którymi pracują w izolacji inne zespoły, w których wszystkie moduły głęboko zagnieżdżają zależności między sobą. Nikt nie wie, do czego służą wszystkie podprojekty, biorąc pod uwagę skalę i złożoność projektu.
Czy w tej sytuacji spróbujesz wygenerować wizualną reprezentację DAG dla każdej zależności komponentu, którego dotyczy problem, i spróbujesz ustalić, gdzie w czasie wykonywania mogą wystąpić kolizje? Nie mam kontroli nad zarządzaniem zależnościami w innych podprojektach i nie mogę zmienić żadnego kodu Java napisanego przez innych programistów
Rozwiązania, które wymyśliłem, działają tylko przez godzinę lub dwie, a potem przestają działać z powodu zmian w komponentach początkowych. Przykładem wcześniejszego komponentu jest artefakt, od którego zależy projekt, nad którym pracuję, od którego jest budowany na wcześniejszym etapie w potoku CI.
Na prośby innych osób zamierzam podać informacje o tym, jaka technologia jest używana, na ryzyko zamknięcia pytania za dostarczenie zbyt dużej ilości informacji lub zbyt długiego ciała:
- Maven służy do zarządzania zależnościami; i
- Sprężyna jest używana jako pojemnik DI;
- Większość problemów związanych z zależnościami obejmuje nakładające się konteksty komponentu bean w wyniku załadowania kontekstów innych modułów w czasie wykonywania
- Produkt działa poprawnie, a istnieją testy zawierające testy jednostkowe i testy integracyjne, aby uniknąć poprawności działania programu
Zasadniczo szukam niezależnego od języka podejścia do identyfikowania sposobów rozwiązywania konfliktów zależności bez wyliczania wszystkich możliwych kombinacji zależności danego projektu.
Nie mogę ponownie zaprojektować projektu, dodać dodatkowych bramek jakości, naciskać na zmiany paradygmatu w firmie ani zmieniać języków jako rozdzielczości.
Odpowiedzi:
Możliwe jest rozwiązanie problemu za pomocą niestandardowych modułów ładujących, aby każdy moduł w aplikacji miał własne środowisko wykonawcze.
Zasadniczo zdefiniowałbyś podstawowe środowisko składające się z małego jądra aplikacji, wraz z wszelkimi zależnościami uzgodnionymi powszechnie i wszystkimi interfejsami niezbędnymi do komunikacji między modułami. Następnie każdy ładowany moduł otrzymuje własny moduł ładujący, który ma dostęp do (1) klas ze środowiska wykonawczego, (2) klas z rdzenia aplikacji i (3) klas z tego modułu i jego bezpośrednich zależności. Cała komunikacja między modułami odbywa się za pośrednictwem interfejsów zdefiniowanych w rdzeniu, dzięki czemu żaden moduł nie zależy bezpośrednio od innego.
Technikę tę stosuje się na serwerach aplikacji, aby umożliwić aplikacjom zależności, które w innym przypadku kolidowałyby, dzięki czemu można zobaczyć działającą implementację tej techniki, na przykład w Tomcat (i, jeśli masz szczęście, możesz użyć Tomcat's wdrożenie z niewielkimi zmianami).
źródło
Nigdy nie współpracowałem z Maven ani Spring, ale aby dać ci ogólną odpowiedź na ogólne pytanie: jeśli chodzi o problemy z zależnościami, twój system powinien być zaprojektowany tak, aby wykryć je jak najwcześniej i kiedy te problemy zostaną wykryte , należy je natychmiast zasygnalizować, podając ich możliwą przyczynę.
Idealnie, ten moment nie jest w „czasie produkcji”. Najlepszym momentem jest „czas kompilacji”, ale w twoim przypadku wydaje się to niemożliwe. Drugą najlepszą opcją są testy w czasie wykonywania. Powiedziałeś nam, że istnieją „testy integracyjne”, ale ponieważ nie wykrywają problemów zależności, wydają się być niekompletne lub ogólnie nie testują kolizji zależności. Właśnie tam powinieneś zacząć próbować rozwiązać problem.
Co więcej, aby testy były bardziej skuteczne, komponenty muszą „szybko zawieść”, gdy pojawi się problem zależności. Oznacza to, że po rozwiązaniu zależności i załadowaniu komponentu potencjalne kolizje zależności powinny zostać natychmiast sprawdzone i zasygnalizowane. Jeśli system po raz pierwszy uruchomi się na godzinę przed wykryciem kolizji, bardzo trudno będzie znaleźć przyczynę problemu. Nie wiem, czy Maven / Spring już oferuje wbudowaną strategię „szybkiego niepowodzenia”, ale jeśli tak nie jest, spróbuj myśleć w tym kierunku.
Aby złagodzić problemy związane z produkcją, system powinien być tak zaprojektowany, aby nie umierał całkowicie, gdy dojdzie do kolizji zależności z udziałem mniej ważnego podskładnika. Awaria nie powinna być oczywiście maskowana, ale system powinien idealnie odrzucać ładowanie tego komponentu, rejestrować i / lub sygnalizować problem i pozostawać w stabilnym stanie. Po pierwszym załadowaniu komponentu system staje się niestabilny, a dopiero później wykrywasz problem, prawdopodobnie prawdopodobnie będziesz musiał całkowicie zamknąć i ponownie uruchomić system, co, jak sądzę, jest lepszym rozwiązaniem.
Na przykład, jeśli Twój system to sklep internetowy, a Twój moduł podrzędny „subskrypcja biuletynu” nie może być ładowany przez kilka godzin, jest to coś, co może być łatwiej tolerowane, tak jakby cały sklep już nie działał.
Wreszcie, może to nie być opcja w twoim przypadku, ale jeśli komponenty można uruchomić w lepszej izolacji względem siebie, a jeśli to pozwoli uniknąć kolizji zależności, może to być podejście, o którym warto pomyśleć.
źródło
Pomyśl o tym, że po prostu myślę tutaj głośno. W zależności od wymagań / ograniczeń czasowych mogę rozważyć:
1) utwórz listę interfejsów i ich implementacji (używając refleksji, jeśli jest dostępna)
2) stwórz coś w rodzaju otoki wokół swojej DI. Kiedy DI jest proszony o zapewnienie konkretnej implementacji, sprawdź, czy istnieje już reguła DI; jeśli reguła istnieje - po prostu zwróć to, co zapewnia DI; w przeciwnym razie jeśli istnieje jedna implementacja interfejsu i możesz utworzyć instancję - zaloguj się i zwróć instancję; w przeciwnym razie zaloguj się i zawieść.
Chyba zależy od tego, jak bardzo chcesz się zaangażować, ale ostatecznie chcesz mieć pełną listę tego, co wymaga tego - to rozwiązanie w końcu wygeneruje tę listę.
Prawdopodobnie jest to jednak dużo pracy i nie jest wiarygodne - co zrobić, jeśli masz dziwny stan wymagający pewnej zależności raz na niebieskim księżycu?
Co masz na myśli mówiąc „zmiany w komponentach upstream”?
źródło
Jeśli podążę za tobą poprawnie, problem polega na tym, że kod, którego potrzebujesz użyć, jest zależny od czasu wykonania modułów wyrażonych w Spring XML, ale maven nie jest o nich informowany. Kiedy ich używasz, rzeczy, których potrzebują (zależności przechodnie), nie znajdują się w twojej ścieżce klas i nie robią tego, co powinny.
Zgaduję, kiedy pytasz kolegów, jak to zrobić? ”, Odpowiadają:„ oczywiście, że potrzebujesz tej listy 35 modułów i wersji , jak możesz tego nie wiedzieć? ”.
Prawdopodobnie po zakończeniu testów integracyjnych wymagane moduły są deklarowane jako zależności testowe. Tak więc systematyczne rozwiązanie polega na skonfigurowaniu inspekcji pom testów integracyjnych, aby upewnić się, że nie mają nic oprócz narzędzi testowych innych firm zadeklarowanych jako zależności testowe. Może to nawet zostać zautomatyzowane przez wtyczkę maven enforcer .
Najwyraźniej nie możesz tego zrobić, więc prawdopodobnie znajdziesz tutaj najlepszą opcję .
źródło