Jak nazywać zmienne?

Rozpoczynając naukę programowania nie skupiałem większej uwagi nazewnictwu zmiennych. Później, korzystając z różnych bibliotek, modułów czy też frameworków zwróciłem większą uwagę na konwencje nazewnictwa. To niemniej jednak jest tylko jedna z wielu kwestii, o których należy pamiętać. Jak zatem nazywać zmienne?

Raz napisany kod czyta się wiele razy. Powinno się więc zadbać o to, by jego czytanie było możliwie proste, szybkie i przyjemne. Nazwy symboli (zmiennych, klas, metod, itp.) odgrywają tu ważną rolę. Nie musisz zgadzać się ze wszystkimi wskazówkami, które są zamieszczone poniżej, niemniej jednak warto mieć je na uwadze podczas wymyślania nazw i stosować się choć do części z nich.

Twórz opisowe nazwy

Ile razy zdarzyło Ci się, że gdy czytałeś swój kod po kilku tygodniach, nie mogłeś sobie przypomnieć, co oznaczała dana zmienna? Mi to się przytrafiło nie raz i nie dwa. Nazwy zmiennych powinny zawierać tyle informacji, by móc dokładnie określić do czego jest ona wykorzystywana. Cytując Roberta Martina:

The name of a variable, function, or class, should answer all the big questions. It should tell you why it exists, what it does, and how it is used. If a name requires a comment, then the name does not reveal its intent.
Clean Code – A Handbook of Agile Software Craftsmanship

Powyżej zacytowany tekst zawiera w sobie sporo wskazówek, które zostały opisane poniżej.

Przedstaw swoje intencje

Co mówi nazwa d gdy zobaczy się ją w kodzie? Prawdę powiedziawszy: nic. Owszem, jest komentarz, ale są co najmniej 3 powody, dla których nie powinno się tak robić:

  1. Znalezienie komentarza wymaga czasu. Prawdą jest, że wiele IDE wyświetla nam ten komentarz, ale pamiętaj, że kod nie czyta się tylko w IDE! Gdy mamy kod na GitHubie albo ktoś dokonuje Code Review na Gerricie, to czy on będzie widział ten komentarz od razu obok nazwy zmiennej? Nie!
  2. Niektórzy powiedzą, że wpisywanie takiej zmiennej jest szybsze, więc skraca czas programowania. Nieprawda. Nie zgadzam się z tym stwierdzeniem. Po pierwsze – wpisuje się tylko kilka pierwszych znaków, a resztę nazwy podpowiada nam IDE. Po drugie – co da nam kilka sekund zaoszczędzonych na wpisywaniu nazwy zmiennej? Później, gdy będzie się (wielokrotnie!) czytać ten kod, będzie potrzebne dużo więcej czasu, by sobie przypomnieć, co dana zmienna oznaczała.
  3. Komentarze kłamią. Gdy edytuje się kod, nie wszyscy patrzą na komentarze i dbają o ich aktualność. Niekoniecznie ty będziesz modyfikować swój kod, więc warto zadbać o jego aktualność – użyj dobrej nazwy zmiennej zamiast komentarza!

Pamiętaj – kod czyta się dużo częściej, aniżeli się go pisze. Warto zatem zadbać o jego jakość. Poprawiony przykład:

Dużo lepiej, prawda?

Nazwa powinna być opisowa, ale krótka

Priorytetem powinna być opisowość zmiennej. Gdy będzie się miało już kilku dobrych kandydatów, powinno się wybrać jednego z krótszych.
Zły przykład: howLongDoesItTakeToOpenTheDoor
Dobry przykład: timeToOpenTheDoor

Unikaj dezinformacji

Nazwa powinna być na tyle dokładna, by była jednoznaczna. Warto zatem unikać wieloznacznych skrótów, jak np. hp w znaczeniu hypotenuse (ang. przeciwprostokątna), bowiem wielu osobom może się skojarzyć z hit points.

Twórz wyraźne różnice

Gdy ktoś zapomni o dopisaniu const przy wskaźniku na źródło – to jak rozróżnisz źródło od celu kopiowania?

Nazwy powinny być wymawialne

Taką nazwę jest trudno przeczytać, ale prawdopodobnie starałeś się to zrobić i zrozumieć co ta nazwa oznacza – to jest naturalne. Nawet gdy myśli się o takich zmiennych, to zbyt wiele naszego czasu i uwagi zabierają ich nazwy. A co w sytuacji, gdy chce się spytać o coś kolegi z zespołu i próbuje się wymówić tę nazwę? Jest problem. Po co więc go tworzyć nadając takie nazwy zmiennym?

Unikaj notacji węgierskiej

