Jako doświadczony programista nauczyłem się unikać magicznych ciągów.
Mój problem polega na tym, że minęło tyle czasu, odkąd ich użyłem, zapomniałem o większości powodów. W rezultacie mam problem z wyjaśnieniem, dlaczego stanowią one problem dla moich mniej doświadczonych kolegów.
Jakie są obiektywne powody, aby ich unikać? Jakie problemy powodują?
anti-patterns
Kramii
źródło
źródło
Odpowiedzi:
W języku, który się kompiluje, wartość ciągu magicznego nie jest sprawdzana podczas kompilacji . Jeśli ciąg musi pasować do określonego wzorca, musisz uruchomić program, aby zagwarantować, że pasuje do tego wzorca. Jeśli użyłeś czegoś takiego jak wyliczenie, wartość jest co najmniej ważna w czasie kompilacji, nawet jeśli może to być niepoprawna wartość.
Jeśli magiczny ciąg jest zapisywany w wielu miejscach , musisz zmienić je wszystkie bez żadnego bezpieczeństwa (np. Błąd czasu kompilacji). Można temu przeciwdziałać, deklarując go tylko w jednym miejscu i ponownie wykorzystując zmienną.
Literówki mogą stać się poważnymi błędami. Jeśli masz funkcję:
i ktoś przypadkowo pisze:
Im gorzej, tym rzadszy lub bardziej złożony jest łańcuch, szczególnie jeśli masz programistów, którzy nie znają języka ojczystego projektu.
Magiczne ciągi rzadko są samo-dokumentujące. Jeśli widzisz jeden ciąg, nie mówi to nic o tym, co jeszcze mógłby / powinien być. Prawdopodobnie będziesz musiał zajrzeć do implementacji, aby upewnić się, że wybrałeś odpowiedni ciąg.
Tego rodzaju implementacja jest nieszczelna i wymaga zewnętrznej dokumentacji lub dostępu do kodu, aby zrozumieć, co należy napisać, zwłaszcza, że musi być perfekcyjnie znakowy (jak w punkcie 3).
Poza funkcjami „znajdowania łańcucha” w IDE istnieje niewielka liczba narzędzi, które obsługują wzorzec.
Możesz przypadkowo użyć tego samego magicznego sznurka w dwóch miejscach, gdy tak naprawdę są to różne rzeczy, więc jeśli zrobiłeś Znajdź i zamień i zmieniłeś oba, jeden z nich mógłby się zepsuć, podczas gdy drugi działał.
źródło
Szczytem, na który sięgnęły inne odpowiedzi, nie jest to, że „magiczne wartości” są złe, ale że powinny być:
To, co zazwyczaj odróżnia dopuszczalne „stałe” od „magicznych wartości”, to naruszenie jednego lub więcej z tych reguł.
Dobrze użyte, stałe pozwalają nam po prostu wyrazić pewne aksjomaty naszego kodu.
Co prowadzi mnie do ostatecznego punktu, że nadmierne użycie stałych (a zatem nadmierna liczba założeń lub ograniczeń wyrażonych w kategoriach wartości), nawet jeśli w inny sposób spełnia powyższe kryteria (ale zwłaszcza jeśli odbiega od nich), może sugerować, że opracowane rozwiązanie nie jest wystarczająco ogólne lub dobrze ustrukturyzowane (i dlatego tak naprawdę nie mówimy już o zaletach i wadach stałych, ale o zaletach i wadach dobrze ustrukturyzowanego kodu).
Języki wysokiego poziomu zawierają konstrukcje wzorców w językach niższego poziomu, które musiałyby wykorzystywać stałe. Te same wzorce można również zastosować w języku wyższego poziomu, ale nie powinno tak być.
Ale może to być osąd eksperta oparty na wrażeniu wszystkich okoliczności i jak powinno wyglądać rozwiązanie, a to, w jaki sposób uzasadnienie tego osądu będzie zależeć w dużej mierze od kontekstu. Rzeczywiście, może to nie być uzasadnione żadną ogólną zasadą, z wyjątkiem stwierdzenia: „Jestem na tyle dorosły, że widziałem już tego rodzaju pracę, z którą jestem zaznajomiony, zrobiony lepiej”!
EDYCJA: zaakceptowałem jedną edycję, odrzuciłem inną, a teraz dokonałem własnej edycji, czy mogę teraz rozważyć styl formatowania i interpunkcji mojej listy reguł, który należy ustalić raz na zawsze haha!
źródło
value / 2
, niż wvalue / VALUE_DIVISOR
przypadku tej ostatniej zdefiniowanej jak2
gdzie indziej. Jeśli zamierzałeś uogólnić metodę obsługującą CSV, prawdopodobnie chciałbyś, aby separator został przekazany jako parametr, a nie zdefiniowany jako stała. Ale to wszystko jest kwestia oceny w kontekście - przykład @ WGroleau na toSPEED_OF_LIGHT
jest coś, co chciałbyś wyraźnie nazwać, ale nie każda literalna tego potrzebuje.źródło
Przykład z życia: Pracuję z systemem innej firmy, w którym „byty” są przechowywane z „polami”. Zasadniczo system EAV . Ponieważ dodanie kolejnego pola jest dość łatwe, dostęp do niego uzyskuje się za pomocą nazwy pola jako ciągu:
(zwróć uwagę na magiczny ciąg „ProductName”)
Może to prowadzić do kilku problemów:
Więc moim rozwiązaniem było wygenerowanie stałych dla tych nazw, uporządkowanych według typu encji. Więc teraz mogę użyć:
Nadal jest ciągiem stałym i kompiluje się dokładnie do tego samego pliku binarnego, ale ma kilka zalet:
Dalej na mojej liście: ukryj te stałe za wygenerowanymi silnie typowanymi klasami - wtedy również typ danych jest zabezpieczony.
źródło
nameField = myEntity.ProductName;
.Magiczne łańcuchy nie zawsze są złe , więc może to być powód, dla którego nie możesz znaleźć ogólnego powodu do ich uniknięcia. (Przez „magiczny ciąg” zakładam, że masz na myśli dosłowność łańcucha jako część wyrażenia, a nie jako stałą.)
W niektórych szczególnych przypadkach należy unikać magicznych ciągów:
Ale w niektórych przypadkach „magiczne sznurki” są w porządku. Załóżmy, że masz prosty analizator składni:
Naprawdę nie ma tutaj magii i żaden z wyżej opisanych problemów nie ma zastosowania. IMHO nie miałoby żadnych korzyści
string Plus="+"
itp. Uprość to.źródło
if (dx != 0) { grad = dy/dx; }
."+"
i"-"
zTOKEN_PLUS
aTOKEN_MINUS
. Za każdym razem, gdy go czytam, miałem wrażenie, że trudniej go czytać i debugować! Zdecydowanie miejsce, w którym zgadzam się, że używanie prostych ciągów jest lepsze.Aby dodać do istniejących odpowiedzi:
Internacjonalizacja (i18n)
Jeśli tekst do wyświetlenia na ekranie jest zakodowany na stałe i zakopany w warstwach funkcji, bardzo trudno będzie ci przetłumaczyć ten tekst na inne języki.
Niektóre środowiska programistyczne (np. Qt) obsługują tłumaczenia poprzez wyszukiwanie z ciągu tekstowego w języku podstawowym na przetłumaczony język. Magiczne ciągi zwykle mogą to przetrwać - dopóki nie zdecydujesz, że chcesz użyć tego samego tekstu w innym miejscu i dostać literówkę. Nawet wtedy bardzo trudno jest znaleźć, które ciągi magiczne wymagają tłumaczenia, jeśli chcesz dodać obsługę innego języka.
Niektóre środowiska programistyczne (np. MS Visual Studio) przyjmują inne podejście i wymagają przechowywania wszystkich przetłumaczonych ciągów w bazie danych zasobów i odczytywania bieżących ustawień narodowych przez unikalny identyfikator tego ciągu. W takim przypadku aplikacja z ciągami magicznymi po prostu nie może zostać przetłumaczona na inny język bez większych przeróbek. Efektywne programowanie wymaga wprowadzenia wszystkich ciągów tekstowych do bazy danych zasobów i nadania unikalnego identyfikatora podczas pierwszego pisania kodu, a następnie i18n jest stosunkowo łatwe. Próba wypełnienia tego po fakcie zazwyczaj wymaga bardzo dużego wysiłku (i tak, byłem tam!), Więc o wiele lepiej jest zrobić wszystko dobrze.
źródło
Nie jest to priorytetem dla wszystkich, ale jeśli kiedykolwiek chcesz mieć możliwość automatycznego obliczania wskaźników sprzężenia / kohezji w kodzie, magiczne łańcuchy sprawiają, że jest to prawie niemożliwe. Łańcuch w jednym miejscu będzie odnosił się do klasy, metody lub funkcji w innym miejscu i nie ma łatwego, automatycznego sposobu na określenie, czy łańcuch jest sprzężony z klasą / metodą / funkcją tylko przez parsowanie kodu. Tylko podstawowa struktura (np. Angular) może ustalić, że istnieje powiązanie - i może to zrobić tylko w czasie wykonywania. Aby samodzielnie uzyskać informacje o sprzęganiu, twój parser musiałby wiedzieć wszystko o używanym frameworku, wykraczającym poza podstawowy język, w którym kodujesz.
Ale znowu, nie jest to coś, na czym zależy wielu programistom.
źródło