Sabotaż standardów kodowania [zamknięty]

35

Istnieją różne standardy kodowania egzekwowane w firmach programistycznych, których celem jest zwiększenie niezawodności, przenośności i, co najważniejsze, czytelności kodu napisanego wspólnie przez różnych programistów.

Dwa godne uwagi przykłady to MISRA C i standard C ++ opracowany dla projektu JSF .

Zazwyczaj mają one następującą formę, po dokładnym określeniu, co oznaczają słowa „musi”, „powinno”, „powinno”, „może” itd.:

Przykład:

Reguła 50: Zmiennych zmiennoprzecinkowych nie bada się pod kątem dokładnej równości lub nierówności.

Uzasadnienie: Ponieważ liczby zmiennoprzecinkowe podlegają błędom zaokrąglania i obcinania, dokładna równość może nie zostać osiągnięta, nawet jeśli jest to oczekiwane.

Te standardy kodowania nakładają ograniczenia, zwykle na kod, który byłby legalny z punktu widzenia kompilatora, ale jest niebezpieczny lub nieczytelny i dlatego jest „uważany za szkodliwy”.

Teraz wykorzystajmy to!

Zostajesz zaakceptowany jako członek małego komitetu normalizacyjnego w swojej firmie, który ma opracować nowe standardy kodowania, z których będzie musiał korzystać każdy programista w firmie. Bez wiedzy innych, potajemnie zatrudniasz złowrogą organizację i Twoim zadaniem jest sabotowanie towarzystwa. Musisz zaproponować jeden lub więcej wpisów do standardu kodowania, które później będą utrudniać programistom. Należy jednak uważać, aby nie uczynić tego natychmiast oczywistym, w przeciwnym razie ryzykujesz, że nie zostanie zaakceptowany w standardzie.

Innymi słowy, musisz wprowadzić zasady do standardu kodowania, które wyglądają na uzasadnione i mają duże szanse na zaakceptowanie przez innych członków komitetu. Po rozpoczęciu projektów i zainwestowaniu w kod niezliczonych roboczogodzin, powinieneś być w stanie nadużyć tych zasad (na przykład ze względów technicznych lub bardzodosłowna interpretacja), aby oznaczyć kod normalny i dobrej jakości jako niezgodny ze standardem. Muszą więc włożyć dużo wysiłku w przeprojektowanie go, a reguły będą odtąd im przeszkadzać, ale ponieważ reguły są aktywne już od dłuższego czasu, czysty pęd utrzyma te role przy życiu, a ponieważ istnieją znaczące konflikty interesów między różnymi poziomami zarządzania, inni menedżerowie prawdopodobnie utrzymają zasady przy życiu (głupotą byłoby przyznać się do błędu!), utrudniając tym samym firmę! Mwahahahahaaa!

Punktacja

Najwyższa głosowana odpowiedź wygrywa po około 2 tygodniach od pierwszego ważnego wpisu. Mam pomysł na dobrą odpowiedź, ale opublikuję ją dopiero kilka dni później, ponieważ ktoś inny może dojść do tego samego pomysłu i nie chcę okradać ich z przyjemności. Oczywiście moja własna odpowiedź nie zostanie zaakceptowana ponad wszystko, bez względu na wynik.

Wyborcy są zachęcani do oceniania odpowiedzi na podstawie tego, jak dobrze luki są ukryte i jak frustrujące byłyby dla programistów.

Zasady i przepisy

  • Reguła lub reguły muszą wyglądać profesjonalnie napisane, jak w powyższym przykładzie
  • Reguły powinny wyglądać autentycznie (więc rzeczy takie jak „wszystkie zmienne muszą zawierać co najmniej jeden znak podkreślenia, jedną wielką literę, jedną małą literę i dwie cyfry” nie są akceptowane. W rzeczywistości utrudniłyby programistom, ale najprawdopodobniej nie zostałyby zaakceptowane przez komitet), a jeśli ich zasługi nie są od razu oczywiste, należy podać dobre uzasadnienie.
  • Powinieneś być w stanie znaleźć sposób na wykorzystanie / nadużywanie swoich zasad, aby później sabotować programistów. Możesz nadużywać niejednoznaczności w innych regułach lub możesz stosować wiele reguł, które same w sobie są nieszkodliwe, ale po połączeniu diaboliczne!
  • Powinieneś zamieścić wyjaśnienie w tagach spoiler na końcu swojego postu, w jaki sposób możesz nadużyć zasad
  • Używany język nie może być językiem ezoterycznym. Należy wybrać język szeroko stosowany w prawdziwych projektach, dlatego preferowane są języki ze składnią podobną do C (zamiast rzeczy takich jak Golfscript).
