Collin Flynn
Collin FlynnComputer Software Professional @ Livefront

Czym są zapachy kodu wyższego rzędu i jak z nimi walczyć

Dowiedz się, czym są zapachy kodu wyższego rzędu i sprawdź, jak sobie z nimi radzić.
26.02.20223 min
Czym są zapachy kodu wyższego rzędu i jak z nimi walczyć

Zapachy kodu to koncepcja dobrze nam wszystkim znana“Zapach” wiele nam tutaj mówi: można to porównać do otwierania lodówki po weekendzie spędzonym poza domem - od razu wiesz, że coś się popsuło. 

Do wykrywania zapachów kodu mamy kilka popularnych narzędzi (Checkstyle, SonarQube itd.). Zapachy zostały również poddane taksonomii w wielu pracach badawczych - określono również ich relatywne koszty. Fajnie jest czasem w ramach ćwiczeń nadawać im nazwy i je klasyfikować oraz zastanawiać się nad tym, które z nich są najgorsze. Najbardziej jednak interesuje mnie to, w jaki sposób one się w ogóle pojawiają. 

A pojawiają się w grupach. Chaos rodzi chaos. Różne zapachy kodu łączą się w unikalne aromaty. Nazwę je zapachami kodu wyższego rzędu, gdzie wiele rzeczy idzie nie tak jednocześnie. 

Chciałbym podzielić się z wami jednym taki zapachem wyższego rzędu - kto wie, może będzie ciąg dalszy. 

Obiekt o n-wymiarach

Jest to metoda albo konstruktor, które mają zależące od siebie parametry z prawidłowymi i nieprawidłowymi kombinacjami.

Charakteryzuje się (1) niekontrolowanymi skutkami ubocznymi (2) zbyt dużą ilością parametrów oraz (3) złożonością cyklomatyczną. 


A obiekt o n-wymiarach stara się robić o wiele za dużo. 

Nieprawidłowa kombinacja argumentów będzie na pierwszy rzut oka wyglądać dobrze, ale spowoduje skutki uboczne (1). Co więcej, próbuje wcisnąć wiele parametrów w jedno miejsce, a każdy będzie służył do czegoś innego (2). Wiele odmian danych wejściowych dotrze do różnych gałęzi kodu i ciężko będzie o nich w jakikolwiek sposób myśleć (3). 

Najgorsze obiekty n-wymiarowe mają naprawdę dużą przestrzeń możliwości, jakie tworzą: iloczyn kartezjański danych wejściowych. Każdy taki obiekt zastawia pułapki. To trochę tak, jak w tej grze, w której jesteś dentystą krokodyla. Tylko, że tutaj Ty jesteś jedynym dentystą - oraz krokodylem.

Przestań robić sobie krzywdę


Oto przykład.

Mamy model, którego użyjemy z ekranem Profile i który jest w stanie pokazywać indywidualny element User, grupę użytkowników oraz kilka kontrolek dla adminów: 

class Profile(
    /**
     * The userId if this is a user profile, or the groupId if this is a user group.
     */
    val id: String?,
    /**
     * The admin access token or null if this isn’t an admin.
     */
    val adminToken: String?,
    /**
     *  The list of this user’s group memberships by their group ids,
     *  or a list of this group’s member ids, or an empty list if this is an admin.
     */
    val groupIds: List<String>
)


Zanim staniesz się zbyt pewny siebie, muszę Ci coś powiedzieć: dokumentacja nie jest aktualna.

Obiekty n-wymiarowe pojawiają się w miejscach, w których prosta funkcja nabiera nowych odmian bez korygowania modelu danych. Czasami wiele decyzji projektowych prowadzi do interfejsu użytkownika z wieloma różnymi „smakami” i permutacje wymykają się spod kontroli. Innym razem jest to kontener UI - na przykład Fragment lub Activity w Androidzie, które ma wiele różnych trybów inicjalizacji.

Poprawka powinna być prosta i klarowna, biorąc pod uwagę przyczyny: podziel klasę na różne typy, z których każdy zawiera własne niestandardowe argumenty. A może nawet ją skomponuj?

class User : GroupMembership, Profile

interface GroupMembership {
    val groupIds: List<String>
}

interface Profile {
    val profileId: String
}

interface Administrator {
    val accessToken: String
}


Naprawianie zapachu kodu wyższego rzędu w ten sposób prowadzi do serii innych potrzebnych poprawek: stare strony wywołań będą teraz bardziej czytelne, a obsługa warstwy UI będzie miała do dyspozycji jasne ścieżki w kodzie, bez zbyt wielu rozgałęzień. Poświęcenie czasu na wykonanie dalszych poprawek w dużym stopniu wyjaśnia, jak taki zapach może utrzymywać się przez jakiś czas.

I to by było na tyle! Dziękuję za uwagę!


Oryginał tekstu w języku angielskim możesz przeczytać tutaj

<p>Loading...</p>