Czym jest Hardcode i czy zawsze jest to zła praktyka?

Hardcode to ciekawy temat w programowaniu, który jest bardzo często niedopowiedziany. Ogólnie dostępne materiały zwykle powtarzają, że jest to okropna praktyka i błąd. Nie jest to do końca prawda, dlatego stwierdziłem, że warto napisać co o tym myślę.

Przede wszystkim, czym jest “hardcode”?

Hardcode to wartość zapisana na sztywno w kodzie programu. Na przykład:

String name = "John";
...

Zwykle wartości w programie, takie jak imię przetwarzanej osoby są pobierane z bazy danych, od użytkownika lub z innego interfejsu. Wartość tego typu nigdy nie powinna być zapisana “na sztywno” w kodzie.

Jest to typowy przykład “złego hardcodowania”. Kod tego typu jest zwykle niedopatrzeniem lub dowodem na kompletny brak umiejętności programistycznych.

Ale czy każdy kod zawierający sztywne wartości jest niepoprawny? Nie jest to takie proste.

Co uznajemy za hardcode, a co nie?

W teorii każda wartość, która zapisana jest twardo w kodzie może być nazwana hardcodem. Jednak umieszczanie tego typu stałych jest czasami nie tylko poprawne, ale też często niezbędne.

Rozważmy przypadek aplikacji, która posiada kilka ról dla użytkowników. Na przykład w programie można być:

  • Adminem
  • Moderatorem
  • Użytkownikiem

Żeby zaprogramować tego typu mechanizm musimy gdzieś zdefiniować role. Najlepiej jest to zahardocodować w kodzie. Zgodnie z najlepszymi praktykami języka Java, użyjmy do tego celi typu enum:

public enum ApplicationRole {
    ADMIN, MODERATOR, USER
}

Czy jest to hardcode? Moim zdaniem jest to “dobre hardcodowanie”. Zwykle nikt nie nazwie tego hardcodem, gdyż powyższy kod jest uzasadniony. Termin niesie ze sobą wiele negatywnych konotacji, dlatego w żargonie taki kod nie został by oczerniony w taki sposób.

Pozostaje pytanie – kiedy hardcodwanie jest na miejscu, a kiedy nie? Żeby odpowiedzieć w pełni na to pytanie najpierw musimy omówić bardziej fundamentalny temat:

Dlaczego tak naprawdę hardcode jest złą praktyką?

W wielkim skrócie:

Hardcode jest błędem wtedy kiedy wartość, która powinna być zmienną jest na stałe wpisana w kod.

Różne dane w programie posiadają różną “zmienność”. Od właśnie tej cechy zależy, czy dany hardcode jest uzasadniony. Warto jest rozgrzebać ten temat dalej.

Poziomy zmienności danych.

Dane mogą zmieniać się z różną częstotliwością. Są trzy główne poziomy tej zmienności:

Typowe zmiennie w wywoływanej operacji.

Są to zwykle dane w metodzie, które zmieniają się w każdym wywołaniu funkcji. Np. w zapisaniu nowego klienta jego imię może być za każdym razem inne. W tym wypadku hardcode imienia jest tragicznym błędem. Tego typu wartości są zwykle w bazie danych lub są pobierane z jakiegoś interfejsu.

Wartości konfiguracyjne – zmienne w zależności od środowiska.

Idealnym przykładem tego typu danych jest np. adres do bazy danych. Jest on wartością, która nie zmienia się w trakcie uruchomienia aplikacji. Jednak hardcodowanie tego typu danch jest dalej błędem. Adres może się zmieniać w zależności od środowiska, dlatego najlepszym miejscem dla niego jest plik konfiguracyjny. Dzięki temu nie musimy zmieniać kodu dla każdego środowiska, co było by okropnym problemem.

Wartości globalnie stałe i rzadko lub w ogóle nie zmieniane.

Tego typu wartość nie dość, że nie zmieniają się w trakcie działania aplikacji, ale też są identyczne dla każdego środowiska. Zapisywanie tego typu danych w konfiguracji lub bazie danych to jakieś nieporozumienie. Nie potrzebujemy tutaj żadnej zmienności, więc każde “dynamiczne” rozwiązanie doda tylko niepotrzebne skomplikowanie. W takim wypadku sztywne zapisanie wartości w kodzie jest uzasadnione. Przykładem tego typu danych mogą być wspomniane wcześniej role w aplikacji.

Identyfikując odpowiedni poziom “zmienności” możemy od razu wiedzieć, czy dany hardcode jest na miejscu.

A co z testami?

Testy, ale także kod eksperymentalny nie będący kodem produkcyjnym są wyjątkami od powyższych reguł.

Testy powinny zawierać proste i łatwe do analizy dane testowe. Zwykle tworzenie dynamicznych danych do testów jest złą praktyką i może doprowadzić do ich zbytniego skomplikowania.

Kod eksperymentalny lub prezentujący jakieś nowe rozwiązanie też może zawierać dowolną ilość hardcodów. Jeśli jedyne, co chcemy osiągnąć to POC, to wprowadzanie zmienności danych jedynie utrudni nasze zadanie. Oby tylko nie zapomnieć o ich usunięciu po wprowadzeniu rozwiązania do produkcyjnego kodu 🙂

Tips and trick odnośnie hardcode.

  • w przypadku zauważenia hardcode przy code review, nie miej dla niego litości, taki kod nie może być przepuszczany
  • kiedy hardcode jest uzasadniony staraj się używać to tego specjalistycznych mechanizmów, taki jak typ “enum” w java
  • jeśli uzasadniony hardcode powtarza się wielokrotnie wyciągnij go do stałej finalnej w klasie, zwiększa to łatwość ewentualnego refactoringu tego hardcodu w przyszłości
  • zawsze przed zrobieniem hardcode zatrzymaj się i pomyśl, jaka jest zmienność rozważanych danych, lepiej pomyśleć wcześniej niż zrobić głupi błąd
  • dane które są na razie stałymi, ale w planach rozwoju systemu będą zmienne powinny nie być hardcodowane, dzięki temu ogólnie zaoszczędzimy sobie pracy
  • duża ilość hardcode zwykle oznacza tragiczną jakość kodu i może być wykorzystywana jako jeden ze wskaźników jakości
  • są rzeczy, które nigdy nie powinno się hardcodować – takie jak: wszystkie hasła i tokeny, adresy zewnętrznych serwisów i systemów, wszystko co jest związane z konkretnym środowiskiem

Leave A Comment