Nasza strona używa cookies. Dowiedz się więcej o celu ich używania i zmianie ustawień w przeglądarce. Korzystając ze strony, wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki. Rozumiem

Jak rozwijać bibliotekę mobilną (SDK)?

Arkadiusz Pachucy Senior Software Developer
Odkryj błędy i problemy, jakie spotkały twórców biblioteki mobilnej do systemu płatności.
Jak rozwijać bibliotekę mobilną (SDK)?

Poprzedni artykuł skupił się na pytaniach, które warto sobie zadać na każdym etapie tworzenia biblioteki mobilnej oraz o kilku narzędziach, jakie wykorzystywaliśmy w procesie jej wytwarzania i utrzymywania. Zachęcam do wrócenia do niego i poczytania o tym, jak tworzyć i utrzymywać bibliotekę mobilną.

W tej części artykułu opowiem o kilku faux-pas, które tworzą wyzwania dla programistów oraz podsumuję wady i zalety istniejącego rozwiązania. To wszystko w oparciu o przykład realnej biblioteki do płatności, której opis znajdziecie w poprzedniej części.


Rozwój biblioteki jako źródło wyzwań

Każda osoba, która napisała kiedyś aplikację, zapewne użyła przynajmniej jednej biblioteki ułatwiającej jakąś czynność lub poprawiającej wygląd. Poza nazwą biblioteki bardzo ważna jest jej wersja. Rodzi to wszechogarniające pytanie - czy potrzebuję aktualnej wersji biblioteki? W końcu nie może się ona aż tak różnić od najnowszej wersji. To właśnie dlatego pojawia się wspomniana w poprzednim artykule fragmentacja. Na pytanie odnośnie różnic zawsze warto odpowiadać w ​changelogu ​- jednym pliku, który powinien zachęcić do korzystania zawsze z ostatniej wersji.

W przypadku tworzenia biblioteki, aktualna wersja wykorzystanych komponentów jest bardzo ważna. Często takie rozwiązania posiadają swoje własne zależności odnoszące się do innych bibliotek.


W czym tu jest problem?

Biblioteka może posiadać swoje zależności, natomiast aplikacja, która ją wykorzystuje, może posiadać swoje. W przypadku, kiedy posiadają one tę samą zależną bibliotekę, ale różne jej wersje, może to prowadzić do kłaczków, co jest synonimem bardzo nieciekawych problemów.

Domyślnie ​Gradle ​stara się wymusić wykorzystanie najbardziej aktualnej wersji biblioteki z wybranych przez developera. Jednak w przypadku, gdy wykorzystujemy funkcje niedostępne w nowszej wersji, rodzi się problem, którego najszybszym rozwiązaniem jest downgrade zależności w aplikacji.

Inną z możliwości jest shade jednej z wersji bibliotek, czyli zaszycie biblioteki firmy trzeciej wewnątrz istniejącego rozwiązania poprzez zmianę jej pakietu na inny. Dzięki temu, biblioteki nie „gryzą się wzajemnie. Wadą podejścia z ukryciem biblioteki jest zwiększenie jej rozmiaru i klasy biblioteki, ale pozwala to na pewną niezależność i oddzielenie aplikacji od biblioteki.


Rozwój

Ewolucja biblioteki (wprowadzanie nowych funkcjonalności) również wpływa na powstawanie nowych wersji istniejącego rozwiązania. Jeżeli jakaś biblioteka zostanie wydana, to niestety, ale nie można cofnąć jej oficjalnego releasa, więc zawsze warto zwrócić (dużą) uwagę na jakość biblioteki. Fragmentacja może przybierać różne postacie. Większość osób naturalnie kojarzy problem fragmentacji z platformą Android lub z wbudowanym kontenerem WebView, który przez długi czas otrzymywał aktualizacje tylko i wyłącznie razem z platformą. Odgrywa ona również istotną rolę podczas tworzenia bibliotek. W przypadku wydania każdej następnej wersji wprowadzamy fragmentację naszego istniejącego rozwiązania (czyli wersjonujemy SDK). Takie podejście ma zarówno wady, jak i zalety - reagujemy elastycznie na rynek, aktualizujemy zależności. Posiadamy jednak również starsze wersje biblioteki, które działają oraz taką, która nie jest częścią oficjalnego flow, ale jest dostępna z jedną konkretną metodą płatności.

Klienci w swoich aplikacjach wykorzystują różne wersje biblioteki wspomagającej płatności. Niestety, ale biblioteka nie posiada mechanizmu wymuszającego aktualizacje na naszych klientach, w związku z czym liczymy tu na ich dobrą wolę.

