Współczesna inżynieria oprogramowania zdaje się podążać w jednym kierunku: chmura, architektura mikroserwisowa, aplikacje typu SPA (Single Page Application) i podejście mobile-first. To standardy, które w większości przypadków sprawdzają się doskonale. Jednak w GOTOMA SOFTWARE HOUSE wierzymy, że rola architekta systemowego nie polega na bezrefleksyjnym podążaniu za trendami, ale na doborze narzędzi, które najlepiej rozwiązują unikalne problemy biznesowe i operacyjne klienta.
Projekt realizowany dla firmy HARMO jest tego doskonałym przykładem. Odsłaniamy karty i pokazujemy techniczną stronę tego przedsięwzięcia.
Opowiemy o tym, dlaczego w 2024 roku zdecydowaliśmy się napisać aplikację desktopową w technologii WPF zamiast modnego Reacta. Wyjaśnimy, jak zbudowaliśmy nowoczesny pipeline CI/CD dla izolowanego środowiska on-premise. Przeanalizujemy bolesny proces migracji danych z systemu legacy i pokażemy, jak algorytmy synchronizacji radzą sobie z pracą offline.
To tekst dla inżynierów, napisany przez inżynierów. Bez marketingowego pudrowania rzeczywistości – tylko kod, architektura i lekcje wyciągnięte z pola walki.
Podstawowym założeniem projektowym było zrozumienie specyfiki pracy użytkownika końcowego. W przypadku HARMO byli to programiści i inżynierowie DevOps. Ich praca charakteryzuje się wysokim tempem, częstym przełączaniem kontekstu (Context Switching) i koniecznością precyzyjnego rejestrowania czasu pracy (Time Tracking) z dokładnością co do minuty.
Pierwszym dylematem architektonicznym był wybór platformy dla aplikacji klienckiej. Naturalnym odruchem w dzisiejszych czasach jest budowa aplikacji webowej (SPA) lub wykorzystanie wrapperów typu Electron. Jednak po głębokiej analizie wymagań niefunkcjonalnych, zdecydowaliśmy się na natywną aplikację desktopową w technologii .NET/WPF.
Dlaczego odrzuciliśmy podejście webowe (PWA/SPA)? Deweloperzy w HARMO pracują na wielu narzędziach jednocześnie (IDE, terminale, kontenery, przeglądarka z dokumentacją). Kolejna karta w przeglądarce to ryzyko. Ryzyko przypadkowego zamknięcia, ryzyko „uśpienia” procesu przez mechanizmy oszczędzania energii przeglądarki (co jest zabójcze dla precyzji timerów) oraz trudność w obsłudze skrótów globalnych.
Technologia WPF (Windows Presentation Foundation) pozwoliła nam na osiągnięcie kilku kluczowych celów:
Backend systemu musiał obsłużyć dwa rodzaje ruchu: standardowe operacje na danych oraz komunikację w czasie rzeczywistym. Zastosowaliśmy podejście hybrydowe:
Największym wyzwaniem w aplikacjach desktopowych jest obsługa braku sieci. Deweloper jadący pociągiem lub pracujący przy niestabilnym VPN nie może stracić możliwości logowania czasu.
Zaimplementowaliśmy strategię Offline-First. Aplikacja desktopowa posiada lokalny storage (lekka baza danych SQLite lub zserializowany plik), który pełni rolę bufora:
Ciekawym aspektem jest podział logiki biznesowej między klienta (Desktop) a serwer. Zastosowaliśmy model mieszany. Thick Client (częściowo): Logika odpowiedzialna za natychmiastowe podpowiedzi (np. „ostatnio używane zadania”, „projekty przypisane do mnie”) działa lokalnie. Dzięki temu interfejs jest ultra-responsywny, nawet przy słabym łączu. Server-Side Intelligence: Bardziej zaawansowane algorytmy, takie jak model scoringu podpowiadający zadania na podstawie analizy pracy całego zespołu czy wykrywanie anomalii w czasie pracy, są liczone na backendzie. Serwer cyklicznie przesyła do klienta zaktualizowane wagi i sugestie. Pozwala to nam na iteracyjne ulepszanie algorytmów bez konieczności wymuszania aktualizacji aplikacji u wszystkich użytkowników.
Decyzja o wdrożeniu systemu w modelu On-Premises (na własnej infrastrukturze klienta) była podyktowana względami bezpieczeństwa i polityką firmy HARMO. W erze, gdzie „git push” zazwyczaj kończy się wdrożeniem na AWS czy Azure, musieliśmy zaprojektować nowoczesny proces CI/CD dla środowiska izolowanego.
Mimo że infrastruktura klienta opierała się na klasycznych maszynach wirtualnych, nie chcieliśmy rezygnować z dobrodziejstw konteneryzacji. Backend (napisany w .NET Core), baza pomocnicza oraz serwisy towarzyszące (np. Redis do cache’owania) zostały spakowane w kontenery Docker.
Na serwerach produkcyjnych klienta wykorzystaliśmy Docker Compose. Dlaczego nie Kubernetes (K8s)? Przy skali projektu (kilkudziesięciu użytkowników, kilka kontenerów) i ograniczeniach zasobowych, K8s byłby przysłowiowym strzelaniem z armaty do wróbla. Docker Compose zapewnił nam wystarczającą orkiestrację, łatwość zarządzania konfiguracją (YAML) i restart policies, przy minimalnym narzucie operacyjnym dla działu IT klienta.
Największym wyzwaniem było dostarczenie kodu z naszego repozytorium (GitLab w chmurze) na serwery klienta, które są schowane za VPN i firewallem. Zbudowaliśmy pipeline dwuetapowy:
Aktualizacja aplikacji zainstalowanej na komputerach pracowników to często koszmar administratorów. Aby tego uniknąć, zaimplementowaliśmy mechanizm Auto-Update. Aplikacja desktopowa przy starcie (oraz cyklicznie w tle) odpytuje wewnętrzny serwer (po prostym protokole HTTP lub przez zasób SMB) o plik manifestu wersji. Jeśli wykryje nowszą wersję, pobiera ją w tle. Wdrożyliśmy obsługę tzw. Breaking Changes. Jeśli zmiana w API backendu jest niekompatybilna wstecznie, aplikacja wymusza aktualizację przed pozwoleniem użytkownikowi na dalszą pracę. To drastycznie redukuje ilość błędów wynikających z niespójności wersji.
Sercem systemu jest MS SQL Server. Wybór relacyjnej bazy danych od Microsoftu był podyktowany jej doskonałą wydajnością przy złożonych zapytaniach analitycznych. Dane o czasie pracy mają strukturę hierarchiczną i silnie powiązaną (Użytkownik -> Projekt -> Zadanie -> Log Czasu -> Tagi -> Statusy rozliczeniowe). Bazy NoSQL, choć świetne do zapisu dużej ilości zdarzeń, mogłyby polec przy generowaniu skomplikowanych raportów przekrojowych (Joiny).
Tabela logów czasu – najbardziej obciążona w systemie – została zoptymalizowana pod kątem odczytu (Read-Heavy). Zastosowaliśmy:
W pierwszej części technicznego deep-dive’u udowadniamy, że w starciu ze specyficznymi wymaganiami wydajnościowymi i security, natywny WPF i strategia Offline-First deklasują podejście webowe – a już teraz zapraszamy na drugą odsłonę, w której zejdziemy jeszcze głębiej w kod i twarde dane z wdrożeni.
Jeśli chcesz dowiedzieć się więcej, zapraszamy do kontaktu z naszymi specjalistami.