Cześć, przyjaciele. W związku z nadchodzącym uruchomieniem kursu , tradycyjnie dzielimy się z wami tłumaczeniem przydatnego materiału.
Oprogramowanie rozwiązuje coraz więcej codziennych zadań, jednocześnie stając się coraz bardziej złożone. Jak kiedyś powiedział Marc Andreessen, pochłania ono świat.

W rezultacie, w ciągu ostatnich kilku lat podejścia do tworzenia i dostarczania aplikacji uległy poważnym zmianom. Były to przemieszczenia tektoniczne, które doprowadziły do powstania zestawu zasad. Zasady te okazały się przydatne w formowaniu zespołów, projektowaniu, tworzeniu i dostarczaniu aplikacji końcowym użytkownikom.
Zasady można podsumować w następujący sposób: aplikacja powinna być mała, sieciowa i mieć architekturę skupioną na deweloperze. Opierając się na tych trzech zasadach, można stworzyć niezawodną, kompleksową aplikację, która może być szybko i bezpiecznie dostarczona do końcowego użytkownika oraz łatwo skalowalna i rozwijalna.

Każda z proponowanych zasad ma szereg aspektów, które omawiamy, aby pokazać, jak każda zasada przyczynia się do osiągnięcia końcowego celu, jakim jest szybkie dostarczanie niezawodnych aplikacji łatwych w utrzymaniu i użytkowaniu. Będziemy rozpatrywać zasady w porównaniu z ich przeciwieństwami, aby wyjaśnić, co to znaczy, powiedzmy, „Upewnij się, że stosujesz zasadę małości».
Mamy nadzieję, że ten artykuł zachęci cię do korzystania z proponowanych zasad budowania nowoczesnych aplikacji, które zapewnią jednolite podejście do projektowania w kontekście nieustannie rosnącego staku technologii.
Stosując te zasady, odkryjesz, że korzystasz z najnowszych trendów w tworzeniu oprogramowania, w tym podejścia do tworzenia i dostarczania aplikacji, wykorzystania kontenerów (np. ) i frameworków do orkiestracji kontenerów (np. ), wykorzystania mikroserwisów (w tym Architektury Mikroserwisów i dla aplikacji mikroserwisowych.
Czym jest nowoczesna aplikacja?
Nowoczesne aplikacje? Nowoczesny stos? Co dokładnie oznacza „nowoczesny”?
Większość deweloperów ma jedynie ogólne pojęcie o tym, z czego składa się nowoczesna aplikacja, dlatego należy precyzyjnie zdefiniować to pojęcie.
Nowoczesna aplikacja obsługuje wielu klientów, niezależnie od tego, czy jest to interfejs użytkownika w bibliotece JavaScript React, aplikacja mobilna na Androida lub iOS, czy aplikacja, która łączy się z inną za pomocą API. Nowoczesna aplikacja zakłada istnienie nieokreślonej liczby klientów, dla których dostarcza dane lub usługi.
Nowoczesna aplikacja udostępnia API do uzyskiwania żądanych danych i usług. API powinno być stabilne i niezmienne, a nie pisane z myślą o specyficznych żądaniach z konkretnego klienta. API jest dostępne przez HTTP(S) i zapewnia dostęp do całej funkcjonalności, jaką oferuje GUI lub CLI.
Dane muszą być dostępne w powszechnie akceptowalnym, kompatybilnym formacie, takim jak JSON. API dostarcza obiekty i usługi w zrozumiałej, zorganizowanej postaci; na przykład RESTful API lub GraphQL zapewniają odpowiedni interfejs.
Nowoczesne aplikacje budowane są na nowoczesnym stosie, a nowoczesny stos to taki stos, który obsługuje takie aplikacje. Taki stos umożliwia deweloperowi łatwe tworzenie aplikacji z interfejsem HTTP i wyraźnymi punktami końcowymi API. Wybrana metoda pozwoli twojej aplikacji łatwo przyjmować i wysyłać dane w formacie JSON. Innymi słowy, nowoczesny stos odpowiada elementom aplikacji Twelve-Factor. .
Popularne wersje tego typu stosu opierają się na , , , , i . Architektura mikro usługowa ucieleśnia przykład nowoczesnego stosu, wdrożonego w każdym z wymienionych języków.
Zauważ, że nie propagujemy wyłącznie podejścia mikro usługowego. Wielu z was pracuje z monolitami, które muszą ewoluować, podczas gdy inni mają do czynienia z aplikacjami SOA, które rozwijają się i przekształcają się w mikro usługi. Niektórzy podążają w kierunku stosowania aplikacji bezserwerowych (serverless), a niektórzy wprowadzają kombinacje z powyższymi. Zasady przedstawione w artykule mają zastosowanie do każdego z tych systemów, z pewnymi drobnymi modyfikacjami.
Zasady
Teraz, kiedy osiągnęliśmy wspólne zrozumienie, czym jest nowoczesna aplikacja i nowoczesny stos technologiczny, nadszedł czas, aby zanurzyć się w zasady architektury i rozwoju, które będą wam służyć w opracowywaniu, wdrażaniu i utrzymywaniu nowoczesnej aplikacji.
Jedna z zasad brzmi: „twórz małe aplikacje”, nazwijmy ją po prostu zasadą małości. Istnieją niezwykle złożone aplikacje, które składają się z wielu ruchomych komponentów. Z kolei budowanie aplikacji z małych dyskretnych komponentów upraszcza jej projektowanie, konserwację i ogólne działanie. (Zauważcie, powiedzieliśmy „upraszcza”, a nie „czyni prostym”).
Druga zasada polega na tym, że możemy zwiększyć produktywność programistów, pomagając im skupić się na funkcjach, które opracowują, zwalniając ich od trosk o infrastrukturę i CI/CD podczas realizacji. A więc, w skrócie, nasze podejście jest zorientowane na programistów.
Wreszcie, wszystko, co dotyczy waszej aplikacji, powinno być podłączone do sieci. W ciągu ostatnich 20 lat znacznie posunęliśmy się ku przyszłości sieci, ponieważ sieci stały się szybsze, a aplikacje bardziej złożone. Jak już ustaliliśmy, nowoczesna aplikacja powinna być używana przez wiele różnych klientów w sieci. Zastosowanie myślenia sieciowego w architekturze ma znaczące zalety, które dobrze współgrają z zasadą małości i koncepcją podejścia, które jest zorientowane na programistów.
Jeśli przy projektowaniu i wdrażaniu aplikacji będziecie pamiętać o tych zasadach, będziecie mieć niezaprzeczalną przewagę w rozwoju i dostarczaniu swojego produktu.
Przyjrzyjmy się tym trzynom zasadom bardziej szczegółowo.
Zasada małości
Ludzki mózg ma trudności z jednoczesnym przetwarzaniem dużej ilości informacji. W psychologii termin „obciążenie poznawcze” oznacza ogólną ilość wysiłku umysłowego potrzebnego do zapamiętania informacji. Zmniejszenie obciążenia poznawczego programistów jest priorytetowe, ponieważ w takim przypadku mogą oni skoncentrować się na rozwiązaniu problemu, zamiast utrzymywać w głowie aktualny, złożony model całej aplikacji i opracowywanych funkcji.

Aplikacje są dekomponowane z następujących powodów:
- Zmniejszenie obciążenia poznawczego dla programistów;
- Przyspieszenie i uproszczenie testowania;
- Szybkie dostarczanie zmian w aplikacji.
Istnieje kilka sposobów, aby zmniejszyć obciążenie poznawcze dla programistów, i tu z pomocą przychodzi zasada małości.
Zatem trzy sposoby na obniżenie obciążenia poznawczego:
- Zmniejszyć ramy czasowe, które muszą być brane pod uwagę podczas tworzenia nowej funkcji – im krótszy czas, tym niższe obciążenie poznawcze.
- Zmniejszyć ilość kodu, nad którym pracują jednocześnie – mniej kodu – mniejsze obciążenie.
- Uprościć proces wprowadzania inkrementalnych zmian w aplikacji.
Zmniejszenie ram czasowych w rozwijaniu
Powróćmy do czasów, gdy metodologia waterfall była standardem w procesie rozwoju, a ramy czasowe od sześciu miesięcy do dwóch lat na opracowanie lub aktualizację aplikacji były powszechną praktyką. Zazwyczaj inżynierowie najpierw czytali odpowiednie dokumenty, takie jak wymagania produktu (PRD), dokument referencyjny systemu (SRD), plan architektury i zaczynali łączyć te wszystkie rzeczy w jedną model poznawczy, według którego pisali kod. W miarę jak wymagania i architektura się zmieniały, należało włożyć wiele wysiłku, aby poinformować cały zespół o aktualizacjach modelu poznawczego. Takie podejście w najgorszym przypadku mogło po prostu sparaliżować pracę.
Największą zmianą w procesie tworzenia aplikacji było wprowadzenie metodologii agile. Jedną z kluczowych cech metodologii agile jest iteracyjne programowanie. To z kolei prowadzi do zmniejszenia obciążenia poznawczego inżynierów. Zamiast wymagać od zespołu programistycznego wdrożenia aplikacji w jednym długim cyklu, agile podejście to pozwala koncentrować się na małych fragmentach kodu, które można szybko testować i wdrażać, otrzymując jednocześnie feedback. Obciążenie poznawcze aplikacji przesunęło się z ram czasu od sześciu miesięcy do dwóch lat, biorąc pod uwagę ogromną liczbę specyfikacji, na dwutygodniowe dodanie lub zmianę funkcji, z bardziej rozmytym zrozumieniem dużej aplikacji.
Przesunięcie uwagi z masywnych aplikacji na konkretne małe funkcje, które mogą być zrealizowane w dwutygodniowym sprincie, z myśleniem o maksymalnie jednej funkcji na następny sprint, stanowi znaczną zmianę. Umożliwiło to zwiększenie produktywności rozwoju, jednocześnie zmniejszając obciążenie poznawcze, które nieustannie się zmienia.
W metodologii agile zakłada się, że końcowa aplikacja będzie nieco zmienioną wersją pierwotnej koncepcji, dlatego ostateczny punkt zakończenia rozwoju musi być zasadniczo niejednoznaczny. Jasne i wyraźne mogą być tylko wyniki każdego konkretnego sprintu.
Małe bazy kodu
Następnym krokiem w zmniejszaniu obciążenia poznawczego jest redukcja bazy kodu. Zazwyczaj nowoczesne aplikacje są masywne – solidna, korporacyjna aplikacja może składać się z tysięcy plików i setek tysięcy linii kodu. W zależności od organizacji plików, związki i zależności między kodem a plikami mogą być oczywiste lub wręcz przeciwnie. Nawet debugowanie samego wykonania kodu może stwarzać problemy, w zależności od używanych bibliotek i tego, jak dobrze narzędzia do debugowania oddzielają biblioteki/pakiety/moduły od kodu użytkownika.
Stworzenie roboczej mentalnej mapy kodu aplikacji może zająć znaczną ilość czasu i ponownie nałożyć na dewelopera dużą kognitywną ciężar. Jest to szczególnie charakterystyczne dla monolitycznych baz kodu, w których występuje wiele kodu, a interakcja między komponentami funkcjonalnymi nie jest jasno określona, a podział obiektów uwagi jest często zamazany, ponieważ nie są przestrzegane granice funkcjonalne.
Jednym z efektywnych sposobów na zmniejszenie obciążenia poznawczego inżynierów jest przejście na architekturę mikrousług. W podejściu mikrousługowym każdy serwis koncentruje się na jednym zestawie funkcji; w tym sensie serwis jest zazwyczaj jasno zdefiniowany i zrozumiały. Granice serwisu są także jasne – pamiętaj, że komunikacja z serwisem odbywa się za pośrednictwem API, więc dane generowane przez jeden serwis mogą być łatwo przekazywane do innego.
Interakcja z innymi usługami jest zazwyczaj ograniczona do kilku usług użytkowników i kilku usług dostawcy, które wykorzystują proste i czyste wywołania API, na przykład za pomocą REST. To znacznie redukuje obciążenie poznawcze inżyniera. Najtrudniejszym zadaniem pozostaje zrozumienie modelu interakcji usług i tego, jak takie rzeczy jak transakcje przebiegają w wielu usługach. Ostatecznie wykorzystanie mikroserwisów zmniejsza obciążenie poznawcze, redukując ilość kodu, wyznaczając wyraźne granice usługi i zapewniając zrozumienie relacji między użytkownikami a dostawcami.
Małe, inkrementalne zmiany
Ostatni element zasady drobnostki – to zarządzanie zmianami. Deweloperzy często mają pokusę spojrzeć na bazę kodu (nawet na swój własny, starszy kod) i stwierdzić: „To jest złe, musimy to wszystko przepisać.” Czasami to właściwa decyzja, a czasami nie. Nosi to ze sobą ciężar globalnej zmiany modelu na zespół deweloperski, co z kolei prowadzi do dużego obciążenia poznawczego. Lepiej, aby inżynierowie koncentrowali się na zmianach, które mogą wprowadzić w ciągu sprintu, aby następnie terminowo wdrożyć potrzebną funkcjonalność, nawet jeśli stopniowo. Finalny produkt powinien przypominać wstępnie zaplanowany, ale z pewnymi zmianami i testowaniem, aby odpowiadał potrzebom klienta.
Podczas przepisywania dużych fragmentów kodu czasami szybka realizacja zmian okazuje się niemożliwa, gdyż w grę wchodzą inne zależności systemu. Aby kontrolować przepływ zmian, można zastosować ukrywanie funkcji (feature hiding). W zasadzie oznacza to, że funkcjonalność istnieje w środowisku produkcyjnym, ale nie jest dostępna przez ustawienia zmiennych środowiskowych (env-var) lub jakiś inny mechanizm konfiguracyjny. Jeśli kod przeszedł wszystkie procesy kontroli jakości, może znaleźć się w produkcji w ukrytym stanie. Ta strategia działa jednak tylko wtedy, gdy funkcja ostatecznie zostanie włączona. W przeciwnym razie jedynie zaśmieci kod i zwiększy obciążenie poznawcze, z którym deweloper będzie musiał sobie poradzić, aby pracować wydajnie. Zarządzanie zmianami i zmiany inkrementalne same w sobie pomagają utrzymać obciążenie poznawcze deweloperów na dostępnym poziomie.
Inżynierowie muszą pokonywać wiele trudności nawet przy prostym wdrażaniu dodatkowej funkcjonalności. Z perspektywy kierownictwa rozsądne będzie zmniejszenie zbędnego obciążenia dla zespołu, aby mógł skupić się na kluczowych elementach funkcjonalności. Istnieją trzy rzeczy, które możesz zrobić, aby pomóc swojemu zespołowi deweloperów:
- Zastosować metodologię
agile, aby ograniczyć ramy czasowe, w których zespół musi skupić się na kluczowych funkcjach. - Zrealizować swoje aplikacje jako kilka mikroserwisów. Ograniczy to liczbę wdrażanych funkcji i wzmocni granice, które utrzymują obciążenie poznawcze podczas pracy.
- Preferuj zmiany inkrementalne wobec dużych i nieporęcznych, zmieniaj małe fragmenty kodu. Stosuj ukrywanie funkcji, aby wprowadzać zmiany, nawet jeśli nie będą one widoczne od razu po dodaniu.
Jeśli zastosujesz zasadę małości w swojej pracy, twój zespół stanie się znacznie szczęśliwszy, lepiej skupi się na realizacji niezbędnych funkcji i będzie miał większą szansę na szybkie wprowadzenie jakościowych zmian. Jednak to nie oznacza, że praca nie może stać się bardziej skomplikowana; czasami wprowadzenie nowej funkcjonalności wymaga modyfikacji kilku serwisów, a ten proces może być trudniejszy niż w przypadku architektury monolitycznej. W każdym razie, korzyści płynące z zastosowania podejścia małości są tego warte.
Koniec pierwszej części.
Wkrótce opublikujemy drugą część tłumaczenia, a teraz czekamy na wasze komentarze i zapraszamy na , który odbędzie się już dzisiaj o 20:00.
Źródło: habr.com
