Dlaczego pomijanie nawiasów klamrowych uważa się za złą praktykę? [Zamknięte]


177

Dlaczego wszyscy mówią mi, że pisanie takiego kodu jest złą praktyką?

if (foo)
    Bar();

//or

for(int i = 0 i < count; i++)
    Bar(i);

Moim największym argumentem za pominięciem nawiasów klamrowych jest to, że czasami może zawierać dwa razy więcej wierszy. Na przykład, oto kod do malowania efektu blasku dla etykiety w C #.

using (Brush br = new SolidBrush(Color.FromArgb(15, GlowColor)))
{
    for (int x = 0; x <= GlowAmount; x++)
    {
        for (int y = 0; y <= GlowAmount; y++)
        {
            g.DrawString(Text, this.Font, br, new Point(IconOffset + x, y));
        }
     }
 }
 //versus
using (Brush br = new SolidBrush(Color.FromArgb(15, GlowColor)))
    for (int x = 0; x <= GlowAmount; x++)
        for (int y = 0; y <= GlowAmount; y++)
            g.DrawString(Text, this.Font, br, new Point(IconOffset + x, y));

Możesz także uzyskać dodatkową korzyść z łączenia w łańcuch usingsbez konieczności wciskania milion razy.

using (Graphics g = Graphics.FromImage(bmp))
{
    using (Brush brush = new SolidBrush(backgroundColor))
    {
        using (Pen pen = new Pen(Color.FromArgb(penColor)))
        {
            //do lots of work
        }
    }
 }
//versus
using (Graphics g = Graphics.FromImage(bmp))
using (Brush brush = new SolidBrush(backgroundColor))
using (Pen pen = new Pen(Color.FromArgb(penColor)))
{
    //do lots of work
}

Najczęstszy argument za nawiasami klamrowymi dotyczy programowania konserwacyjnego i problemów, które wynikną z wstawienia kodu między oryginalną instrukcję if a jej zamierzonym wynikiem:

if (foo)
    Bar();
    Biz();

Pytania:

  1. Czy źle jest chcieć używać bardziej zwartej składni, jaką oferuje język? Ludzie, którzy projektują te języki, są sprytni, nie wyobrażam sobie, żeby umieścili funkcję, która zawsze jest niewłaściwa.
  2. Powinniśmy czy nie powinniśmy napisać kod tak, aby najniższy wspólny mianownik mógł go zrozumieć i nie miał z nim problemów?
  3. Czy jest inny argument, którego mi brakuje?

6
Zgadzam się z Tobą. Pomiń je. Kropka.
Andrei Rînea,

67
KTO DBA O ILE LINII COŚ JEST W 2010. Monitory są szerokie, tanie i wysokiej rozdzielczości! Mój monitor to 2048 X 1152 i mam ich DWA! Czytelność jest o wiele ważniejsza niż zapisanie 2 pionowych linii, kiedy można łatwo wprowadzić subtelne błędy, które są trudne do znalezienia.

51
Monitory są szerokie i tanie, ale nie są wysokie i tanie. Przestrzeń pionowa jest rzadsza niż przestrzeń pozioma.
mówi Adam - Przywróć Monikę

32
@AdamRuth Turn them side :)
Zachary Yates

16
Więc nie spieprzysz jak Apple z błędem SSL znalezionym w lutym 2014, LOL.
learnvst

Odpowiedzi:


183

Właściwie jedyny raz, kiedy naprawdę mnie ugryzł, to debugowanie i skomentowanie bar ():

if(foo)
  // bar();
doSomethingElse();

Poza tym zwykle używam:

if(foo) bar();

Który załatwia powyższy przypadek.

EDYCJA Dziękuję za wyjaśnienie pytania, zgadzam się, nie powinniśmy pisać kodu do najniższego wspólnego mianownika.


31
To oczywiście trudne, ale myślę, że największym problemem dla opiekunów jest to, że dodadzą drugą linię i nie zdadzą sobie sprawy, że nie jest to część instrukcji warunkowej, mimo że NAPRAWDĘ wygląda tak, jak powinna.
danieltalsky

23
Nie podoba mi się styl z jedną wkładką, ponieważ zawsze szukam poniżej body pętelkowego.
Nosredna

18
Uważam, że jednoliniowy styl jest bardziej irytujący niż pomocny, ponieważ (szczególnie w głębokim zagnieżdżaniu - ugh) stwierdzenie można łatwo nadpisać i może dojść do zamieszania. Prawie wyłącznie używam takich pojedynczych instrukcji ifs do walidacji danych wejściowych (tj. Wczesnych zwrotów) lub kontroli pętli (np. Ignorowanie nieistotnych nazw plików w spacerach po systemie plików), gdzie puste linie pomagają oddzielić je od głównego kodu.
Alan Plum

1
Styl jednowierszowy powoduje również ukrycie słupka () przed pokryciem testu. Będzie wyglądać na zakrytą, nawet jeśli foo jest zawsze fałszywe.
Bohumil Janda

1
To inny sposób powiedzenia: „gdyby źródło zawierało nawiasy klamrowe, nie traciłbym czasu na debugowanie”. - dodanie szelek jest banalnie proste i pozwala uniknąć pozostawienia pułapek dla następnej osoby. Jedynym argumentem przeciwko jest „czytelność”, która jest dość wątła, biorąc pod uwagę, że jest to przypadek, w którym coś się niejawnie dzieje, jeśli je pominiesz.
Andrew Theken

156

Szybkość czytania ...

Oprócz tego, co już zostało wspomniane. W tym momencie zostałem już uwarunkowany analizowaniem instrukcji if z nawiasami klamrowymi i spacjami. Przeczytałem więc:

if (condition)
{
    DoSomething();
}