vsz
źródło
4
Python, Ruby, Haskell, Makefile, XML itp. To niektóre języki używane w wielu prawdziwych projektach, które nie mają składni podobnej do C.
kennytm
7
To pytanie wydaje się nie na temat, ponieważ nie jest to konkurs programowy.
Peter Taylor
5
@PeterTaylor: definicja obejmuje „zagadki programistyczne”, co nie oznacza, że ​​odpowiedź musi być fragmentem kodu oprogramowania. Nigdzie w definicji strony nie jest napisane, że chodzi tylko o „konkursy programistyczne”. Definicja to: „Code golf / Programowanie puzzli / Inne konkursy lub wyzwania programistyczne”
vsz
7
@PeterTaylor wygląda mi to na konkurs dotyczący programowania; w wyzwaniach gliniarzy i rabusiów rabusie też nie kodują (a jeśli argumentujesz, że rabusie komentują, to koniecznie skomentuj meta post sugerujący podział gliniarzy i rabusiów na dwa osobne pytania)
John Dvorak
5
Głosowałem za ponownym otwarciem. Wygląda na to, że wciąż mamy pytania, na które nie możemy się zgodzić, czy dotyczą one tematu. Przypomina mi to ten związany ze sztuką, który został zamknięty, a następnie ponownie otwarty dwa razy. Mam pomysł na odpowiedź na to pytanie i jest to zdecydowanie związane z programowaniem. To pytanie pasuje nawet do 2 tagów na stronie.
hmatt1

Odpowiedzi:

40

C / C ++

Zasada 1: nie należy stosować stałych ósemkowych

Uzasadnienie: stałe ósemkowe mogą być przyczyną zamieszania. Na przykład przypadkowe spojrzenie nad linią const int coefficients[] = {132, 521, 013, 102};
może pomijać fakt, że jedna z liczb w tablicy jest zdefiniowana ósemkowo.

Jeśli chcesz być jeszcze bardziej zły, dodaj:

Reguła 2: Stałe szesnastkowe należy stosować wyłącznie w kontekście manipulacji bitami.

Uzasadnienie: Jeśli stała reprezentuje wartość liczbową, jest bardziej czytelna, jeśli jest dziesiętna. Stała szesnastkowa powinna wskazywać, że reprezentuje maskę bitową, a nie wartość liczbową.

Jak można go nadużywać:

Weź następujący prosty program, który doda pierwsze 10 elementów tablicy. Ten kod nie byłby zgodny ze standardami.

sum = 0;
for (i = 0; i < 10; i++) 
{
    sum += array[i];
}

Uwaga, że 0 definicji jest to liczba ósemkowa. Zgodnie z regułą 1, wymaganie, aby cały kod był zapisywany jako 0x00, jest frustrujące. Według reguły 2, nawet bardziej frustrujące.

vsz
źródło
1
Czy możesz 0podać link do standardowej definicji kodowania, która mówi, że jest to ósemkowa stała? Zakładam, że to dlatego, że zaczyna się od charakteru 0. Wzmocniłoby to hipotetyczny argument pedanta.
xnor
16

Pyton

Reguła 1: Cały kod musi być skompilowany bajtowo przy użyciu -OO flagi, która optymalizuje kod bajtowy. Chcemy zoptymalizowanego kodu bajtowego pod względem wielkości i wydajności!

Reguła 2: Testy muszą być przeprowadzane na tym samym „artefakcie” kodu, który zostanie wprowadzony do produkcji. Nasi audytorzy tego wymagają.

Korzystanie -OOusuwa assertpolecenia. W połączeniu z regułą 2 skutecznie zakazuje używania assertinstrukcji w testach. Baw się dobrze!

ErlVolton
źródło
Usuwa to również dokumenty, co oznacza, że ​​nie otrzymujesz niczego z help()REPL, a nieformalne testowanie REPL wciąż testuje.
Kevin
Nie. Jeśli napiszesz odpowiednią platformę testową, użyje unittestmodułu lub, który implementuje swoje własne twierdzenia niezależne od __debug__flagi. Doctests po cichu nie będą jednak działać. Podstępny!
pppery
15

To jest dla projektu Node.JS.

Sekcja 3 - Szybkość i wydajność są najważniejsze

Reguła 3.1: Pliki powinny mieć maksymalnie 1kb. Pliki większe niż to są przetwarzane zbyt długo.

Reguła 3.2: Nie zagnieżdżaj funkcji głębszych niż 3 poziomy. Silnik V8 musi śledzić wiele zmiennych, a takie głębokie zamknięcia sprawiają, że pracuje ciężej, spowalniając ogólną interpretację.

Zasada 3.3: Unikajrequire() obejścia.

Reguła 3.3.1: Żadne moduły require()d nie powinny mieć require()głębokości większej niż 3. Głębokierequire() łańcuchy są drogie zarówno pod względem wykorzystania pamięci, jak i szybkości.

