Code Smell: Temporary Field

19-10-2022

Czy w Twoim kodzie są zmienne, które tylko czasami przyjmują jakąś wartość? Czy nie powoduje to u Ciebie uczucie zdziwienia i zakłopotania? Spodziewasz się, że ta zmienna ma jakąś wartość, jakiegoś typu, a tu jednak się okazuje, że nie ma nic… Prawdopodobnie wyczuwasz zapaszek Temporary Field. Brzydkimi zapachami określamy kod który inaczej ujmując „śmierdzi”. Kod, na widok którego masz ochotę coś zmodyfikować, aby pozbyć się tego nieprzyjemnego zapachu.

 

Zapachem Temporary Field (pole tymczasowe) określamy miejsca w kodzie, w których dla zmiennej ustawiana jest wartość tylko i wyłącznie w niektórych sytuacjach.

Czasami obserwujemy obiekty, w których pewna zmienna instancji otrzymuje wartość tylko w niektórych okolicznościach. Taki kod trudno się czyta, gdyż z reguły spodziewamy się, że obiekt potrzebuje wszystkich swoich zmiennych. Próby zrozumienia, dlaczego obiekt zawiera zmienną, która nie jest używana, mogą doprowadzić do poważnej irytacji.

Martin Fowler, Kent Beck

 

W części artykułów z jakimi się spotkałam zapaszek ten zmienił wydźwięk z „obiekty, w których pewna zmienna instancji otrzymuje wartość tylko w niektórych okolicznościach.” na:

  1. A Temporary field is a variable that isn’t really needed, or used in a very limited situation” ~Javier Arroyo, 2020 [artykuł]
  2. If you have a class instance variable that has only been used once, you have a code smell called Temporary Fields.” ~www.codegrip.tech
  3. Temporary Fields code smell happens when you have a class instance variables that have been used only sometimes.” ~Mohamed Aladdin, 2018 [artykuł]

 

Ja się jednak skupię tutaj na definicji tego zapaszku w jego postaci z książki Fowlera.

Poniżej możesz zobaczyć bardzo okrojoną klasę SomeClass. Klasa ta ma metodę doSomething. W tej metodzie możesz zobaczyć, że najpierw coś robi, potem wpada w sprawdzenie warunku i jeśli jest prawdziwy to wychodzi z metody. W przypadku, gdy nie jest prawdziwy to ustawia wartość zmiennej $someValue. Następnie przechodzi do wykonania metody doSomethingTwo i w niej operuje na tej ustawionej zmiennej.

class SomeClass
{
    private string $someValue;

    public function doSomething(int $id): bool
    {
        // .. do some staff

        if ($this->checkSomething($id)) {
            return false;
        }
        
        $this->someValue = "TEXT";
        
        return $this->doSomethingTwo();
    }

    private function doSomethingTwo(): bool
    {
        if ($this->someValue === 'text') {
            // .. do something
            return true;
        }
        
        return false;
    }

    private function checkSomething(int $id): bool
    {
        // ...

        return true;
    }
}

Dlaczego to jest zapaszek?

Powiedzmy, że kolejna osoba spojrzy na tą klasę, chce dopisać kolejną metodę publiczną, która korzysta z metody doSomethingTwo. Może się mocno zaskoczyć, że zawsze dostanie z niej false. Po „krótkim” debugu zauważa, że zmienna someValue, nie zawsze ma przypisaną wartość.

Innym problematycznym przypadkiem będzie, gdy ktoś z jakiegoś powodu będzie chciał wynieść wykonanie metody doSomethingTwo na początek metody. Również może się zaskoczyć co tu się stało i dlaczego wykonanie się tak szybko kończy.

Jak można to rozwiązać?

Obecnie widzę 2 sposoby

  1. Metoda doSomethingTwo przyjmuje w parametrze zmienną someValue. Po takiej zmianie myląca prywatna zmienna nie będzie już potrzebna.
  2. Zmienną i zależne od niej metody wydzielamy do osobnej klasy.

Znasz jakieś inne rozwiązanie?

Podziel się w komentarzu swoimi przemyśleniami na ten temat 😉

A może w Twojej opinii to nie jest zapaszek? 🤔


Źródła

Komentarze
  1. Daniel

    Super zapaszek, często go widuje.

    Traity są dobrym rozwiązaniem na nie duże zwiększenia.

    Osobiście idealnie widzę tu dekorowanie obiektu np. Call, CallWithCapaign 🙂

    • Monika Młodzik

      Traity i dziedziczenie nie darzę największą sympatią. Wydaje mi się, że zdecydowaną większość problemów da się rozwiązać poprzez kompozycje [composition] zamiast Trait. 🤔

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.