DoSomethingElse();

Nieco szybciej niż czytałem:

if (condition) DoSomething();

DoSomethingElse();

Czytam to trochę wolniej, jeśli wygląda to tak:

if (condition) DoSomething();
DoSomethingElse();

Czytam to znacznie wolniej niż poprzedni:

if (condition) 
    DoSomething();
DoSomethingElse();

ponieważ nie mogę się powstrzymać od przeczytania go ponownie na wszelki wypadek i zastanawiam się, czy autor miał zamiar:

if (condition)
{
    DoSomething();
    DoSomethingElse();
}

Omówiono już ogólnie, ale jeśli chodzi o przeczytanie poniżej, będę się temu przyglądać przez dłuższy czas, aby upewnić się, co zamierzał autor. Może nawet wytropię oryginalnego autora, aby to potwierdzić.

if (condition) 
    DoSomething();
    DoSomethingElse();

29
Problem zostanie rozwiązany, gdy w czwartej próbce po prostu wstawisz pusty wiersz po instrukcji if, aby oddzielić ją od DoSomethingElse () To właśnie robię, a czytelność jest praktycznie taka sama jak w przypadku pierwszej próbki (jeśli nie lepsza ;-P) Inną rzeczą jest to, że umieszczanie wierszy w grupach po 2 lub 3 znacznie poprawia czytelność, po prostu skanujesz kod znacznie szybciej.
Piotr Owsiak

6
Może dlatego, że jestem przyzwyczajony do Pythona, ale umieszczenie pierwszego nawiasu klamrowego w tym samym wierszu co instrukcja if pozwala mi czytać + rozumieć to jeszcze szybciej.
Ponkadoodle

16
Problem z stylem bez klamry sprawia, że ​​marnujesz cenną koncentrację na myślenie o tym, czy blok ma szelki, a nie ważniejsze rzeczy. Już samo to jest wystarczającym powodem, aby stosować najprostszą możliwą konwencję, czyli zawsze nawiasy klamrowe.
Nate CK

2
Szelki są z natury wyraźne. Będę się tego trzymać, dzięki.
TheOptimusPrimus

2
W ostatnim przypadku dopadnij oryginalnego autora i daj mu klapsa ...;)
Per Lundberg

55

Jeśli to coś małego, napisz to tak:

if(foo()) bar();

Jeśli jest wystarczająco długi, aby podzielić na dwie linie, użyj nawiasów klamrowych.


tak, to też robię. Zmusza cię do dodania nawiasów klamrowych, jeśli dodasz kolejną linię, i jest całkiem jasne, że bar () jest w rzeczywistości częścią if, więc złe rzeczy mogą się wydarzyć, jeśli po prostu to skomentujesz.
jalf,

10
Jednak niezbyt przyjazny dla debugera. Jak ustawić punkt przerwania w części „słupkowej”?
Nemanja Trifunovic,

9
@Nemanja: Po prostu ustaw kursor na bar (); i naciśnij F9. Zarówno VS2005, jak i VS2008 obsługują wewnątrzwierszowe punkty przerwania, jeśli są oddzielnymi „instrukcjami”.
GalacticCowboy,

4
GalanticCowboy: Jest więcej środowisk niż tych, które znasz. :-)

20
Jasne, ale ponieważ kontekst jest C #, to powinno obejmować znaczną większość użytkowników ...
GalacticCowboy,

47

Uważałem też, że lepiej jest używać szelek tylko wtedy, gdy są naprawdę potrzebne. Ale już nie, główny powód, dla którego masz dużo kodu, czyni go bardziej czytelnym i możesz szybciej przeanalizować kod, jeśli masz spójny styl nawiasów klamrowych.

Innym dobrym powodem, dla którego zawsze należy używać nawiasów klamrowych, poza tym, że ktoś dodaje drugą instrukcję do if, może się zdarzyć coś takiego:

if(a)
   if(b)
     c();
else
   d();

Czy zauważyłeś, że klauzula else jest faktycznie klauzulą ​​„if (b)”? Prawdopodobnie tak, ale czy zaufałbyś komuś, kto znał ten chwyt?

Tak więc, jeśli tylko dla spójności i ponieważ nigdy nie wiesz, jakie nieoczekiwane rzeczy mogą się wydarzyć, gdy ktoś inny (to zawsze inni są głupi) zmieni kod, zawsze umieszczam nawiasy klamrowe, ponieważ sprawia, że ​​kod źródłowy jest bardziej czytelny, szybszy do przeanalizowania przez Twój mózg. Tylko w przypadku najprostszych instrukcji if, takich jak if, w których następuje delegacja lub jest ona podobna do przełącznika, gdzie wiesz, że klauzula nigdy nie zostanie rozszerzona, pominę nawiasy klamrowe.


12
To jeden z dwóch przypadków, w których używam nawiasów klamrowych. W przeciwnym razie nie.
Andrei Rînea,

3
Powinien być raczej napisany tak, jakby (a && b) ... w pierwszej kolejności wydaje mi się.
alexander.biskop

8
@ alexander.biskop: Z pewnością nie, ponieważ to nadaje blokowi else inne znaczenie ( !a || !b) niż z ( !a) lub bez ( a && !b) dodanych nawiasów.
Ben Voigt

1
@Ben Voigt: Prawda! Czułem się za to ;-) Pół roku i dwa głosy poparcia później ktoś zdaje sobie sprawę, że moje stwierdzenie jest błędne ... Chyba nie przywiązywałem wystarczającej wagi do szczegółów, głównie dlatego, że mój komentarz miał inny zamiar niż wskazanie technicznie poprawne przekształcenie tej klauzuli if. Chodziło mi o to, że zagnieżdżone wbudowane instrukcje if generalnie zmniejszają czytelność (a zwłaszcza śledzenie przepływu sterowania) znacznie imho i dlatego powinny być raczej połączone w jedną instrukcję (lub całkowicie omijane). Pozdrawiam
alexander.biskop