Reguła 3.3.2: Moduły podstawowe liczą się jako pojedyncze require(), bez względu na to, ile razy require()wewnętrznie.

Reguła 3.3.3: Moduły zewnętrzne liczą się jako maksymalnie 2 require()s. Nie możemy sobie pozwolić na taką samą łagodność jak w przypadku modułów podstawowych, ale możemy założyć, że autorzy modułów piszą wydajny kod.

Zasada 3.4: Unikaj połączeń synchronicznych za wszelką cenę. Często zajmuje to dużo czasu i blokuje kontynuowanie całej pętli zdarzeń.

Jak można go nadużywać:

Reguły 3.1 i 3.3 nie działają dobrze razem. Utrzymując maksymalnie 1kb i 3 require()s w dół łańcucha, będą ciężko pracować, aby odnieść sukces.
Reguły 3.2 i 3.4 są prawie niezgodne. 3.4 zakazuje połączeń synchronicznych; 3.2 utrudnia zaawansowaną pracę asynchroniczną, ograniczając liczbę wywołań zwrotnych.
Zasada 3.4 jest, szczerze mówiąc, zasadą, której przestrzeganie jest prawdziwe. 3.1, 3.2 i 3.3 są całkowicie fałszywe.

Scimonster
źródło
11

JavaScript (ECMAScript)

7.3.2: Literały wyrażeń regularnych

Nie wolno używać literałów wyrażeń regularnych. W szczególności kod źródłowy nie może zawierać żadnych podciągów pasujących do nieterminala RegularExpression zdefiniowanego poniżej.

RegularExpression     :: '/' RegularExpressionBody '/'
RegularExpressionBody :: [empty]
                         RegularExpressionBody [any-but-'/']

[pusty] dopasowuje pusty ciąg, a [dowolny, ale - '/'] dopasowuje dowolny ciąg jednoznakowy oprócz tego zawierającego „/” (ukośnik, U+002F).

Racjonalne uzasadnienie

Wyrażenia regularne są często odradzane ze względu na czytelność. Często łatwiej jest zrozumieć kod za pomocą tradycyjnych operacji na łańcuchach, niż odwołując się do wyrażeń regularnych. Co ważniejsze, wiele silników wyrażeń regularnych oferuje słabą wydajność. Wyrażenia regularne są również powiązane z problemami bezpieczeństwa w kontekście JavaScript.

Jednak Organizacja ™ rozpoznaje, że wyrażenia regularne okazjonalnie najlepszym narzędziem do pracy. Dlatego RegExpsam obiekt nie jest zabroniony.

(Składnia samego fragmentu gramatyki [nie tego, który on definiuje] odpowiada składni specyfikacji ECMAScript. Zostałoby to oczywiście zdefiniowane bardziej rygorystycznie w innym punkcie hipotetycznej specyfikacji.)

Sztuczka

Następujący program jest niezgodny:

// sgn(x) is -1 if x < 0, +1 if x > 0, and 0 if x = 0.
function sgn(x) {
  return x > 0?  +1
       : x < 0?  -1
       :          0
}

Przedstawione powyżej produkcje dla nieterminala RegularExpressionBody pokazują powszechny sposób wyrażania list w BNF poprzez poleganie na jawnej rekurencji. Sztuczka polega na tym, że „przypadkowo” dopuszczam pusty ciąg jako RegularExpressionBody , tak że ciąg ten //jest zabroniony w kodzie źródłowym. Ale kto w ogóle potrzebuje komentarzy jednowierszowych? Wydaje się, że C89 i CSS działają dobrze, dopuszczając tylko /* */blokowanie komentarzy.

Robaczek świętojański
źródło
15
W rzeczywistości jest jeszcze bardziej zły: kod nie może zawierać komentarzy blokowych ani więcej niż jednego operatora podziału na plik.
Chromatix
O tak, masz rację. Nawet o tym nie myślałem. : P
FireFly
5

DO#

12.1 Metody statyczne wpływające na stan programu są zabronione

Jest tak, ponieważ trudno jest wiarygodnie przetestować wyniki metody statycznej, zwłaszcza takiej, która zmienia jakiś stan.

12.2 Metody statyczne muszą być deterministyczne

Jeśli metoda statyczna pobiera dane wejściowe i daje wynik, wynik musi być taki sam za każdym razem, gdy metoda statyczna jest wywoływana z tymi samymi danymi wejściowymi.

Czemu

