Boolean (typ logiczny, w wielu językach bool) to typ danych, który ma tylko dwie wartości: true (prawda) i false (fałsz). Boolean obsession to nadużywanie takich wartości tam, gdzie stan ma w rzeczywistości więcej niż dwa warianty albo gdzie sama flaga nie mówi, co oznacza.
Boolean obsession w skrócie
- Boolean ma dwie wartości:
trueifalse. Nazwa pochodzi od George’a Boole’a, twórcy algebry logiki. - Problem zaczyna się, gdy kilka flag opisuje jeden stan (
isAdmin+isGuest) albo gdy dotrue/falsedochodzi trzeci stan (null). - Objaw: ifologia, czyli rozrastające się drabinki
if/else. - Lekarstwo: enum lub union type, osobne funkcje zamiast flagi, obiekt konfiguracyjny, maszyna stanów.
Boolean – co to jest?
Boolean to typ danych reprezentujący dwie wartości logiczne: prawdę i fałsz. Nazwa pochodzi od angielskiego matematyka George’a Boole’a (1815–1864), który w pracach The Mathematical Analysis of Logic (1847) i The Laws of Thought (1854) opisał logikę za pomocą algebry – dziś nazywamy ją algebrą Boole’a. Jednym z pierwszych języków z jawnym typem BOOLEAN był ALGOL 60.
W praktyce każdy język podchodzi do typu logicznego trochę inaczej:
- TypeScript – typ
booleanto w rzeczywistości unia dwóch typów literalnychtrue | false. To ważne, bo za chwilę zobaczysz, że unia literałów jest też najprostszym lekarstwem na boolean obsession. - JavaScript – poza
trueifalseliczy się też „prawdziwość” wartości:0, pusty string,null,undefinediNaNw warunku zachowują się jakfalse(tzw. falsy). - Python –
booljest podklasąint, więcTrueiFalsezachowują się jak 1 i 0. - C – przez lata nie miał osobnego typu logicznego (0 to fałsz, każda inna liczba to prawda).
_Boolpojawił się w C99, a C23 wprowadził słowo kluczoweboolz wartościamitrueifalse.
Zmienna boolean (np. const isLoggedIn: boolean = true) jest najtańszym sposobem zapisania odpowiedzi na pytanie „tak czy nie?”. I właśnie dlatego tak łatwo ją nadużyć.
Czym jest boolean obsession?
„Boolean obsession” to określenie nadmiernego korzystania z typów boolean (prawda/fałsz) w kodzie. Chociaż booleany są wygodnym i prostym sposobem reprezentowania stanu, ich nadmiar może prowadzić do problemów z czytelnością i zrozumieniem kodu. Kiedy kod zaczyna być zbyt zależny od wartości logicznych, staje się mniej intuicyjny, trudniejszy do utrzymania, a także mniej elastyczny na przyszłe zmiany.
To nie jest formalny termin z katalogu refaktoryzacji, tylko szczególny przypadek kilku dobrze opisanych problemów:
- Primitive obsession – zapach kodu z katalogu Martina Fowlera i Kenta Becka (Refactoring): używanie typów prostych (liczb, stringów, booleanów) zamiast małych obiektów lub typów opisujących dziedzinę.
- Flag argument – parametr, który przełącza funkcję między różnymi zachowaniami. Fowler w 2011 r. pisał, że zamiast
book(martin, false)czytelniej jest wywołaćregularBook(martin), a w katalogu refaktoryzacji opisuje to jako Remove Flag Argument. - Boolean blindness – określenie Roberta Harpera (2011): sam bit
true/falsenie niesie informacji, skąd się wziął i co znaczy, więc żeby go użyć, trzeba znać jego pochodzenie.
Gdzie zazwyczaj pojawia się problem?
Najczęściej spotykane miejsca, w których boolean obsession może się pojawić, to:
- Parametry metod: Gdy funkcje przyjmują wiele parametrów boolean, kod staje się nieczytelny, ponieważ w miejscu wywołania nie widać, co dany parametr oznacza. To znaczy wiadomo, ale często zachodzi potrzeba, by sprawdzić różne warianty parametrów. Dodatkowo taka metoda tych parametrów może dostawać coraz więcej.
- Wewnętrzne flagi w klasach i obiektach: Wzrost liczby flag w klasach i obiektach może spowodować rozrost logiki warunkowej, co utrudnia rozumienie tego, co się dzieje w programie.
- Rozbudowane instrukcje warunkowe: Gdy kod zaczyna zawierać wielopoziomowe warunki oparte na wielu booleanach, debugowanie i śledzenie logiki staje się bardziej skomplikowane. Jedyny ratunek to bardzo dobre pokrycie tej pokrętnej logiki testami.
Przykłady boolean obsession
Flagi w parametrach funkcji, czyli ifologia
Myślę, że pierwszy przykład świetnie obrazuje problem. Mamy tutaj dwie flagi isAdmin oraz isGuest. W swojej karierze wiele razy widziałem podobny kod. Problem, jaki tutaj się pojawia, to trudne do ogarnięcia instrukcje warunkowe (ifologia), które mają sprawdzić dokładnie rodzaj użytkownika. Nawet nie chcę wiedzieć, jak ta funkcja by wyglądała, gdyby trzeba było dodać więcej typów użytkowników.
function createUser(name: string, isAdmin: boolean, isGuest: boolean) {
if (isAdmin && !isGuest) {
console.log(`${name} jest adminem.`);
} else if (!isAdmin && isGuest) {
console.log(`${name} jest gościem.`);
} else {
console.log(`${name} jest zwykłym użytkownikiem.`);
}
}Dwie flagi to cztery kombinacje, a sensowne są tylko trzy. Wywołanie createUser('Ania', true, true) – admin, który jest jednocześnie gościem – kompilator przepuści bez słowa, a funkcja po cichu zrobi z niego zwykłego użytkownika. Do tego w miejscu wywołania createUser('Ania', false, true) nie widać, która flaga jest która. Każda kolejna flaga podwaja liczbę kombinacji, a razem z nimi rośnie ifologia.
True, false… i null, czyli trzeci stan w API
Innym ciekawym przykładem, z jakim ostatnio miałem styczność, była odpowiedź z API. W jednym z endpointów było pole isOnline, które przyjmowało dwie wartości: true lub false. Wszystko wyglądało całkiem dobrze do momentu, w którym nastąpiła integracja z innym systemem, który nie potrafił określić, czy użytkownik jest online. Co zrobili programiści, by nie psuć kontraktu? Dodali null jako trzeci stan.
interface UserStatus {
isOnline: boolean | null; // null = „nie wiadomo”
}To teraz, cytując klasyka, „biorę od państwa po 200 zł i pytam”, jak to będzie wyglądało, jeśli trzeba będzie dodać kolejne dwa stany? Znaczenie null żyje tylko w komentarzu (albo w głowie autora), a każdy klient API musi pamiętać, że if (!user.isOnline) wrzuca do jednego worka „offline” i „nie wiadomo”.
Dobra wiadomość jest taka, że da się to prosto naprawić.
Jak unikać boolean obsession?
- Enumy i typy wyliczeniowe: Zamiast booleanów używaj bardziej opisowych typów, które lepiej wyrażają możliwe stany.
- Obiekty konfiguracyjne: Zamiast przekazywać wiele booleanów, lepiej jest używać obiektu konfiguracji, który nazywa każdą opcję w miejscu wywołania. To ogólnie dobra praktyka, aby funkcje miały jak najmniej parametrów. Jeżeli jest ich dużo (powyżej 3), to sygnał, że coś poszło nie tak.
- Klarowne nazewnictwo: Zadbaj o to, aby zmienne boolean miały nazwy dokładnie opisujące ich rolę, np. zamiast
isActiveużyjuserHasActiveSubscription, co od razu daje pełniejszy kontekst. W tym przypadkuisActivemoże sugerować, czy dany użytkownik jest zalogowany w systemie. - Unikaj zagnieżdżania logiki warunkowej: Gdy warunki stają się zbyt złożone, rozważ refaktoryzację kodu, np. dzieląc logikę na mniejsze funkcje.
Enum i union types zamiast true/false
Jeśli zmienna opisuje „rodzaj” albo „stan” czegoś, prawie zawsze lepiej sprawdzi się typ z nazwanymi wartościami. W TypeScripcie najprościej zrobić to unią literałów, w innych językach – enumem:
type Role = 'admin' | 'guest' | 'user';
enum Role2 { Admin, Guest, User } // to samo jako enumDodanie czwartej roli to jedna linijka, a kompilator pokaże wszystkie miejsca, które trzeba obsłużyć.
Osobne funkcje zamiast flagi
Jeśli boolean przełącza między dwoma różnymi zachowaniami, często lepiej rozdzielić funkcję na dwie, tak jak radzi Fowler: zamiast sendEmail(user, true) – sendWelcomeEmail(user) i sendReminderEmail(user).
Obiekt konfiguracyjny lub obiekt wartości
Gdy flag nie da się uniknąć, przekaż je w obiekcie – wtedy wywołanie czyta się jak zdanie:
exportReport(data, { includeCharts: true, compress: false });Krok dalej to obiekt wartości (value object), np. klasa Subscription z metodą isActive() zamiast luźnej flagi – logika siedzi wtedy w jednym miejscu.
Maszyna stanów zamiast kilku flag
Klasyczny przykład z frontendu: isLoading, isError i isSuccess w jednym komponencie. Trzy flagi to osiem kombinacji, z czego sensowne są trzy lub cztery. Zamiast tego warto opisać stan jako jedną wartość (tzw. discriminated union), w której nie da się zapisać stanu niemożliwego – Yaron Minsky ujął to hasłem „make illegal states unrepresentable”.
type RequestState =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: User[] }
| { status: 'error'; message: string };Jak można poprawić przytoczone wcześniej przykłady?
Pierwszy przykład można zrefaktoryzować w następujący sposób – dwa booleany zamienić na jeden parametr role.
function createUser(name: string, role: 'admin' | 'guest' | 'user') {
const labels = { admin: 'adminem', guest: 'gościem', user: 'zwykłym użytkownikiem' };
console.log(`${name} jest ${labels[role]}.`);
}
createUser('Ania', 'guest');Ifologia znika, wywołanie mówi samo za siebie, a admin-gość przestaje być możliwy. W przypadku odpowiedzi API można zrobić podobnie:
type OnlineStatus = 'online' | 'offline' | 'unknown';Kiedy boolean jest w porządku?
Boolean obsession nie oznacza, że booleanów trzeba unikać. Pole emailVerified albo hasDiscount to naturalnie pytania typu „tak/nie”, które nie dostaną trzeciej odpowiedzi. Problem zaczyna się, gdy flaga opisuje coś, co ma więcej wariantów, gdy kilka flag razem koduje jeden stan albo gdy true/false w wywołaniu funkcji nic nie mówi czytelnikowi. Dobrym testem jest pytanie: „czy za pół roku może pojawić się trzecia opcja?”.
Takie decyzje dobrze sprawdzać na code review – również wtedy, gdy kod pisze AI, o czym więcej we wpisie o vibe codingu i jakości oprogramowania. Jeśli piszesz w JavaScripcie, przyda się też tekst o tym, kiedy używać var, let i const, a przed rozmową o pracę – lista pytań rekrutacyjnych dla frontend developera.
01Boolean – co to jest?+
02Czym różni się boolean od bool?+
03Co oznacza true i false w programowaniu?+
04Co to jest ifologia?+
05Czym zastąpić boolean, gdy pojawia się trzeci stan?+
Podsumowanie
Boolean obsession to jeden z tych ukrytych problemów, które mogą sprawić, że kod staje się trudniejszy do zrozumienia, rozbudowy i utrzymania. Co więcej, bezmyślne brnięcie w to może skutkować tworzeniem coraz większego długu technologicznego.
Używając enumów, obiektów konfiguracyjnych i dobrego nazewnictwa, możemy zwiększyć czytelność kodu oraz ułatwić jego przyszłe rozwijanie.
Dlatego zawsze przed użyciem booleana warto zadać sobie pytanie, czy istnieje szansa, że może pojawić się trzecia (i kolejne) opcja.