Jest to nieco kontrowersyjny temat i myślę, że jest tyle opinii, ile jest programistów. Ale ze względu na to chcę wiedzieć, jakie są powszechne praktyki w biznesie (lub w miejscach pracy).
W moim miejscu pracy mamy ścisłe wytyczne dotyczące kodowania. Jedna z nich poświęcona jest magicznym ciągom znaków / liczbom. Mówi (dla C #):
Nie używaj wartości literalnych, ani liczbowych, ani ciągów znaków w kodzie innym niż definiowanie stałych symbolicznych. Użyj następującego wzorca, aby zdefiniować stałe:
public class Whatever { public static readonly Color PapayaWhip = new Color(0xFFEFD5); public const int MaxNumberOfWheels = 18; }
Istnieją wyjątki: wartości 0, 1 i null prawie zawsze można bezpiecznie stosować. Bardzo często wartości 2 i -1 są również OK. Ciągi przeznaczone do rejestrowania lub śledzenia są wyłączone z tej reguły. Literały są dozwolone, gdy ich znaczenie jest jasne z kontekstu i nie podlega przyszłym zmianom.
mean = (a + b) / 2; // okay
WaitMilliseconds(waitTimeInSeconds * 1000); // clear enough
Idealną sytuacją byłby jakiś oficjalny artykuł badawczy pokazujący wpływ na czytelność / łatwość konserwacji kodu, gdy:
- Magiczne liczby / ciągi znaków są wszędzie
- Magiczne ciągi / liczby są zastępowane ciągłymi deklaracjami w rozsądny sposób (lub w różnych stopniach zasięgu) - i proszę nie krzycz na mnie za używanie „rozsądnie”, wiem, że każdy ma inne pojęcie, co to „rozsądnie”
- Liczby magiczne / liczby są zastępowane w nadmiarze i tam, gdzie nie musiałyby być (patrz mój przykład poniżej)
Chciałbym to zrobić, aby mieć pewne naukowe argumenty podczas kłótni z jednym z moich kolegów, który dąży do tego, aby zadeklarować stałe, takie jak:
private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;
Innym przykładem może być (a ten jest w JavaScript):
var someNumericDisplay = new NumericDisplay("#Div_ID_Here");
Czy przyklejasz identyfikatory DOM na wierzchu pliku javascript, jeśli ten identyfikator jest używany tylko w jednym miejscu?
Przeczytałem następujące tematy:
StackExchange
StackOverflow
Bytes Społeczność IT
Istnieje wiele innych artykułów, a po ich przeczytaniu pojawiają się pewne wzorce.
Więc moim pytaniem powinno być używanie magicznych ciągów i liczb w naszym kodzie? W szczególności szukam odpowiedzi ekspertów, które w miarę możliwości są poparte referencjami.
źródło
NumberTen = 10
Jest to bezcelowe, ponieważ liczba 10 nie zostanie ponownie zdefiniowana.MaxRetryCount = 10
W tym momencie możemy chcieć zmienić maksymalną liczbę ponownych prób.private const char SemiColon = ';';
Głupi.private const char LineTerminator = ';'
; Mądry.Odpowiedzi:
Argument, który musisz wysunąć z kolegą, nie dotyczy nazywania dosłownej przestrzeni,
Space
ale jego zły wybór imienia dla jego stałych.Załóżmy, że Twoim zadaniem jest przeanalizowanie strumienia rekordów, które zawierają pola oddzielone średnikami (
a;b;c
) i same są oddzielone spacjami (a;b;c d;e;f
). Jeśli ktoś, kto napisał twoją specyfikację, zadzwoni do ciebie za miesiąc i powie: „popełniliśmy błąd, pola w rekordach są oddzielone symbolami potoku (a|b|c d|e|f
)”, co robisz?W ramach schematu wartość-jak-nazwa, który preferuje twój kolega, musisz zmienić wartość literal (
SemiColon = '|'
) i żyć z kodem, który nadal używaSemiColon
do czegoś, co tak naprawdę nie jest już średnikiem. Doprowadzi to do negatywnych komentarzy w recenzjach kodu . W celu zmniejszenia, że można zmienić nazwę na dosłownymPipeSymbol
i przejść i zmienić wszystkie wystąpieniaSemiColon
doPipeSymbol
. Przy takim tempie równie dobrze mógłbyś po prostu użyć dosłownego średnika (';'
), ponieważ będziesz musiał ocenić każde użycie z osobna i będziesz wprowadzać taką samą liczbę zmian.Identyfikatory stałych muszą opisywać, co robi wartość , a nie jaka jest wartość , i tam kolega skręcił w lewo w chwasty. W opisanej powyżej aplikacji do dzielenia pól średnikiem jest separator pól, a stałe należy odpowiednio nazwać:
W ten sposób, gdy zmienia się separator pól, zmieniasz dokładnie jeden wiersz kodu, deklarację stałej. Ktoś patrząc na zmianę zobaczy tylko jedną linię i natychmiast zrozumie, że separator pola zmienił się z średnika na symbol potoku. Pozostała część kodu, który nie musiał się zmieniać, ponieważ używał stałej, pozostaje taki sam, a czytelnik nie musi go przekopywać, aby zobaczyć, co jeszcze zostało zrobione.
źródło
#define one 1 #define two 2
itp. (Lub jakikolwiek inny odpowiednik w brytyjskim urzędzie pocztowym Coral, wówczas wybranym języku). Z góry dobiegło słowo, że w polu długości będzie liczba bajtów, a nie segmentów, więc oczywiście kod został zmieniony na#define one 8 #define two 16
etc;
na|
.public static final String MY_KEY_NAME = "MyKeyName"
CSV_RECORD_SEPARATOR
,TSV_RECORD_SEPARATOR
itd.)Zdefiniowanie średnika jako stałej jest zbędne, ponieważ średnik jest już sam w sobie stały . To się nigdy nie zmieni.
To nie jest tak, że pewnego dnia ktoś ogłosi „zmiana terminologii, + to teraz nowy średnik”, a twój kolega chętnie spieszy się tylko z aktualizacją stałej (śmiali się ze mnie - spójrz na nie teraz).
Jest też kwestia spójności. Gwarantuję, że jego
NumberTen
stała NIE będzie używana przez wszystkich (większość programistów nie oszaleje), więc i tak nie spełni ona zamierzonego celu. Kiedy nadejdzie apokalipsa i globalnie przeskaluje „dziesięć” do 9, aktualizacja stałej NIE zadziała, ponieważ nadal pozostawi ci mnóstwo literałów10
w kodzie, więc teraz system staje się całkowicie nieprzewidywalny, nawet w zakresie rewolucyjnego założenia, że „dziesięć” oznacza „9”.Przechowywanie wszystkich ustawień jako stałych jest również czymś, o czym chciałbym się zastanowić. Nie należy tego robić lekko.
Jakie przykłady tego rodzaju użytkowania zebraliśmy do tej pory? Terminator linii ... maksymalna liczba ponownych prób ... maksymalna liczba kół ... czy jesteśmy pewni, że to się nigdy nie zmieni?
Kosztem jest to, że zmiana ustawień domyślnych wymaga ponownej kompilacji aplikacji, aw niektórych przypadkach nawet jej zależności (ponieważ wartości stałych numerycznych mogą zostać zakodowane podczas kompilacji).
Istnieje również aspekt testowania i kpiny. Zdefiniowałeś ciąg połączenia jako const, ale teraz nie możesz wyśmiewać dostępu do bazy danych (ustanowić fałszywe połączenie) w teście jednostkowym.
źródło
’
(lewy pojedynczy cytat, Unicode 8217 ) dla aplikacji zgodnych z pokazywaniem innego glifu dla zwiniętego znaku. Ponieważ Europa używa przecinków tak, jak Amerykanie używają kropek jako miejsca dziesiętnego, trochę waham się przed ogłoszeniem „nie ... nigdy”.DecimalPoint
stałej - ale nieComma
lubPeriod
stałymi. To spora różnica: ta pierwsza oznacza funkcję , rolę lub cel wartości. „Średnik” lub „przecinek” nie należą do tej kategorii.Więc twój kolega dąży do codziennego wpisu do WTF. Te definicje są głupie i zbędne. Jednak, jak zauważyli inni, następujące definicje nie byłyby głupie ani zbędne:
Liczby i łańcuchy „magiczne” są stałymi, które mają znaczenie przekraczające ich bezpośrednią, dosłowną wartość. Jeśli stała
10
ma znaczenie wykraczające poza „dziesięć rzeczy” (powiedzmy jako kod dla określonej operacji lub warunku błędu), wtedy staje się „magią” i powinna zostać zastąpiona stałą symboliczną opisującą to abstrakcyjne znaczenie.Poza wyraźnym opisaniem zamiarów, stałe symboliczne również oszczędzają ci bólów głowy, gdy źle literujesz. Prosta transpozycja z „CVS” do „CSV” w jednym wierszu kodu przeszła przez testy jednostkowe i kontrolę jakości i wprowadziła go do produkcji, gdzie spowodowała niepowodzenie określonej operacji. Tak, oczywiście testy jednostkowe i QA były niekompletne i to jest własny problem, ale użycie stałej symbolicznej pozwoliłoby uniknąć zgagi.
źródło
Nie powinno być w tym nic kontrowersyjnego. Nie chodzi o to, czy używać magicznych liczb, czy nie, chodzi o to, aby mieć czytelny kod.
Rozważ różnicę między:
if(request.StatusCode == 1)
aif(request.HasSucceeded)
. W tym przypadku argumentowałbym, że ten drugi jest o wiele bardziej czytelny, ale to nie znaczy, że nigdy nie możesz mieć takiego koduint MaxNumberOfWheels = 18
.PS: Właśnie dlatego absolutnie nienawidzę wytycznych dotyczących kodowania. Deweloperzy powinni być wystarczająco dojrzali, aby móc wykonywać takie oceny; nie powinni pozostawiać tego fragmentowi tekstu utworzonego przez boga, który wie kto.
źródło