Czy zmienne flag są złe? Czy poniższe rodzaje zmiennych są głęboko niemoralne i czy niegodziwe jest ich używanie?
„zmienne boolowskie lub całkowite, które przypisujesz wartości w określonych miejscach, a następnie w dół poniżej sprawdzasz, a następnie w innym miejscu, aby coś zrobić, lub nie, na przykład używając
newItem = true
kilku wierszy poniżejif (newItem ) then
”
Pamiętam, że wykonałem kilka projektów, w których całkowicie zaniedbałem użycie flag i skończyłem na lepszej architekturze / kodzie; jednak jest to powszechna praktyka w innych projektach, nad którymi pracuję, a gdy kod rośnie i dodaje się flagi, rośnie również kod spaghetti IMHO.
Czy powiedziałbyś, że istnieją przypadki, w których używanie flag jest dobrą praktyką, a nawet konieczne? Czy zgadzasz się, że używanie flag w kodzie to ... czerwone flagi i należy ich unikać / refaktoryzować; ja po prostu radzę sobie z robieniem funkcji / metod, które sprawdzają stany w czasie rzeczywistym.
źródło
newItem = true
kilku wierszy poniżejif (newItem ) then
Odpowiedzi:
Problem, który widziałem podczas utrzymywania kodu korzystającego z flag, polega na tym, że liczba stanów rośnie szybko i prawie zawsze występują nieobsługiwane stany. Jeden przykład z własnego doświadczenia: pracowałem nad kodem, który miał te trzy flagi
Te trzy stworzyły osiem stanów (tak naprawdę były też dwie inne flagi). Kod nie obejmuje wszystkich możliwych kombinacji wartości, a użytkownicy widzieli błędy:
Okazało się, że były sytuacje, w których założenie w powyższym stwierdzeniu if było fałszywe.
Flagi z czasem się komplikują i ukrywają rzeczywisty stan klasy. Dlatego należy ich unikać.
źródło
Oto przykład, kiedy flagi są przydatne.
Mam kawałek kodu, który generuje hasła (za pomocą kryptograficznie bezpiecznego generatora liczb pseudolosowych). Osoba wywołująca metodę wybiera, czy hasło powinno zawierać wielkie litery, małe litery, cyfry, symbole podstawowe, symbole rozszerzone, symbole greckie, cyrylicy i Unicode.
W przypadku flag wywołanie tej metody jest łatwe:
i można nawet uprościć:
Bez flag, jaki byłby podpis metody?
o nazwie tak:
Jak zauważono w komentarzach, innym podejściem byłoby użycie kolekcji:
Jest to o wiele bardziej czytelne w porównaniu do zestawu
true
ifalse
, ale nadal ma dwie wady:Główną wadą jest to, że aby umożliwić łączenie wartości, tak
CharacterSet.LettersAndDigits
jakbyś pisał coś takiego wGenerate()
metodzie:ewentualnie przepisane w ten sposób:
Porównaj to z tym, co masz, używając flag:
Druga, bardzo niewielka wada polega na tym, że nie jest jasne, jak zachowałaby się metoda, gdyby została wywołana w następujący sposób:
źródło
newItem = true
kilku wierszy poniżejif (newItem ) then
Ogromnym blokiem funkcyjnym jest zapach, a nie flagi. Jeśli ustawisz flagę na linii 5, sprawdź tylko flagę na linii 354, to źle. Jeśli ustawisz flagę na linii 8 i sprawdzisz flagę na linii 10, nie ma sprawy. Również jedna lub dwie flagi na blok kodu są w porządku, 300 flag w funkcji jest złe.
źródło
Zazwyczaj flagi można całkowicie zastąpić pewnym smakiem wzorca strategii, z jedną implementacją strategii dla każdej możliwej wartości flagi. To znacznie ułatwia dodawanie nowych zachowań.
W sytuacjach krytycznych pod względem wydajności koszt pośredni może się pojawić i konieczne jest rozłożenie flagi na wyraźne flagi. Biorąc to pod uwagę, mam problem z zapamiętaniem jednego przypadku, w którym musiałem to zrobić.
źródło
Nie, flagi nie są złe ani zło, które należy za wszelką cenę zrewidować.
Rozważ wywołanie Java Pattern.compile (wyrażenie regularne, flagi int) . Jest to tradycyjna maska bitowa i działa. Spójrz na stałe w java i gdziekolwiek zobaczysz grupę 2 n , wiesz, że są tam flagi.
W idealnym świecie refaktoryzowanym zamiast tego należy użyć EnumSet, w którym stałe są zamiast tego wartościami w wyliczeniu i jak czytamy w dokumentacji:
W idealnym świecie to wywołanie Pattern.compile staje się
Pattern.compile(String regex, EnumSet<PatternFlagEnum> flags)
.Wszystko, co mówiło, nadal jego flagi. O wiele łatwiej jest pracować,
Pattern.compile("foo", Pattern.CASE_INSENSTIVE | Pattern.MULTILINE)
niż byłoby to mieć,Pattern.compile("foo", new PatternFlags().caseInsenstive().multiline())
albo w inny sposób próbować robić to, co flagi naprawdę są i są dobre.Flagi są często widoczne podczas pracy z rzeczami na poziomie systemu. Kiedy łączysz się z czymś na poziomie systemu operacyjnego, prawdopodobnie gdzieś masz flagę - czy to wartość zwracaną przez proces, czy uprawnienia do pliku, czy flagi do otwierania gniazda. Próba zmiany tych przypadków w polowaniu na czarownice przeciwko wyczuwalnemu zapachowi kodu prawdopodobnie skończy się gorszym kodem, niż gdyby ktoś użył i zaakceptował flagę.
Problem pojawia się, gdy ludzie niewłaściwie używają flag, łącząc je ze sobą i tworząc zestaw frankenflag wszelkiego rodzaju niepowiązanych flag lub próbując użyć ich tam, gdzie wcale nie są flagami.
źródło
Zakładam, że mówimy o flagach w podpisach metod.
Używanie pojedynczej flagi jest wystarczająco złe.
Dla twoich kolegów nic to nie znaczy, że pierwszy raz to zobaczą. Będą musieli spojrzeć na kod źródłowy metody, aby ustalić, co ona robi. Prawdopodobnie będziesz w tej samej pozycji kilka miesięcy później, gdy zapomnisz o co chodziło w twojej metodzie.
Przekazywanie flagi do metody zwykle oznacza, że metoda jest odpowiedzialna za wiele rzeczy. Wewnątrz metody prawdopodobnie wykonujesz proste sprawdzenie wierszy:
To słaba separacja problemów i zwykle można to obejść.
Zwykle mam dwie oddzielne metody:
Będzie to bardziej sensowne w przypadku nazw metod, które mają zastosowanie do rozwiązywanego problemu.
Przekazywanie wielu flag jest dwa razy gorsze. Jeśli naprawdę potrzebujesz przekazać wiele flag, rozważ kapsułkowanie ich w klasie. Nawet wtedy nadal będziesz mieć do czynienia z tym samym problemem, ponieważ Twoja metoda prawdopodobnie robi wiele rzeczy.
źródło
Flagi i większość zmiennych temp ma silny zapach. Najprawdopodobniej można je refaktoryzować i zastąpić metodami zapytań.
Ulepszony:
Flagi i zmienne tymczasowe podczas wyrażania stanu, powinny zostać ponownie przekształcone w metody zapytań. Wartości stanu (booleany, inty i inne prymitywy) powinny prawie zawsze być ukryte jako część szczegółów implementacji.
Flagi używane do sterowania, routingu i ogólnego przebiegu programu mogą również wskazywać na możliwość przefakturowania sekcji struktur kontrolnych na osobne strategie lub fabryki lub cokolwiek, co może być odpowiednie w danej sytuacji, które nadal korzystają z metod zapytań.
źródło
Kiedy mówimy o flagach, powinniśmy wiedzieć, że zostaną zmodyfikowane w czasie wykonywania programu i że wpłyną na zachowanie programu na podstawie ich stanów. Dopóki będziemy mieć czystą kontrolę nad tymi dwiema rzeczami, będą działać świetnie.
Flagi mogą działać świetnie, jeśli
Jeśli jest dużo piekła flag, należy poprzedzić dobrą pracę projektową, ponieważ flagi zaczynają odgrywać kluczową rolę w zachowaniu programu. Możesz przejść do diagramów stanu do modelowania. Takie diagramy działają również jako dokumentacja i wskazówki wizualne podczas ich obsługi.
Dopóki te rzeczy są na miejscu, myślę, że nie doprowadzi to do bałaganu.
źródło
Z pytania wynikało, że QA oznacza zmienne flagowe (globalne), a nie bity parametru funkcji.
Są sytuacje, w których nie masz wielu innych możliwości. Na przykład bez systemu operacyjnego musisz ocenić przerwania. Jeśli przerwanie przychodzi bardzo często i nie masz czasu na przeprowadzenie długiej oceny w ISR, nie tylko jest dozwolone, ale czasem nawet najlepsze praktyki, aby ustawić tylko niektóre flagi globalne w ISR (powinieneś spędzić jak najmniej czasu) w ISR) i do oceny tych flag w głównej pętli.
źródło
Nigdy nie sądzę, żeby coś było absolutnym złem w programowaniu.
Jest jeszcze jedna sytuacja, w której flagi mogą być w porządku, o których tu jeszcze nie wspomniano ...
Rozważ użycie zamknięć w tym fragmencie kodu JavaScript:
Funkcja wewnętrzna, przekazana do „Array.forEach”, nie może po prostu „zwrócić true”.
Dlatego musisz utrzymywać stan na zewnątrz za pomocą flagi.
źródło