3
@ alexander.biskop: W tym samym czasie debugowanie jest łatwiejsze dzięki zagnieżdżonym warunkom if, każdy z prostszymi warunkami, ponieważ możesz przejść do każdego z nich pojedynczo.
Ben Voigt


35

Linie są tanie. Moc procesora jest tania. Czas programisty jest bardzo drogi.

Z reguły, jeśli nie opracowuję jakiejś aplikacji, która ma absolutnie kluczowe znaczenie dla zasobów / szybkości, zawsze popełniłbym błąd po stronie pisania kodu, czyli

(a) Każdy inny programista może łatwo śledzić to, co robię

(b) Skomentuj określone części kodu, które mogą tego wymagać

(c) Łatwe do debugowania, jeśli coś pójdzie nie tak

(d) Łatwe do modyfikacji, jeśli zajdzie taka potrzeba w przyszłości (np. dodanie / usunięcie kodu)

Szybkość lub akademicka elegancja kodu jest drugorzędna w stosunku do tych czynników z biznesowego punktu widzenia. Nie oznacza to, że postanowiłem napisać niezgrabny lub brzydki kod, ale to jest MOJA kolejność priorytetów.

Pomijanie nawiasów klamrowych w większości przypadków sprawia, że ​​(b), (c) i (d) są trudniejsze (uwaga nie jest jednak niemożliwa). Powiedziałbym, że używanie nawiasów klamrowych lub nie ma wpływu na (a).


9
Twoje ostatnie stwierdzenie na temat (a) to opinia, którą spierałaby się duża liczba deweloperów, w tym również inni autorzy.
Kelly S. French

34

Wolę przejrzystość, jaką zapewnia klamra kręcona. Wiesz dokładnie, co to znaczy i nie musisz zgadywać, czy ktoś po prostu go oszukał i zostawił (i wprowadził błąd). Pomijam je tylko wtedy, gdy umieszczam if i akcję w tej samej linii. Ja też nie robię tego zbyt często. Właściwie wolę białe spacje wprowadzone przez umieszczenie nawiasu klamrowego we własnej linii, chociaż od lat programowania w stylu K&R C, kończenie wiersza nawiasem klamrowym jest praktyką, nad którą muszę pracować, aby przezwyciężyć, jeśli IDE nie wymusza tego dla mnie.

if (condition) action();  // ok by me

if (condition) // normal/standard for me
{
   action();
}

23

Myślę, że to kwestia wytycznych dotyczących projektu, nad którym pracujesz, i osobistego gustu.

Zwykle pomijam je, gdy nie są potrzebne, z wyjątkiem niektórych przypadków, takich jak:

if (something)
    just one statement; // i find this ugly
else
{
    // many
    // lines
    // of code
}

wolę

if (something)
{
    just one statement; // looks better:)
}
else
{
    // many
    // lines
    // of code
}

15

Jednym z przypadków, w których może to cię ugryźć, jest dawne makra C / C ++. Wiem, że jest to kwestia C #, ale często standardy kodowania są przenoszone bez powodu, dla którego standard został stworzony w pierwszej kolejności.

Jeśli nie jesteś bardzo ostrożny podczas tworzenia makr, możesz spowodować problemy z instrukcjami if, które nie używają {}.

#define BADLY_MADE_MACRO(x) function1(x); function2(x);

if (myCondition) BADLY_MADE_MACRO(myValue)

Nie zrozum mnie źle, nie mówię, że zawsze powinieneś robić {} tylko po to, aby uniknąć tego problemu w C / C ++, ale z tego powodu miałem do czynienia z kilkoma bardzo dziwnymi błędami.


2
gdyby tylko cały kod zadeklarował się jako taki ... westchnij
Nathan Strong,

15

Zwykłem myśleć w ten sam sposób.

Aż pewnego dnia (dlaczego zawsze jest ten „jeden dzień”, który na zawsze zmienia twoje życie?) Spędzamy od 24 do 36 godzin bez debugowania kodu produkcyjnego tylko po to, by dowiedzieć się, że ktoś nie założył nawiasów klamrowych połączonych ze zmianą wyszukiwania / zamiany .

To było coś takiego.

 if( debugEnabled ) 
      println( "About to save 1 day of work to some very important place.");
 saveDayData();

To, co przyszło później, było

 if( debugEnabled ) 
 //     println( "About to save 1 day of work to some very important place.");
 saveDayData();

Okazuje się, że system generował 500 MB logów dziennie i zostaliśmy poproszeni o jego zatrzymanie. Flaga debugowania nie była wystarczająca, więc wyszukiwanie i zamiana println były w porządku.

Mimo to, gdy aplikacja została uruchomiona, flaga debugowania była wyłączona, a ważne polecenie „saveDayData” nigdy nie zostało wywołane.

EDYTOWAĆ

Teraz jedynym miejscem, w którym nie używam nawiasów, jest konstrukcja if / try.

