Marcin, ze strony Forte jesteś najlepiej obeznany z projektem dla naszego duńskiego klienta. Powiedz na początek - jakie wersje .NET wykorzystujecie i dlaczego?

Celujemy w najnowsze wersje LTS .NET, choć obecnie korzystamy z wersji STS. Gdy tylko pojawi się nowa wersja LTS, planujemy migrację. Nowe komponenty budujemy od zera w nowoczesnych technologiach, jednak pewne decyzje są ograniczane przez stan zastany w systemie legacy. Migracja do nowego stosu oznacza również konieczność przejęcia wielu istniejących problemów technicznych.

Czy korzystacie z konkretnych wzorców projektowych?

Tak – podstawą naszej architektury jest wzorzec CQS (Command Query Segregation), który zakłada rozdzielenie operacji modyfikujących stan aplikacji (Command) od operacji tylko odczytujących dane (Query). Dzięki temu struktura kodu jest bardziej przejrzysta i łatwiejsza w utrzymaniu. Staramy się projektować system modułowo, z zachowaniem równowagi między czytelnością, wydajnością a skalowalnością – to jedna z naszych kluczowych zasad projektowych.

Z jakich bibliotek i frameworków korzystacie poza .NET?

Do zaimplementowania wzorca CQS wykorzystujemy MediatR, który pozwala nam zachować czytelny podział pomiędzy operacjami zapisu i odczytu. W przyszłości planujemy zastąpić go innym rozwiązaniem, ponieważ MediatR przechodzi na model komercyjny. W backendzie korzystamy również z Entity Framework oraz Azure Graph API. Po stronie frontendu opieramy się na Next.js oraz React Query, które zapewniają efektywną komunikację z API i zarządzanie stanem danych.

Jak podchodzicie do CI/CD?

Wdrożyliśmy procesy CI/CD z wykorzystaniem Azure Pipelines, które są integralną częścią platformy Azure DevOps. Obecnie rozwijamy infrastrukturę w podejściu Infrastructure as Code, wykorzystując Bicep – dedykowany przez Microsoft framework do zarządzania zasobami w chmurze. W zakresie ciągłego wdrażania (CD) opieramy się na wzorcu Landing Zones, który umożliwia porządkowanie zasobów w ramach wielu Azure Subscriptions i pozwala nam utrzymać zgodność ze standardami enterprise w zakresie bezpieczeństwa, zarządzania i skalowalności.

Jakie narzędzia i praktyki pomagają Wam utrzymać wysoką jakość kodu?

Naszym codziennym standardem jest code review. Nie korzystamy obecnie z narzędzi takich jak SonarQube. Tworzymy testy jednostkowe dla nowych komponentów, a w kodzie legacy dopisujemy je przy okazji refaktoryzacji – choć bywa to trudne ze względu na jego złożoność.

Czy stosujecie TDD lub inne podejścia do testowania?

Nie pracujemy ściśle według TDD, ale testy jednostkowe są obowiązkowe. Mamy QA w zepole.

Jakie narzędzia wykorzystujecie do monitoringu i logowania?

Bazujemy na Azure Application Insights, który pozwala monitorować stan systemu i definiować alerty.

Jak wygląda proces deploymentu?

Stosujemy klasyczny Git Flow. Programiści pracują na feature branchach, z których zmiany trafiają do głównej gałęzi developerskiej i są wdrażane na środowisko developerskie. Następnie, przez dedykowaną gałąź testową, przechodzą na staging, skąd wypuszczamy releasy. W razie potrzeby jesteśmy elastyczni i dostosowujemy proces.

Czy jako developer masz wpływ na decyzje architektoniczne i technologiczne?

Zdecydowanie tak. Nie mamy formalnie wyznaczonego architekta – decyzje podejmujemy wspólnie, słuchając każdego członka zespołu. To kolektywne podejście dobrze się u nas sprawdza.

Jakie są największe wyzwania techniczne w projekcie?

Największym wyzwaniem jest komunikacja między naszą chmurową infrastrukturą a systemem klienta on-premise. Współpracujemy z zespołem IT klienta oraz jego doradcami technologicznymi. To trójstronne partnerstwo wymaga dobrej koordynacji i wysokich standardów bezpieczeństwa. Nasza Product Ownerka odgrywa tu kluczową rolę – doskonale spina wszystkie wątki i skutecznie wywalcza potrzebne decyzje. Klient to duża korporacja, ale świadomie podchodzi do współpracy i zna swoje potrzeby.

Jak podejmowane są decyzje techniczne?

Większość decyzji inicjujemy wewnętrznie. W przypadku potrzeby formalnej zgody – np. na zakup licencji czy pluginów do Umbraco – komunikujemy się przez Product Ownerkę, która koordynuje ustalenia z zespołem klienta w Danii.

Jakie były najważniejsze zmiany techniczne ostatnio?

Największym osiągnięciem było skonfigurowanie i uruchomienie środowiska chmurowego wraz z pełną infrastrukturą DevOps. To był wymagający etap, ale dzięki niemu mamy teraz solidne fundamenty pod dalszy rozwój.

Czy projekt ma wysokie wymagania wydajnościowe?

Tak. W określonych momentach miesiąca – np. przy masowym pobieraniu faktur – system jest intensywnie wykorzystywany. Komunikacja z lokalnymi bazami danych klienta potrafi wtedy generować przeciążenia, dlatego optymalizacja zapytań i reagowanie na timeouty to nasze priorytety.

Jakie macie podejście do optymalizacji?

Stawiamy na profilowanie, cache’owanie oraz optymalizację zapytań do baz danych. Staramy się reagować szybko i wdrażać zmiany tam, gdzie widać realny zysk. Nie korzystamy z automatycznych narzędzi do profilowania, tylko analizujemy konkretne przypadki.

Czy projekt obejmuje przetwarzanie dużych ilości danych?

Aktualnie nie zajmujemy się bezpośrednio przetwarzaniem dużych wolumenów danych, choć źródła, z których korzystamy, są intensywnie obciążone. W przyszłości przewidujemy wejście w te obszary.

Czego nauczyłeś się technicznie podczas pracy w tym projekcie?

Na pewno pracy z legacy code – to wymaga nie tylko umiejętności technicznych, ale też cierpliwości i zaufania do siebie. Poza tym pogłębiłem wiedzę na temat CMS-a Umbraco oraz architektury enterprise z wykorzystaniem chmury Azure i B2C.

Dzięki za rozmowę, mam nadzieję, że za jakiś czas gdy zakres projektu się poszerzy będziemy mogli opowiedzieć o nim jeszcze więcej ciekawych rzeczy!