Dobra nazwa zmiennej sama sugeruje, jakiego jest typu, a w razie niepewności zawsze można to szybko sprawdzić przy pomocy IDE. Zmienne będące parametrem funkcji tudzież składnikiem (zmienną instancyjną) danej klasy są wyróżnianie własnymi kolorami we współczesnych środowiskach. Chcąc skorzystać z podpowiadania nazwy zmiennej nie ma sensu wpisywać zbędnych prefiksów i kilka kolejnych znaków, by uniknąć długich list z kandydatami (np. po wpisaniu samego m_). Po co sobie utrudniać pracę? Dla jakich korzyści warto stosować notację węgierską?

Bądź konsekwentny

  • Jedna konwencja nazewnictwa – jeśli pisząc w Pythonie w pewnym miejscu dla nazw klasy zastosujesz PascalCase‚a, dla zmiennych lokalnych camelCase‚a, a dla metod snake_case‚a – zachowaj tę konwencję w całym projekcie.
  • Niech jedno słowo oznacza jedno abstrakcyjne pojęcie – dzięki temu można szybciej i sprawniej korzystać z nazw, bowiem każda jest wtedy jednoznaczna. Przykładowo:

  • Nazwy z domeny aplikacji – w różnych domenach różne koncepty mogą mieć bardzo konkretne i odmienne znaczenia. Przykładowo jeśli klient w naszym sklepie zastanawia się nad potwierdzeniem swojego zamówienia lub jego dalszą modyfikacją, niewłaściwym byłoby nazwanie tego zamówienia jako order. Rozróżnij je od potwierdzonego zamówienia nadając mu nazwę nonApprovedOrder.

Nie używaj negatywnej logiki

Dobrze: isEnabled
Źle: isNotEnabled

Czy miałeś kiedyś tak, by dogłębniej analizować wyrażenie logiczne z powodu wielokrotnego zaprzeczenia w nim? Zawsze jest nam łatwiej zrozumieć wyrażenie zapisane w „pozytywnym języku”.

Nazwy klas i obiektów

  • Nazwy klas i obiektów powinny być rzeczownikami lub wyrażeniami rzeczownikowymi, np. Customer, WikiPage, bowiem to one są podmiotami, na których wykonywane są akcje lub które to wykonują akcje.
  • W ich nazywaniu powinno się unikać takich słów jak Manager, Processor, Data czy Info, bowiem już ich nazwa sama wskazuje, iż ta klasa wykonywałaby wiele różnych zadań, co kłóci się z zasadą pojedynczej odpowiedzialności.

Nazwy metod

  • Metoda wykonuje konkretną czynność, stąd jej nazwa powinna być czasownikiem albo wyrażeniem czasownikowym, np. postPayment, displayImage.
  • Nazwy akcesorów, mutatorów oraz predykatów powinny być tworzone w oparciu o własność, do której się odnoszą, oraz rozpoczynać od get, set lub is.
  • Masz przeciążony konstruktor? Rozważ jego zastąpienie fabrykami:

Dodaj znaczący kontekst

Widząc w klasie – obsługującej np. wystawienie faktury – zmienne firstName, lastName, street, houseNumber, flatNumber, state i zipcode możemy łatwo się domyślić, że te zmienne, jako całość, tworzą adres. Jednak co w przypadku, gdy w danym fragmencie kodu widzimy odwołanie się tylko do jednego albo dwóch z tych pól? Wtedy to już nie jest takie oczywiste, że wchodzą one w skład adresu. W takim przypadku utwórz osobną klasę Address, w której zawrzesz te pola, dzięki czemu przy późniejszym odwołaniu się do nawet pojedynczej zmiennej, będziesz musiał napisać customerAddress.street. W takim kontekście nie ma najmniejszego problemu ze zrozumieniem przeznaczenia każdego pola klasy z osobna.

Unikaj nadmiarowego kontekstu

Nie dodawaj do nazw informacji oczywistych. Jeśli pracujesz nad projektem o nazwie Super Awesome Music Player, nie ma sensu dopisywać do każdej nazwy klasy SuperAwesomeMusicPlayer lub nawet krótkiego SAMP jako przedrostek.

Złota zasada #1 – poświęć kilka minut na wymyślenie nazwy

Jeśli korzystasz z nazw, które wymyślasz bez większego zastanowienia podczas pisania kod, ponieważ potrzebujesz nowej zmiennej, klasy czy metody – prawdopodobnie dobierasz złe nazwy. Poświęć kilka minut na wymyślenie dobrej nazwy. Nawet, jeśli nie będziesz się stosować do wcześniejszych zasad, to stosując tę jedną z dużym prawdopodobieństwem dobierzesz całkiem dobre nazwy.

Złota zasada #2 – nie bój się refaktoryzacji