if( object != null ) try { 
     object.close();
} catch( .....

Po obejrzeniu, jak robi to supergwiazda.


3
Nie rozumiem. Masz zmienną kontrolującą debugowanie (debugEnabled) i nadal używasz komentarzy, aby wyłączyć debugowanie ??? Dlaczego po prostu nie ustawiłeś debugEnabled na false?
Igor Popov

To nie jest dokładnie taki scenariusz, ale masz rację. Głupie rzeczy (takie jak brak ustawienia debugowania na false) tworzą subtelne i głupie błędy, które są trudniejsze do znalezienia niż „oczywiste” błędy. Brak szelek nie pomógł w tym przypadku zbytnio.
OscarRyz,

1
@igor A może dlatego, że chcieli tylko usunąć jeden wiersz logowania, a nie wszystkie wiersze?
gman

14

Mówiąc szczerze, widzę to jako:

Dobrzy programiści programują defensywnie, źli programiści nie.

Ponieważ jest kilka przykładów powyżej i moje własne podobne doświadczenia z błędami związanymi z zapominaniem aparatu ortodontycznego, nauczyłem się trudnej drogi, aby ZAWSZE ZAKŁADAĆ SZELKI.

Cokolwiek innego to wybór osobistego stylu zamiast bezpieczeństwa, a to wyraźnie złe programowanie.

Joel nawet wspomina o tym w Making Wrong Code Look Wrong

Gdy zostaniesz ugryziony przez błąd z powodu brakujących nawiasów, dowiesz się, że brakujące nawiasy wyglądają nieprawidłowo, ponieważ wiesz, że jest to potencjalne miejsce na wystąpienie kolejnego błędu.


Jeśli otwarte nawiasy klamrowe zostaną umieszczone osobno w wierszach, to każde miejsce, w którym dwie lub więcej linii są wcięte bez pary nawiasów, będzie wyglądać nieprawidłowo, podobnie jak każda niedopasowana para nawiasów. Takie użycie będzie kosztować pusty wiersz w przypadkach, gdy ifinstrukcja kontroluje blok, ale unikniesz potrzeby stosowania bloku w przypadkach, gdy ifinstrukcja kontroluje pojedynczą akcję, a nie blok.
supercat

14

Bardzo się cieszę, że:

foreach (Foo f in foos)
  foreach (Bar b in bars)
    if (f.Equals(b))
      return true;

return false;

Osobiście nie rozumiem dlaczego

foreach (Foo f in foos)
{
  foreach (Bar b in bars)
  {
    if (f.Equals(b))
    {
      return true;
    }
  }
}

return false;

jest bardziej czytelny.

Tak, wiersze są darmowe, ale po co przewijać strony i strony kodu, skoro rozmiar może być o połowę mniejszy?

Jeśli istnieje różnica w czytelności lub łatwości konserwacji, to oczywiście, wstaw nawiasy klamrowe ... ale w tym przypadku nie widzę powodu, aby to robić.

Poza tym zawsze będę umieszczać nawiasy klamrowe dla zagnieżdżonych ifów, w których zagnieżdżono inne

if (condition1)
  if (condition2)
    doSomething();
  else (condition2)
    doSomethingElse();

vs

if (condition1)
  if (condition2)
    doSomething();
else (condition2)
  doSomethingElse();

jest strasznie zagmatwana, więc zawsze piszę to jako:

if (condition1)
{
  if (condition2)
    doSomething();
  else (condition2)
    doSomethingElse();
}

O ile to możliwe, używam operatorów trójskładnikowych, ale nigdy ich nie zagnieżdżam .


właśnie widziałem, jak to prawie się dzieje w moim kodzie :) pomyślałem, że rozejrzę się dookoła i oto ... już tam jest :)
Noctis

10

Zgadzam się, że „jeśli jesteś na tyle sprytny, by skłonić kogoś, by zapłacił ci za pisanie kodu, powinieneś być na tyle sprytny, aby nie polegać wyłącznie na wcięciach, aby zobaczyć przepływ kodu”.

Jednak ... błędy mogą zostać popełnione, a ten jest trudny do debugowania ... zwłaszcza jeśli przychodzisz do kodu kogoś innego.


10

Moja filozofia jest taka, że ​​jeśli dzięki temu kod będzie bardziej czytelny, dlaczego nie?

Oczywiście musisz gdzieś wyznaczyć granicę, na przykład znaleźć to szczęśliwe medium między zwięzłymi i nadmiernie opisowymi nazwami zmiennych. Ale nawiasy naprawdę pozwalają uniknąć błędów i poprawiają czytelność kodu.

Można argumentować, że ludzie wystarczająco sprytni, by być programistami, będą na tyle sprytni, aby uniknąć błędów, które wynikają z instrukcji bez nawiasów klamrowych. Ale czy możesz szczerze powiedzieć, że nigdy nie wpadłeś na coś tak prostego jak błąd ortograficzny? Taka Minutia może być przytłaczająca, patrząc na duże projekty.


7
Oczywiście jest to bardzo subiektywne. Pozostawienie ich czasami poprawia czytelność.
Brian Knoblauch,

To prawda, jeśli kiedykolwiek zostawię nawiasy, zachowam jedną linię, jak wspominali inni. Zostałem ugryziony zbyt wiele razy, ale stwierdzenia zawierające wiele wierszy bez nawiasów. Nawet jeśli wiesz, jak na to uważać, czasami może cię dopaść.
James McMahon,

10

Zawsze są wyjątki, ale sprzeciwiłbym się pomijaniu nawiasów klamrowych tylko wtedy, gdy występuje w jednej z form:

if(x == y)
   for(/* loop */)
   {
      //200 lines
   }

//rampion's example:
for(/* loop */)
{
   for(/* loop */)
      for(/* loop */)
      {
         //several lines
      }
}

W przeciwnym razie nie mam z tym problemu.


4
Złe przykłady. W obu tych przypadkach uwzględniłbym tę 200 linii pętli w swojej własnej metodzie, a najlepiej na kilka metod.
Adam Jaskiewicz,

2
To prawda, ale to się zdarza. Ponadto za każdym razem, gdy blok jest dłuższy niż ekran czytnika jest wysoki, będziesz mieć ten problem. I nie możesz kontrolować wysokości ekranu swojego czytnika kodu. Mogą widzieć tylko kilka linii z każdej strony.
rampion