Z drugiej strony, wprowadzenie takiego mechanizmu mogłoby okazać się dużym błędem albo przestrzałem. Wymuszenie takiego rozwiązania na pewno podwyższyłoby koszty związane z utrzymaniem aplikacji, gdyż mogłoby się okazać, że wymuszona aktualizacja SDK wymagałaby zaktualizowania innych bibliotek i być może kodu.


Programiści też błądzą, nawet często

Jak już jesteśmy przy problemach, powiemy o kilku “naszych” wyzwaniach, z którymi nieraz się mierzyliśmy. Zawsze najprościej jest popełnić błąd ludzki. W przypadku problemu technicznego, możemy liczyć zarówno na testy, jak i kolegę obok, który poświęci chwilę na przetestowanie Twojego pomysłu. Błędy ludzkie jest o wiele trudniej poprawić, w związku z tym na nich się skupię:

  • Cicha akceptacja (słaba asertywność) jest pierwszym z problemów, jakie mogą się zdarzyć każdemu programiście. Zwłaszcza w przypadku, kiedy tworzone jest nowe rozwiązanie, a klient już chce się zintegrować z nim, żeby tylko ruszyć z developmentem aplikacji. Często programista postawiony jest pod ścianą i zgadza się udostępnić wersję developerską, która np. nie jest przetestowana lub ukończona. Zdarzały się sytuacje, w których uprzedzaliśmy potencjalnego odbiorcę o ryzykach oraz prosiliśmy o to, żeby aplikacja z taką wersją biblioteki nie była wypuszczana w świat. Jednak takie rzeczy się zdarzają, gdyż klient zna ryzyko. Niestety, ale nie ma uniwersalnego rozwiązania na tę przypadłość. Dodanie postfixu nie pomaga. Być może mieszanka większej asertywności oraz przekierowanie całej komunikacji sieciowej do serwera testowego, może coś zdziałać.
  • Planowanie releasów - wydawanie wersji w piątek również uważam za złą praktykę. W końcu co złego może stać się po wydaniu wersji biblioteki na sam koniec tygodnia, skoro została ona dogłębnie przetestowana? Biblioteka komunikuje się z backendem, a ten nie zawsze musi odpowiadać zgodnie z kontraktem, jaki został ustalony, zwłaszcza na środowisku testowym. Może się też okazać, że biblioteka po prostu nie będzie poprawnie działała u klienta, czyli proces szybkiej integracji nie zadziała i będzie potrzebne wsparcie. Jeżeli musimy wydać nową wersję biblioteki, staramy się to zrobić we czwartek, lub poniedziałek. Dzięki takiemu podejściu mamy pewność, że jeżeli coś nie będzie działało, a klienci się zintegrują, mamy przynajmniej dzień na sprawdzenie źródła problemu.
  • Przerzucanie odpowiedzialności, czyli konflikt backend-frontend. W przypadku, kiedy pracujemy nad nową funkcjonalnością, często rodzą się pytania: kto powinien wziąć za nią odpowiedzialność, czy jest to część backendowa, czy jest to na tyle proste, aby frontend sobie poradził? Jeżeli tak, to czy dodajemy funkcjonalność tylko do bibliotek mobilnych? Czy warto zrobić to raz, czy robimy osobno na każdej platformie? Jaki będzie koszt utrzymania oraz aktualizacji? Konflikt, gdzie umieścić daną funkcjonalność zawsze będzie. Wyzwaniem jest przekonanie drugiej strony, dlaczego właśnie po jej stronie powinna się ona znaleźć.
  • Wspieranie starych wersji systemu Android - będziemy to wspierać, bo nie znaleźliśmy powodów żeby tego nie robić. Nie raz takie podejście wprowadziło utrudnienia: a to obejście dla platformy Gingerbread, a to keystore został wprowadzony dopiero od wersji X. A my chcemy wspierać kilka wersji przed jego oficjalnym wprowadzeniem. TLS 1.2 nie miał oficjalnego wsparcia dla Androida < 4.3, a mimo to, część klientów chciała wsparcie Androida 4.1. Ten temat również odnosi się do asertywności - czasem warto powiedzieć nie i podeprzeć to solidną liczbą argumentów z dziedziny bezpieczeństwa lub po prostu podeprzeć to liczbą potencjalnych użytkowników końcowych, którzy posiadają urządzenia z daną wersją systemu Android.


Ciekawostki związane z utrzymaniem