Punktem wejścia dla programu C # jest prywatna metoda statyczna „main”. Zgodnie z pierwszą regułą jest to teraz zabronione, ponieważ reguła zapomina stwierdzić, że tylko publiczne, chronione lub wewnętrzne metody powinny przestrzegać tej reguły. Jeśli testowanie naprawdę stanowi problem, tylko publiczne metody powinny być zgodne z regułą 1. Main może również złamać regułę 2, ponieważ program poda kod błędu, jeśli program się nie powiedzie, może to nastąpić niezależnie od parametrów wejściowych. Na przykład program może nie znaleźć pliku lub może mieć zależności od innych systemów, które nie są poprawnie skonfigurowane.

Sydan
źródło
4

JAVA / SPRING

4.2 Zastosowanie odbicia w kodzie produkcji

Ponieważ Refleksji można używać do uzyskiwania dostępu do innych części naszego kodu źródłowego objętych ograniczeniami, użycie refleksji w Kodzie produkcyjnym jest surowo zabronione.

Sztuczka

Spring technicznie używa refleksji do tworzenia instancji i zarządzania obiektami, które obsługuje. Egzekwując tę ​​regułę, należy usunąć wszystkie narzędzia Spring.

tfitzger
źródło
3

Kodowanie strony internetowej

666.13 UTF-8 nie może być używany i należy go zastąpić UTF-7
Uzasadnienie: UTF-7 jest bardziej wydajny niż UTF-8, szczególnie w przypadku atakowania użytkowników z krajów arabskich, które robimy.

Jak można go nadużywać:

HTML5 w szczególności nie zezwala na UTF-7. Oznacza to, że nowoczesne przeglądarki go nie obsługują. Jeśli wszystkie testy zostaną przeprowadzone w przeglądarce takiej jak IE 11, nikt tego nie zauważy, dopóki nie będzie za późno.

Stefnotch
źródło
2

JavaScript Operatory bitowe

1.9 Nie wolno używać mnożenia, dzielenia lub wykładania podłóg, chyba że są one znacznie szybsze niż ich odpowiedniki bitowe. Zastąpią je odpowiednio operatory bitowe <<, >> i ~~.
Uzasadnienie: Operatory bitowe są bardziej wydajne.

Jak można go nadużywać:

Użycie << lub >> zamiast mnożenia lub dzielenia spowoduje problemy przy obsłudze dużych liczb. Ignorują również pierwszeństwo operacji i kropki dziesiętne. Podwójna tylda zwróci różne wartości, jeśli podasz jej liczbę ujemną.

Stefnotch
źródło
2
Myślę, że to już oczywiste, że x = (x<<10) + (x<<8) + (x<<5) + (x<<4) + (x<<3) + (x)jest gorsze pod każdym względem (być może nawet prędkości) x *= 1337, i że zastąpienie dzielenia przez brak potęgi dwóch sumami przesunięć bitowych jest jeszcze gorsze.
lirtosiast
@Thomas Kwa Zredagowałem odpowiednio swoją odpowiedź. Dziękuję za zwrócenie na to uwagi. Jestem nowy dla operatorów bitowych.
Stefnotch
1

JavaScript (ECMAScript)

7.3.1: Konwencje dotyczące identyfikatorów

Ograniczenia dotyczą identyfikatorów w zależności od typu identyfikatora. Identyfikatory są podzielone na typy Zmienna , Stała , Funkcja i Konstruktor ; patrz 5.3. Ograniczenia podano poniżej.

  • Zmienna: Pierwszy znak musi być małą literą. W celu oddzielenia słów w identyfikatorze należy użyć wielbłąda (patrz 1.3).

  • Stała: identyfikator musi składać się wyłącznie z wielkich liter i znaków podkreślenia („_”, U+005F). Podkreślenia należy używać do oddzielania słów w identyfikatorze.

  • Funkcja: Funkcje muszą spełniać te same zasady, co typ identyfikatora .

  • Konstruktor: Pierwszy znak musi być wielką literą. W celu oddzielenia słów w identyfikatorze należy użyć wielbłąda (patrz 1.3).

Racjonalne uzasadnienie

Czytelne nazwy identyfikatorów są bardzo ważne dla łatwości konserwacji. Ograniczenie identyfikatorów do dobrze znanych konwencji ułatwia także przechodzenie między różnymi bazami kodu. Te szczególne konwencje są wzorowane na standardowych konwencjach dla języka programowania Java ™ [1] .

Sztuczka

Z przykrością informuję zespół jQuery, że najczęstsza nazwa ich „globalnego obiektu jQuery” koliduje z tą konwencją nazw. Na szczęście już o tym pomyśleli i podali zarówno nazwy globalne, jak $i jQueryodnoszące się do tego samego obiektu. Wyobrażam sobie, że userbase może nie być tak chętni do przełączania $się jQuerywszędzie, choć.

Robaczek świętojański
źródło
2
»Funkcje muszą być zgodne z tymi samymi regułami, co typ identyfikatora .« - masz na myśli »jako typ zmiennej «?
Paŭlo Ebermann