2
To się zdarza. To nie znaczy, że to powinno się wydarzyć.
Adam Jaskiewicz,

3
@AdamJaskiewicz Racja. To się zdarza. Musimy pomyśleć o tym, co się dzieje, a nie o tym , co powinno się stać. Gdybyśmy mogli ograniczyć się do tego, co powinno się wydarzyć, nie musielibyśmy martwić się o błędy.
Beska

10

Czasami używam bardzo dolnego kodu (wiele instrukcji using), ale poza tym zawsze umieszczam nawiasy klamrowe. Uważam, że dzięki temu kod jest bardziej przejrzysty. Jest oczywiste z czegoś więcej niż tylko wcięcia, że ​​instrukcja jest częścią bloku (a zatem prawdopodobnie częścią if itp.).

Widziałem

if (...)
    foo();
    bar();

błąd mnie ugryzł (a raczej „ja i koledzy” - właściwie nie przedstawiłem błędu) raz . Stało się tak pomimo faktu, że nasze ówczesne standardy kodowania zalecały używanie wszędzie nawiasów klamrowych. Zajęło mi to zaskakująco dużo czasu - bo widzisz to, co chcesz. (To było około 10 lat temu. Może teraz znajdę to szybciej).

Oczywiście użycie nawiasu klamrowego na końcu linii zmniejsza liczbę dodatkowych linii, ale osobiście i tak nie lubię tego stylu. (Używam go w pracy i uważam, że jest mniej nieprzyjemny, niż się spodziewałem, ale nadal jest trochę nieprzyjemny.)


Zawsze twierdzę, że konsekwencja jest ważniejsza niż rzeczywisty styl, dlaczego mielibyśmy robić wyjątek tylko w przypadku użycia?
Bob

@Bob: Słuszna uwaga, robię to tylko okazjonalnie. Nie chciałbym, aby udawać, że mam rzeczywiste powody tutaj :) Faktycznie, jest to rozsądny powód - zagnieżdżenie się usings (i tylko usings) jak to jest dość oczywiste, a ty nadal skończyć się w bloku. Nie widzę od razu niebezpieczeństwa.
Jon Skeet,

Co nie znaczy, że oczywiście nie ma żadnego niebezpieczeństwa.
Jon Skeet,