W przypadku rozwoju bibliotek, bardzo istotną rolę pełniły firmy, które integrowały się z tym rozwiązaniem. W związku z tym nie raz przydarzyło nam się C​CDD -​ customer, client driven development, gdzie wymagania były ustalane ad hoc. Podczas tego typu prac mieliśmy bardzo duży nacisk, czy dana funkcjonalność wpłynie na innych klientów, którzy integrują się z biblioteką.

W cyklu artykułów wspominałem już o fragmentacjach systemu operacyjnego oraz biblioteki jako produktu. Kolejnym krokiem jest f​ragmentacja przeglądarek​. Programiści, którzy integrują się z komponentem webowym w aplikacji, mają świadomość, że przeglądarka wbudowana w aplikację może zachowywać się różnie i zależy to zarówno od wersji systemu Android, jak i od typu silnika, jaki znajduje się na urządzeniu. Od KitKata poczyniono naprawdę wiele, aby zniwelować fragmentację na Androidzie - wymieniono silnik oraz wydzielono WebView jako osobną aplikację. Dzięki takiemu zagraniu przeglądarka uniezależniła się od systemu operacyjnego.

Najczęstszą formą płatności mobilnych w Polsce jest płatność za pomocą przelewu bankowego. Banki kładą bardzo duży nacisk na bezpieczeństwo webowe, w związku z tym bardzo często podnoszą minimalną wersję silnika przeglądarki. Jednak biorąc pod uwagę ostatnie dwa miesiące, to płatności Google Pay oraz Apple Pay przypadły do gustu naszym rodakom.

IntelliJ Idea oraz Maven nadają się do tworzenia zarówno aplikacji Androidowych, jak i biblioteki, jednak te rozwiązania stają się anachronizmami. Ich następcy: Android Studio oraz Gradle, są intensywnie rozwijane, a community jest w stanie pomóc w większości problemów.

Spora grupa klientów prosi nas o wspieranie starszych wersji Androida 4 - 4.3 ze względu na dużą pulę klientów końcowych, którzy posiadają starsze urządzenia. Niestety, ze względów bezpieczeństwa nie wszystkie funkcjonalności działają dla starszych wersji systemów Android.


Podsumowanie cech biblioteki

Wszystkie wybory, jakie dokonaliśmy w trakcie projektowania i utrzymywania naszej biblioteki, składają się na zestaw zalet i wad.

Zalety:

  • Marka - podczas procesu płatności klient przechodzi do widoków serwowanych przez szanowanego dostarczyciela rozwiązań płatniczych, przez co ludzie chętniej zakupią produkt za pomocą mobilnego rozwiązania
  • Dojrzałość - produkt, który został już wdrożony oraz wykorzystywany przez lata przez różnych klientów
  • Prosta integracja - dodanie biblioteki, wywołanie kilku metod i programista aplikacji mobilnych zintegrował się z rozwiązaniem
  • Rzeczowa dokumentacja
  • Jeden konkretny flow (aplikacja uruchamia prosty przepływ biblioteki pozwalający na płatność) - mniejsza możliwość dokonania błędów podczas procesu integracji
  • Dobrze przetestowana
  • Użytkownik wie, kto wspiera płatności mobilne


Wady:

  • Różne repozytoria - te dedykowane dla klientów zewnętrznych oraz wewnętrznych, znajdują się w różnych miejscach oraz wykorzystują inne rozwiązania, przez co wzrasta ich koszt utrzymania
  • Trzymanie się starszych technologicznie rozwiązań, np. Mavena zamiast Gradle
  • Jeden konkretny flow (nie ma możliwości zmiany styli, konfigurowania przepływu, etc.) - klient musi dostosować się do flow
  • Coraz trudniejszy rozwój oraz wsparcie
  • Kilka wersji biblioteki dla różnych klientów - koszty wsparcia rosną, konfiguracja CD, sprawdzanie ręczne, czy biblioteka poprawnie działa w “aplikacjach”, poprawa bugów na różnych wersjach bibliotek dla różnych klientów
  • Brak mechanizmu wymuszenia nowej wersji biblioteki na osobach wykorzystujących ją - dzięki takiemu mechanizmowi moglibyśmy zapewnić najnowsze funkcjonalności dla klientów oraz stabilność rozwiązania


Podsumowanie

Pierwsze artykuły wprowadziły do tematyki ogólnej, związanej z bibliotekami mobilnymi. Poruszyłem temat wykorzystywanych narzędzi i technologii. Odpowiedzi na postawione tu pytania są dobrym wstępem do treści, o których będę mówił w kolejnych tekstach.

Zobacz więcej na Bulldogjob

Masz coś do powiedzenia?

Podziel się tym z 80 tysiącami naszych czytelników

Dowiedz się więcej
Rocket dog