Jakie są najlepsze zasady inżynierii oprogramowania?

Zasady tworzenia oprogramowania to zestaw konkretnych zasad i zaleceń, których inżynierowie powinni przestrzegać podczas wdrażania programu, jeśli chcą napisać piękny, przejrzysty i łatwy w utrzymaniu kod. Nie ma magicznej różdżki, która mogłaby zmienić misz-masz zmiennych, klas i funkcji w doskonały kod, ale istnieje kilka wskazówek i podpowiedzi, które mogą pomóc inżynierowi określić, czy postępuje właściwie.

Przyjrzyjrzyjmy się tym podstawowym zaleceniom. Niektóre z poniższych zasad są specyficzne dla Pythona, ale większość z nich nie jest.

Mierz dwa razy i tnij raz

Myślę, że to najważniejsza zasada ze wszystkich. Jeśli nauczysz się tylko jednej zasady z tego postu, powinna to być ta jedna. My, deweloperzy/architekci/menedżerowie zmagamy się z brakiem uwagi, głupimi błędami i błędnymi wydrukami, problemami osobistymi, złym samopoczuciem i zimną kawą. Nic z tych rzeczy nie jest istotne – problem musi zostać rozwiązany. Dla mnie, jako inżyniera, zasada ta oznacza wybór właściwego rozwiązania problemu, wybór właściwego podejścia do problemu, wybór właściwych narzędzi do rozwiązania problemu, zaufanie do zbudowanego rozwiązania. Wybór w tym przypadku oznacza przemyślenie sprawy, znalezienie niezbędnych zasobów, skompletowanie odpowiedniego zespołu, przemyślenie projektu, przemyślenie podejścia, wyznaczenie zadań, kontrolowanie rezultatu i ponoszenie za to odpowiedzialności. To jest „Engineering as is”. Myślę, że sam nie jestem gotowy, aby opisać to poprawnymi słowami.

Don’t Repeat Yourself (DRY)

Jest to dość prosta, ale bardzo użyteczna zasada, która mówi, że powtarzanie tej samej rzeczy w różnych miejscach jest złym pomysłem. Przede wszystkim jest to związane z koniecznością dalszego wspierania i modyfikowania kodu. Jeśli jakiś fragment kodu jest powielony w kilku miejscach wewnątrz programu, istnieje duże prawdopodobieństwo wystąpienia dwóch katastrofalnych sytuacji:

  1. Przy wprowadzaniu nawet niewielkich zmian w kodzie źródłowym, trzeba zmienić ten sam kod w kilku miejscach. Będzie to wymagało dodatkowego czasu, wysiłku i uwagi (często nie jest to łatwe).
  2. Pierwszy punkt następuje po drugim. Ty lub inny programista z Twojego zespołu może przypadkowo przegapić jedną ze zmian (może się to zdarzyć po prostu przez łączenie gałęzi w vcs) i stanąć w obliczu kolejnych błędów w aplikacji. Te błędy mogą być dla Ciebie frustrujące, ponieważ słyszałeś, że taki błąd został już naprawiony.

W związku z tym, istnieje zalecenie – jeśli jakiś kod znajduje się na listingu więcej niż dwa razy, powinien być umieszczony w osobny sposób. Jest to zalecenie ogólne. W rzeczywistości należy pomyśleć o stworzeniu osobnej metody, nawet jeśli napotkamy powtórzenie po raz drugi.

Occam’s Razor

Jest to bardzo powszechna idea, która przyszła do programowania z filozofii. Zasada ta wzięła swoją nazwę od angielskiego mnicha Williama z Oakham. Zasada ta mówi: „Jednostki nie powinny być mnożone bez potrzeby”. W inżynierii zasada ta jest interpretowana w następujący sposób: nie ma potrzeby tworzenia niepotrzebnych bytów bez potrzeby. Dlatego zawsze warto najpierw zastanowić się nad korzyściami płynącymi z dodania kolejnej metody/klasy/narzędzia/procesu, itp. W końcu, jeśli dodasz kolejną metodę/klasę/narzędzie/proces itp. i nie uzyskasz żadnych korzyści poza zwiększoną złożonością, to jaki jest tego sens?

Keep It Simple Stupid (KISS)

Keep It Simple Stupid

Jest to zasada bardzo podobna do powyższej, ale ma nieco inne znaczenie. Zasada ta mówi, że kod musi być tak prosty jak to tylko możliwe, bez skomplikowanych struktur, w przeciwnym razie skomplikuje to debugowanie i utrzymanie kodu. Poza tym, innemu programiście trudniej będzie zrozumieć logikę kodu, co z kolei będzie wymagało dodatkowego czasu i wysiłku. Dlatego zawsze powinieneś starać się używać prostych konstrukcji, które w jak największym stopniu rozwiązują problem, bez licznych rozgałęzień, głębokiego zagnieżdżania i nadmiernie przeciążonych struktur klas. Robiąc to, ułatwisz życie sobie i swoim współpracownikom, ponieważ złożoność generuje błędy. Pamiętaj, co powiedział Peter Hintiens: „Prostota jest zawsze lepsza niż funkcjonalność”.

You Aren’t Gonna Need It (YAGNI)