1
Najlepsze rozwiązanie tego błędu: użyj języka Python. (Oczywiście
żartuję

10

Jestem pod wrażeniem i pokorą, że moi rówieśnicy w tej dziedzinie programowania komputerowego (was, wielu) nie są zrażeni perspektywą potencjalnych błędów, gdy pominiesz nawiasy klamrowe w blokach jednowierszowych.

To chyba znaczy, że nie jestem mądry. Wiele razy popełniałem przy tym błędy. Debugowałem błędy innych w tym zakresie. Widziałem, jak oprogramowanie jest dostarczane z błędami z tego powodu (RDP do maszyny z VS2002 i czcionka w oknie zegarka nie będzie działać).

Jeśli spojrzę na wszystkie błędy, które popełniłem, których można było uniknąć, zmieniając styl kodowania, lista jest bardzo długa. Gdybym nie zmienił swojego podejścia w każdym z tych przypadków, prawdopodobnie nigdy nie zrobiłbym tego jako programista. Znowu, chyba nie jestem mądry. Aby to zrekompensować, przez długi czas byłem zagorzałym użytkownikiem nawiasów klamrowych na blokach jednowierszowych.

To powiedziawszy, na świecie zmieniły się pewne rzeczy, które sprawiają, że zasada „będziesz używać szelek na blokach jednowierszowych” jest dziś mniej aktualna niż wtedy, gdy Mojżesz sprowadził ją do nas:

  • W niektórych popularnych językach problem znika, zmuszając komputer do odczytywania wcięć, tak jak robi to programista (np. Python).

  • Mój edytor automatycznie formatuje dla mnie, więc szanse na wprowadzenie w błąd przez wcięcia są znacznie mniejsze.

  • TDD oznacza, że ​​jeśli wprowadzę błąd, ponieważ jestem zdezorientowany przez blok jednowierszowy, znacznie bardziej prawdopodobne jest, że szybko go odkryję.

  • Refaktoryzacja i ekspresyjność języka powodują, że moje bloki są znacznie krótsze, a bloki jednowierszowe zdarzają się znacznie częściej niż zwykle. Hipotetycznie, przy bezwzględnym zastosowaniu ExtractMethod, mógłbym mieć tylko jednowierszowe bloki w całym moim programie. (Zastanawiam się, jak to by wyglądało?)

W rzeczywistości bezlitosna refaktoryzacja i pomijanie nawiasów klamrowych w blokach jednowierszowych może przynieść wyraźną korzyść: kiedy widzisz nawiasy klamrowe, w Twojej głowie może zadzwonić mały alarm z napisem „tu złożoność! Uwaga!”. Wyobraź sobie, że to norma:

if (condition) Foo();   // normal, everyday code

if (condition) 
{
    // something non-trivial hapening; pay attention!
    Foo();
    Bar();
}

Otwieram się na pomysł zmiany mojej konwencji kodowania na coś w rodzaju „bloki jednowierszowe mogą nigdy nie mieć nawiasów klamrowych” lub „jeśli można umieścić blok w tym samym wierszu co warunek, a wszystko mieści się w 80 znakach, pomiń nawiasy ". Zobaczymy.


Jako były programista Java muszę w pełni zgodzić się z tym, że automatyczne formatowanie jest prawdziwą odpowiedzią na problem. Nie musisz nawet automagicznie dodawać nawiasów klamrowych do swojego edytora - samo automatyczne wcięcie może pomóc uniknąć niejednoznaczności. Oczywiście teraz, gdy przeszedłem na Pythona, przyzwyczaiłem się przede wszystkim do prawidłowego formatowania kodu.
Alan Plum

To samo czuję w przypadku aparatów ortodontycznych. Chodzi o złożoność. Idealnie byłoby, gdybyśmy mieli tylko jeden blok liniowy. To właśnie nazywam czytelnością, a nie zbędnymi nawiasami klamrowymi.
Igor Popov

9

Spośród trzech konwencji:

if(addCurleyBraces()) bugFreeSofware.hooray();

i:

if(addCurleyBraces())
    bugFreeSofware.hooray();

i (które reprezentują dowolny styl wcięcia przy użyciu otwierającego i zamykającego nawiasu klamrowego):

if(addCurleyBraces()) {
    bugFreeSofware.hooray();
}

Wolę ten ostatni jako:

  • Łatwiej jest mi się czytać, jeśli wszystkie instrukcje „jeśli” są zapisane w jednolity sposób.
  • Może to sprawić, że oprogramowanie będzie trochę bardziej niezawodne i wolne od błędów. Jednak wszystkie nowoczesne IDE i zaawansowane edytory tekstu mają ładne funkcje automatycznego wcięcia, których myślę, że każdy powinien używać, o ile nie psuje formatowania komentarzy ani nie jest sprzeczny ze standardami zespołowymi (w wielu przypadkach możliwe jest stworzenie niestandardowego schematu formatowania i podziel się nim z zespołem). Chodzi mi o to, że jeśli wcięcie jest wykonane poprawnie, ryzyko wprowadzenia błędu jest nieco zmniejszone.
  • Wolę, aby wyrażenie boolowskie i instrukcje do wykonania znajdowały się w różnych wierszach. Lubię mieć możliwość zaznaczenia wiersza do celów debugowania. Nawet jeśli używam IDE, w którym mogę zaznaczyć oświadczenie i przejść do niego, jest to operacja interaktywna i mogę zapomnieć, gdzie zacząłem debugować, lub przynajmniej zajmie mi to trochę więcej czasu, aby przejść przez kod kilka razy (ponieważ za każdym razem muszę ręcznie zaznaczyć pozycję podczas debugowania).

8

Twoje główne argumenty przeciwko używaniu nawiasów klamrowych to fakt, że używają one dodatkowych wierszy i wymagają dodatkowego wcięcia.

Linie są (prawie) wolne, więc minimalizacja liczby wierszy w kodzie nie powinna być celem.

Wcięcie jest niezależne od użycia nawiasów klamrowych. W twoim kaskadowym przykładzie „używania” nadal uważam, że powinieneś wcinać je, nawet jeśli pominiesz nawiasy klamrowe.


8

Mocno wierzę w pisanie uporządkowanego i zwięzłego kodu, ale zawsze używałbym nawiasów klamrowych. Uważam, że są one wygodnym sposobem szybkiego sprawdzenia zakresu, w którym istnieje określony wiersz kodu. Nie ma dwuznaczności, jest po prostu wyraźnie przedstawione przed tobą.

Niektórzy mogą powiedzieć, że jest to przypadek preferencji, ale uważam, że logiczny przepływ programu jest znacznie łatwiejszy do prześledzenia, jeśli jest wewnętrznie spójny, i nie uważam, że spójne jest napisanie takiej instrukcji IF;

if(x < y)
    x = y;
else
    y = x;

I jeszcze jeden taki;

if(x < y)
{
    x = y;
    x++;
}
else
{
    y = x;
    y++;
}

Wolę tylko wybrać jeden ogólny styl i się go trzymać :)


7

Jednym z głównych problemów jest, gdy masz regiony jednej wkładki i non-ONE wkładki wraz z oddzieleniem od statment kontrolnej ( for, if, co masz) i koniec statment.

Na przykład:

for (...)
{
  for (...)
    for (...) 
    {
      // a couple pages of code
    }
  // which for block is ending here?  A good text editor will tell you, 
  // but it's not obvious when you're reading the code
}

4
Dlaczego w ogóle masz kilka stron kodu w pętli for?
Adam Jaskiewicz,

b / c Jestem niewrażliwą bryłą i mam obsesję na punkcie pozbycia się „kosztu” wywołań funkcji. :)
rampion

4
Zwykle kilka stron kodu powinno znajdować się w osobnej funkcji.
Jonathan Leffler,

1
przepraszam, chodziło mi o to, że gram rolę takiej grudki. Uważam jednak, że ten sam problem może wystąpić w przypadku krótszych regionów, gdy ogląda się je przez mały obszar roboczy. A to jest poza kontrolą kodera.
rampion

7

Kiedyś byłem wielkim zwolennikiem „nawiasów klamrowych to MUSI!”, Ale od czasu przyjęcia testów jednostkowych stwierdziłem, że moje testy jednostkowe chronią instrukcje bez klamry przed scenariuszami takimi jak:

if (foo)
    snafu();
    bar();

Dzięki dobrym testom jednostkowym mogę śmiało pominąć nawiasy klamrowe w przypadku prostych instrukcji, aby poprawić czytelność (tak, to może być subiektywne).

Alternatywnie, w przypadku czegoś takiego jak powyżej, prawdopodobnie wstawiłbym to tak:

if (foo) snafu();

W ten sposób programista, który musi dodać bar () do warunku, byłby bardziej skłonny rozpoznać brak nawiasów klamrowych i dodać je.


2
Powiedziałeś „nie potrzebuję tego”, a potem podałeś powód, dla którego go użyłem: czytelność!
tvanfosson

