Unikanie parametrów boolean

Pisane przez nas metody naszpikowane są parametrami. Znalazło się tam też też miejsce dla bool’a, ale czy to na pewno dobre rozwiązanie?

Zacytujmy kogoś mądrego

Wpis ten zacznę od słów Roberta C. Martina (o którym mogłeś już przeczytać w jednym z pierwszych moich wpisów ). Autor bestsellera Clean Code: A Handbook of Agile Software Craftsmanship podzielił się z nami takim oto spostrzeżeniem:

Indeed, the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code. …[Therefore,] making it easy to read makes it easier to write.

Słowa te mogę bezpośrednio odnieść do parametrów typu bool, które tak często stosujemy w metodach. Podczas pisania wszystko jest dla nas jasne, sprawa wygląda nieco inaczej przy czytaniu.

Rzuć okiem na ten kawałek kodu i odpowiedz sobie na pytanie:

  • Czy wszystkie parametry metody możesz intuicyjnie zrozumieć bez wchodzenia w jej implementację?
var test = vendor.PlaceOrder(product, 1, true, false);

Już na pierwszy rzut oka, może się nam wydawać że coś tu jest nie tak i powyższa metoda PlaceOrder nie spełnia Single Responsibility Principle (Zasady pojedynczej odpowiedzialności) – skrywanej w pierwszej literze akronimu SOLID (autorstwa Roberta C. Martina – aka Uncle Boba).

Poprawmy czytelność

Co zrobić by w prosty sposób poprawić czytelność naszego kodu i ułatwić życie innym (i sobie w przyszłości)? Rozpatrzmy dwa przypadki użycia booleanów, na których odpowiemy sobie na to pytanie.

 

Metoda przyjmuje 1 parametr typu bool.

Przykład:

public string GetProduct(int productId, bool includeProductDetails)

Co się dzieję?

  • Nasza metoda wykonuje dwie funkcjonalności. Łamiemy SOLIDNą S-kę, a to bardzo nieładnie tak robić.

Rozwiązanie:

  • Rozbicie na dwie metody z pojedynczymi odpowiedzialnościami, teraz jak na tacy widać co jest grane i chyba już nikt nie będzie mieć wątpliwości do czego służy odpowiednia metoda.
public string GetProduct(int productId)
public string GetProductWithDetails(int productId)

 

Metoda przyjmuje więcej niż 1 parametry typu bool.

Poszło nam całkiem sprawnie, co jednak w sytuacji gdy takich parametrów w metodzie znajdzie się więcej? Spróbujmy odpowiedzieć sobie na to pytanie sięgając po kolejny…

Przykład:

public OperationResult PlaceOrder(Product product, int quantity, bool includeAddress, bool sendCopy)

Co się dzieje?

Prawdopodobnie metoda i tak wykonuję więcej niż jedną funkcjonalność, ale na potrzeby przykładu załóżmy, że tak nie jest i spróbujmy jakoś poprawić czytelność naszego rozwiązania. Może po prostu tak musi być, nieważne, nie bądźmy już tacy dociekliwi – poznajmy po prostu kolejną opcję radzenia sobie z boolem (hehe).

Rozwiązanie:

  • Podczas wywołania metody dopisz nazwę parametru by w przyszłości podczas czytania wszystko było jasne.
var test = vendor.PlaceOrder(product, 1,
                            includeAddress: true,
                            sendCopy: false);

Wygląda to zdecydowanie lepiej, teraz każdy już wie, że czarne jest białe a białe jest czarne.

  • Zamiast parametru bool użyj ENUMa
Public enum IncludeAddress { yes, no };
Public enum SendCopy { yes, no };
Public OperationResult PlaceOrder(Product product, int quantity, IncludeAddress includeAddress, SendCopy sendCopy);

var test = vandor.PlaceOrder(product, 1,
                             Vendor.IncludeAddress.yes,
                             Vendor.SendCopy.no);

 

Z pozoru niewielkie zmiany wprowadzają w nasze życie najwięcej korzyści. Za każdym razem gdy pokusisz się o napisanie kolejnej metody z boolem uderz się w pierś i zastanów czy to aby na pewno dobre rozwiązanie.

 

Pozdrawiam i nie łączę się w bulu, Wojtek