Problem, na który cierpi wielu programistów. Chęć zaimplementowania na raz wszystkich niezbędnych (a czasem nawet niepotrzebnych) funkcjonalności już na samym początku projektu. To znaczy, gdy programista od samego początku dodaje do klasy wszystkie możliwe metody i implementuje je, a w przyszłości może nawet nigdy ich nie użyć. Tak więc, zgodnie z tym zaleceniem, najpierw zaimplementuj tylko to, czego potrzebujesz, a później, jeśli to konieczne, rozszerzaj funkcjonalność. W ten sposób zaoszczędzisz wysiłek, czas i nerwy na debugowaniu kodu, który tak naprawdę nie jest potrzebny.

Big Design Up Front

Measure twice and cut once

Przed rozpoczęciem rozwijania funkcjonalności, powinieneś najpierw przemyśleć architekturę aplikacji i zaprojektować cały system do wystarczająco małych szczegółów, a dopiero potem przystąpić do implementacji zgodnie z wcześniej ustalonym planem. Zasada ma prawo istnieć, ale ostatnio pojawia się sporo krytyki pod jej adresem. Wiąże się ona przede wszystkim z dezaktualizacją planu w trakcie projektowania i opracowywania. W związku z tym konieczne jest jeszcze wprowadzanie kolejnych zmian. Ale ma to również niezaprzeczalne zalety, przy poprawnym projektowaniu można znacznie obniżyć koszty dalszego debugowania i poprawiania błędów. Poza tym, takie systemy informatyczne z reguły są bardziej lakoniczne i poprawne architektonicznie.

Avoid Premature Optimization

„Przedwczesna optymalizacja jest korzeniem wszelkiego zła (a przynajmniej jego większości) w programowaniu” – Donald Knuth

Optymalizacja jest bardzo poprawnym i koniecznym procesem do przyspieszenia programu, jak również do zmniejszenia zużycia zasobów systemowych. Jednak wszystko ma swój czas. Jeśli optymalizacja jest przeprowadzana na wczesnym etapie rozwoju programu, może przynieść więcej szkody niż pożytku. Przede wszystkim jest to związane z faktem, że rozwój zoptymalizowanego kodu wymaga więcej czasu i wysiłku na rozwój i wsparcie. W tym przypadku dość często trzeba na początku sprawdzić poprawność wybranego podejścia do rozwoju. Dlatego na początku bardziej opłaca się zastosować proste, ale nie najbardziej optymalne podejście. A później, po oszacowaniu, jak bardzo to podejście spowalnia pracę aplikacji, przejść na szybszy lub mniej zasobożerny algorytm. Dodatkowo, tak długo jak będziesz początkowo implementował najbardziej optymalny algorytm, wymagania mogą się zmienić, a kod pójdzie do śmieci. Nie ma więc potrzeby tracić czasu na przedwczesną optymalizację.

Principle Of Least Astonishment

Zasada ta oznacza, że Twój kod powinien być intuicyjny i oczywisty, a nie zaskakiwać innego dewelopera podczas przeglądania kodu. Na przykład, jeśli metoda nazywa się „robienie ciasteczek”, ale w wyniku otrzymujemy ziemniaki, to taki kod jest zły (oczywiście). Poza tym, powinieneś starać się unikać efektów ubocznych i dokumentować je, jeśli nie możesz ich uniknąć.

S.O.L.I.D.

SOLID

„SOLID” jest właściwie grupą zasad projektowania zorientowanego obiektowo. Każda litera w „SOLID” reprezentuje jedną z zasad, którymi są:

  • Pojedyncza odpowiedzialność stwierdza, że każdy moduł lub klasa powinny być odpowiedzialne za pojedynczą część funkcjonalności dostarczanej przez oprogramowanie, a odpowiedzialność ta powinna być całkowicie hermetyzowana przez klasę;
  • Otwarte-zamknięte stwierdza, że encje oprogramowania (klasy, moduły, funkcje, itp.) powinny być otwarte na rozszerzenie, ale zamknięte na modyfikację;
  • Substytucja Liskova stwierdza, że klasa dziedziczona powinna uzupełniać, a nie zastępować zachowanie klasy bazowej;
  • Segregacja interfejsów stwierdza, że żaden klient nie powinien być zmuszony do zależności od metod, których nie używa;
  • Inwersja zależności mówi, że programista powinien pracować na poziomie interfejsu, a nie na poziomie implementacji.

Po zastosowaniu razem, zasady te pomagają programiście tworzyć kod, który jest łatwy do utrzymania i rozszerzania w czasie.

Prawo Demeter

Podstawową ideą tej zasady jest podział obszarów odpowiedzialności pomiędzy klasy i hermetyzacja logiki wewnątrz klasy, metody lub struktury. Na podstawie tej zasady można wyróżnić kilka zaleceń:

  1. Klasy lub encje powinny być niezależne
  2. Powinno się starać ograniczyć liczbę połączeń między różnymi klasami (tzw. sprzężenie).
  3. Klasy powiązane muszą znajdować się w jednym module/pakiecie/katalogu (nazywane również spójnością.

Przestrzegając tych zasad, aplikacja staje się bardziej elastyczna, zrozumiała i łatwa w utrzymaniu.

Podsumowanie

Koledzy programiści bądźmy inżynierami! Myślmy o projektowaniu i budujmy solidne i dobrze zaimplementowane systemy, a nie hodujmy organiczne potworki. Wymienione zasady są silnie skorelowane i połączone w swojej istocie. Oczywiście nie ja je stworzyłem, ale małe przypomnienie nie zaszkodzi, przynajmniej moja pamięć na pewno nie jest doskonała.

Polecane książki

  • Clean Code Roberta C. Martina
  • Clean Architecture Roberta C. Martina

.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.