4
Nie polegałbym na teście jednostkowym, aby to znaleźć. Może LINT, test jednostkowy nie!
Kristen

2
@Kristen - Ideą testu jednostkowego jest potwierdzenie zachowania metody. Jeśli zachowanie się zmieni (jak opisano powyżej), test jednostkowy zakończy się niepowodzeniem. Nie widzę w tym problemu.
Liggy

Ale po co polegać na teście jednostkowym, aby wykryć rażąco oczywiste, które należy naprawić przed przejściem do UT?
Andrew,

7

Skorzystaj z własnego osądu.

if (foo)
  bar();

sam w sobie jest w porządku. Chyba że naprawdę martwisz się, że kretyni wprowadzą coś takiego później:

if (foo)
  bar();
  baz();

Jeśli nie martwisz się kretynami, nic ci nie jest (nie jestem - jeśli nie potrafią poprawnie uzyskać podstawowej składni kodu, to najmniejszy z ich problemów)>

W zamian jest dużo bardziej czytelny.

Resztę czasu:

if (foo) {
  bar();
  baz();
}

Który był moim ulubionym, odkąd pamiętam. Do tego:

if (foo) {
  bar();
  baz();
} else {
  qux();
}

Pracuje dla mnie.

Sama przestrzeń w pionie nie jest szczególnie istotna, ale czytelność jest. Nawias otwierający w wierszu sam w sobie zatrzymuje rozmowę o element składniowy, dopóki oko nie przejdzie do następnego wiersza. Nie to, co mi się podoba.


Jedyny przypadek, w którym wolę pierwszy styl, to moment, w którym muszę natychmiast wrócić lub zgłosić błąd, jeśli coś jest nie tak. Lubię if (parameter == null) return null;.
nawfal

7

Okej, to jest stare pytanie, na które odpowiedziano na śmierć. Mam coś do dodania.

Najpierw muszę tylko powiedzieć, UŻYJ SZELEK. Mogą tylko pomóc w czytelności, a czytelność (dla ciebie i innych!) Powinna być bardzo wysoko na twojej liście priorytetów, chyba że piszesz asembler. Nieczytelny kod zawsze prowadzi do błędów. Jeśli okaże się, że nawiasy klamrowe powodują, że kod zajmuje zbyt dużo miejsca, Twoje metody są prawdopodobnie za długie. Większość lub wszystkie metody powinny mieścić się na jednej wysokości ekranu, jeśli robisz to dobrze, a Znajdź (F3) jest twoim przyjacielem.

Teraz do dodania: jest z tym problem:

if (foo) bar();

Spróbuj ustawić punkt przerwania, który zostanie uderzony tylko wtedy, gdy bar () ma zostać uruchomiony. Możesz to zrobić w C #, umieszczając kursor w drugiej połowie kodu, ale nie jest to oczywiste i jest trochę uciążliwe. W C ++ w ogóle nie można tego zrobić. Z tego powodu jeden z naszych najstarszych programistów pracujących nad kodem C ++ nalega na podzielenie instrukcji „if” na dwie linie. I zgadzam się z nim.

Więc zrób to:

if (foo)
{
    bar(); //It is easy to put a breakpoint here, and that is useful.
}

2
Kliknij prawym przyciskiem myszy na pasku i wybierz Wstaw punkt przerwania ... Nie jest wcale trudne. Poznaj swoje narzędzia.
Bob

Kliknięcie prawym przyciskiem myszy paska wskaźnika nic nie robi; masz na myśli kliknięcie prawym przyciskiem myszy w tekst? W każdym razie, jeśli chcesz, aby punkt przerwania został trafiony tylko wtedy, gdy instrukcja „if” jest prawdziwa, a „bar ()” znajduje się w osobnym wierszu, możesz umieścić kursor w dowolnym miejscu w tym wierszu i nacisnąć klawisz F9 lub kliknąć lewym przyciskiem myszy margines wskaźnika. Jeśli jednak cały kod znajduje się w jednej linii, musisz ustawić kursor na "bar ()" lub kliknąć prawym przyciskiem dokładnie tam przed naciśnięciem F9, a kliknięcie marginesu wskaźnika nie zadziała (umieszcza punkt przerwania na ' Jeśli'). Nie jest „trudne”, ale wymaga mniejszej koncentracji, gdy kod jest w dwóch wierszach.
kamień

Och, ha ha, kliknij prawym przyciskiem myszy „bar ()”. Miałeś na myśli tekst. Mam cię. Jasne, albo po prostu naciśnij F9 ...
kamień

>> musisz ustawić kursor na "bar ()" lub kliknąć prawym przyciskiem myszy dokładnie tam przed naciśnięciem F9 (miałem na myśli, aby ustawić kursor dokładnie tam przed naciśnięciem F9 lub prawym przyciskiem myszy)
kamień

7

aby kod z nawiasami klamrowymi nie zajmował dużo miejsca, stosuję technikę zalecaną w książce Code Complete :

if (...) {
    foo();
    bar();
}
else {
    ...
}

Nie rozumiem, dlaczego został obniżony, oszczędza jedną linię na każdą parę nawiasów, których używam przez cały czas
Eric,

2
Jest to bardziej znane jako styl K&R. Na podstawie książki The C Programming Language autorstwa Kernighan and Ritchie: en.wikipedia.org/wiki/The_C_Programming_Language_(book) . I nie powinno cię to zmodować.
jmucchiello,

Dzięki! Pomyślałem, że to tylko osobisty gust. Kiedyś uważałem tę składnię za irytującą, ale przyjąłem ją po przeczytaniu Code Complete i teraz naprawdę mi się podoba.
Nathan Prather