Jeśli w trakcie pisania kodu wymyślisz lepszą nazwę dla już istniejącej klasy, metody lub zmiennej – zmień ją. Współczesne IDE wraz z pluginami dobrze sobie radzą z niektórymi aspektami refaktoryzacji, więc zmiana nazwy jest czynnością prostą, a dzięki niej kod zyskuje na jakości i czytelności.

A Ty czym się kierujesz podczas tworzenia nazw? Daj znać w komentarzach! Zachęcam również do subskrypcji bloga.

5 myśli nt. „Jak nazywać zmienne?

  1. Fajnie się czyta Twojego bloga, zwłaszcza opisy obozów i konkursów. Tutaj widzę mocną inspirację „Czystym kodem”, super książka.

    P.S. Też byłem na 2 etapie XX OIa w Krakowie 😉

    • Dziękuję, miło mi to słyszeć! (albo raczej czytać) 🙂
      Może kiedyś się spotkamy 😀 (jakby co to pisz na maila albo gdzieś indziej – kontakt do mnie znajdziesz na blogu)

  2. To ja napiszę o paru wyjątkach od powyższych zasad. Bo choć w niektórych stylach programowania albo sytuacjach powyższe reguły są jak najbardziej sensowne, to w innych się nie sprawdzają.

    1. Jednym ze stylów programowania jest tworzenie bardzo licznych, bardzo krótkich funkcji. W tym przypadku zalecane jest używanie bardzo krótkich nazw zmiennych – w tym stylu programowania znaczenie zmiennej i jej zastosowanie mamy odczytywać z kontekstu, a nie z nazwy zmiennej. Przykład:

    float brightness(float r, float g, float b) = 0.299*r + 0.587*g + 0.114*b

    Nazwanie zmiennych red, green i blue niepotrzebnie rozciągnęłoby formułę, czyniąc ją mniej czytelną.

    2. W programach mocno osadzonych w matematyce, fizyce lub innych dziedzinach, gdzie nawet złożone pojęcia są często oznaczane pojedynczym znakiem (np. grecką literą) zalecane może być stosowanie się do konwencji z danej dziedziny. Przykładowo funkcja transpozycji macierzy może się nazywać po prostu T. Może dla osoby nieobeznanej z danym kodem i z daną dziedziną tak nazwana funkcja będzie mało czytelna, ale dla osoby pracującej od dawna w tej dziedzinie czytanie kodu stosującego się do znanych jej konwencji będzie dużo szybsze i wygodniejsze. Fakt, że w różnych kontekstach ta litera T może znaczyć coś innego… ale tak też jest w podręcznikach matematyki i matematyk do tego przyzwyczajony nie ma problemów z błyskawicznym określaniem z kontekstu o które znaczenie chodzi.

    3. Co do klas takich jak np. Manager… nie zgodzę się, że ta nazwa sugeruje iż klasa wykonuje wiele zadań. Wykonuje jedno zadanie – zarządza.

    4. Co do getterów i setterów… bywają języki programowania, które zalecają nie używać przedrostków get i set. Dzięki temu można podmienić odwołanie do zmiennej na wywołanie funkcji bez modyfikowania kodu który z tej zmiennej korzystał – zmianę wprowadza się wyłącznie w klasie gdzie zmienna była zdefiniowana. Przykład:

    main() {
    println(angle.radians)
    }

    class Angle {
    float radians
    // lub
    float radians() = degrees * degreesToRadians
    }

    Jeśli język pozwala na wywołanie funkcji bezargumentowych bez użycia nawiasów (czyli angle.radians może być wywołaniem funkcji radians(), albo odwołaniem do zmiennej radians) to możemy podmieniać zmienne i funkcje bez modyfikowania kodu po stronie użytkownika.

  3. Świetny wpis, chociaż z tym zmienianiem nazw już nazw klas na zaawansowanym etapie jakiegoś większego projektu może być różnie. PS. Pamiętam, że nas na studiach strasznie katowali za nieregularne wcięcia w kodzie – bardziej czepiali się tego niż składni. Pozdrawiam! 😉

    • Dziękuję!
      Co do zmiany nazwy klasy – ogólnie jest tak, że im później coś poprawiamy, tym więcej za to płacimy, jednak czasem zysk bywa wymierny.
      Ja od dawna staram się ładnie formatować kod. Nie ma za bardzo sensu utrudniać sobie czytania 🙂 Na studiach nie widziałem jeszcze dużo kodu innych studentów, ale pamiętam jak w liceum ludzie nie robili wcięć – ale to chyba nie powinno dziwić, że ktoś początkujący zadaje sobie mniej trudu, skoro wtedy też działa 😛
      Także pozdrawiam! 🙂

Dodaj komentarz