przeczytałem wszystkie powyższe odpowiedzi i pomyślałem „dlaczego nikt jeszcze tego nie zasugerował ???” Powoduje, że nawias zamykający jest wyrównany z blokiem, który jest zamykany, czyli „jeśli” lub „podczas gdy” itd., A nie bezsensownym „{”. +1.
nickf

Jeśli otwarte nawiasy klamrowe są zawsze umieszczane w wierszach same w sobie, to po znaku, po ifktórym następuje pojedyncza linia z wcięciem, można wizualnie rozpoznać, że kontroluje pojedynczą instrukcję bez potrzeby stosowania nawiasów. Styl otwartego nawiasu klamrowego sam w sobie oszczędza zatem białe znaki w sytuacji, gdy ifinstrukcja kontroluje coś, co jest semantycznie pojedynczą akcją (w odróżnieniu od sekwencji kroków, która zdarza się, że zawiera tylko jeden krok). Na przykład if (someCondition)/ `throw new SomeException (...)`.
supercat

6

Powiedzmy, że masz kod:

if (foo)
    bar();

a potem ktoś inny podchodzi i dodaje:

if (foo)
    snafu();
    bar();

Zgodnie ze sposobem zapisu, bar (); jest teraz wykonywany bezwarunkowo. Uwzględniając nawiasy klamrowe, zapobiegasz tego rodzaju przypadkowym błędom. Kod powinien być napisany w taki sposób, aby takie błędy utrudniały lub uniemożliwiały ich popełnienie. Gdybym przeglądał kod i zobaczył brakujące nawiasy klamrowe, szczególnie rozmieszczone w wielu wierszach, utworzyłbym defekt. W przypadkach, gdy jest to uzasadnione, trzymaj go w jednym wierszu, aby szansa popełnienia takiego błędu była ponownie ograniczona do minimum.


Ten punkt został już poruszony w pytaniu.
Mike Scott

Właściwie nie do końca. Tak, wspomniał o potencjale tego rodzaju błędów, ale mówiłem o zabezpieczeniu kodu przed błędami i usunięciu potencjalnych błędów w ramach najlepszych praktyk.
Elie

Czy naprawdę istnieje coś takiego jak kod zabezpieczający przed błędami?
Bob

Nie, ale możesz to utrudnić. Przeczytaj „Najlepiej strzeżone tajemnice wzajemnej weryfikacji kodu” autorstwa Jasona Cohena (patrz łącze z boku niektórych stron tutaj), aby lepiej zrozumieć, dlaczego to robisz.
Elie,

Kim jest ten Mike Scott i dlaczego jest policją? Zawsze mnie wkurza, że ​​ludzie muszą mówić to, co oczywiste. Dlaczego więc Mike nie skomentował dodanego opisu, który użytkownicy piszą na ten temat. Czy wszystkie odpowiedzi nie odnoszą się do pytania?
bruceatk,

6

Redukcja linii nie jest dobrym argumentem za porzuceniem nawiasów klamrowych. Jeśli Twoja metoda jest zbyt duża, prawdopodobnie powinna zostać ponownie podzielona na mniejsze części lub zrestrukturyzowana. Takie postępowanie bez wątpienia zwiększy czytelność bardziej niż zwykłe zdjęcie aparatu.


5

Zawsze je pomijam, gdy jest to stosowne, na przykład w twoim pierwszym przykładzie. Czysty, zwięzły kod, który widzę i rozumiem, patrząc na niego, jest łatwiejszy do utrzymania, debugowania i zrozumienia niż kod, który muszę przewijać i czytać wiersz po wierszu. Myślę, że większość programistów się z tym zgodzi.

Łatwo wymknąć się spod kontroli, jeśli zaczniesz wykonywać wiele zagnieżdżeń, klauzule if / else itd., Ale myślę, że większość programistów powinna być w stanie powiedzieć, gdzie narysować linię.

Widzę to tak jakby argument dla if ( foo == 0 )vs if ( 0 == foo ). Ta ostatnia może zapobiec błędom dla nowych programistów (a może nawet czasami dla weteranów), podczas gdy ta pierwsza jest łatwiejsza do odczytania i zrozumienia, gdy utrzymujesz kod.


4

W większości przypadków jest zakorzeniony jako standard kodowania, czy to dla firmy, czy dla projektu FOSS.

Ostatecznie ktoś inny będzie musiał zagłębić się w twój kod, a każdy programista musi spędzić dużo czasu, aby dowiedzieć się, jaki jest określony styl sekcji kodu, nad którym pracuje.

Wyobraź sobie również, że ktoś przechodzi między Pythonem a językiem Cish więcej niż raz dziennie ... W Pythonie wcięcia są częścią symantyki bloków tego języka i łatwo byłoby popełnić błąd podobny do tego, który zacytowałeś.


+1 za komentarz na temat Pythona. Zawsze jestem zdumiony, jak „głupi” potrafię być, kiedy ciągle przełączam się między językami.
Kena,

3

Po stronie bezpieczniejszego - jeszcze tylko jeden błąd, którego potencjalnie nie będziesz musiał naprawiać.

Osobiście czuję się bezpieczniej, jeśli wszystkie moje bloki są owinięte w kręcone. Nawet w przypadku jednowierszowych są to proste zapisy, które łatwo zapobiegają błędom. Sprawia, że ​​kod jest bardziej czytelny w tym sensie, że wyraźnie widzisz, co jest w bloku, aby nie mylić treści bloku z następującymi instrukcjami poza blokiem.

Jeśli mam jedną linijkę, zwykle formatuję ją w następujący sposób:

if( some_condition ) { do_some_operation; }

Jeśli linia jest po prostu zbyt uciążliwa, użyj następującego:

if( some_condition )
{
    do_some_operation;
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.