Върл привърженик съм на идеята, че няма значение каква е конвенцията, стига да се спазва от всички в екипа с религиозен фанатизъм. Дори веднъж, когато приготвях pull request за един проект, се усъмних, че не съм съвсем в тон със стилистиката му. Прегледах кода още веднъж, и установих, че автора никъде не е ползвал unless
– вместо това навсъкъде прави if !
. Никак не бях съгласен с тази идея, но това не бе моя проект и послушно заместих моя unless
с неговия if !
преди да отворя PR-а. Но има една конвенция, която не ми се е налагало да следвам, и ми е трудно да си представя как бих я понесъл.
Говоря за отваряща „къдрава“ скоба на нов ред. Така и не схванах защо някой би предпочел да го прави. Но след като препрочетох K&R, мисля че разбрах откъде идва.
За щастие, това в днешно време се прави предимно в продуктите на Microsoft и някак ми се разминава да работя с така подреден код. Нито ми се струва по-информативно визуално, нито ми е по-лесно да разпознавам блоковете, нито мога да си представя някаква естетическа причина, поради която бих намерил това за „по-красиво“. С каквито и очи да гледам кода, всеки път се чудя защо трябва да се похабява по цял отделен ред.
Препрочитайки K&R, останах с впечатлението, че причината тази конвенция да се появи, е причината за повечето странни неща в софтуера – legacy.
В книгата дефинират функции така:
{
int i;
for (i = 0; i < size; i++) {
printf("%s\n", names[i]);
}
}
Забележете как само отварящата скоба на print_strings
е на нов ред. Тази на for
– и на if
, while
и прочее – е на същия ред. Причината за това? Промени в C стандарта.
Достолепния ANSI C стандартизира определянето на типове при параметрите на функции, при това, във вида по-горе. В по-ранните години на езика е ставало по следния начин:
char **names;
int size;
{
int i;
for (i = 0; i < size; i++) {
printf("%s\n", names[i]);
}
}
Докато в днешно време ще се озорите да намерите компилатор, който изисква втория стил, едно време далеч не е било така (под „едно време“ разбирайте „преди повечето от нас да се родят“). В тази нотация е съвсем естествено скобата да е на отделен ред. Колкото и субективни да са естетическите въпроси, навярно всички ще се съгласим, че това скобата да стои след int size;
би било „грозно“.
Тази времена са отдавна отминали, обаче, и сега първия стил е далеч по-приет. Всъщност, не се съмнявам втория стил да изненада немалко съвременни C програмисти. Въпреки това, тази конвенция не просто е намерила начин да оцелее, но и да се разпространи до другите конструкции, където въобще не е нужна.
Не успях да намеря друг източник на тази толкова странна според мен практика. Докато това не доказва нищо, не мога да не си мисля, че е една от страните в една от старите безполезни „религиозни войни“ (подобно на vi vs. Emacs) защитава legacy позиция. И докато бих спазвал тази конвенция, макар и с огромно неудоволствие, едва ли ще мога да се оттърся от усещането, че не режа краищата на ястието без причина.
А вие знаете ли друга, по-правдовоподобна история, за отварящата скоба на нов ред?
Продължавам да не разбирам защо държите на ръка да форматирате кода си.
Съжалявам, практиката ми показва, че във всеки екип в който съм бил, наличието на автоформатър при всички от екипа, който on Save се оправя с всички подобни тривиални неща, ни освобождава главите от подобни „велики“ полемики. Всичко е консистентно. Винаги. Всички са щастливи. Zero cognitive effort. End of story.
Не виждам връзката между „ръчното форматиране“ на кода и конвенцията, която се спазва. Не виждам и полемика, но това е друг въпрос 🙂
Също, предполагам, че пишеш на C# или Java, където положението с такива инструменти е доста приятно. В много други езици обаче, нямаш адекватни инструменти, които да форматират кода автоматично. Впрочем, Go има много хубаво решение на този въпрос – още със създаването си върви с инструменти за форматиране и съществуващия Go код е изключително консистентен.
Но ситуацията в ред други (при това популярни) езици не е такава. И отново, това дали имаш такъв инструмент и как той подрежда са две различни неща.
Кода най-визуално се възприема на блокове. Като има доза смисъл, заглавието и съдържанието да са два различни такива.
Следния пример: https://gist.github.com/sovanesyan/8351453
Аз съм привърженик на новия ред, и ми изглежда като най-хигиеничното и чисто нещо на света.
That being said, ако заглавието имаше по-ярко и открояващо оцветяване може би нямаше да мисля така. Не бих се и налагал в съществуващ проект.
Бъси кефа, в нашто семейство легендата е с точените кори на баницата, които винаги се замятат в края на тавата!
За мен скоба на отделен ред позволява по-лесно визуално ориентиране и по-добър изглед върху кода. Също така ми изглежда по-естествено – скоба на същия ред ми изглежда все едно кодът изкуствено е сгъчкан т.е. ето така:
int x; a = 42;
Единственият плюс, който виждам на скоба на същия ред е, че позволява повече код да се вижда без scroll-ване. Същата логика обаче е приложима и в горния пример.
Python се справя с този религиозен спор доста елегантно 🙂
Дали кода изглежда сгъчкан или не е отвсякъде въпрос на навик. Ако си свикнал с едното, другото ще ти изглежда странно. Аз (почти) никога не съм ползвал тази конвенция и скобата на нов ред ми изглежда объркващо и заемащо място. Също, струва ми се, че блока няма нищо общо с конструкцията преди него. В крайна сметка:
…
}
е валиден начин да създадеш лексикален scope – именно това очаквам, като видя отваряща скоба на отделен ред.
Серж Ованесян е прав. Наистина кода най-добре се възприема на блокове, но не виждам какъв му е проблема на варианта без нов ред за отварящата скоба. Не само, че е достатъчно ясен (тялото е отместено навътре в отделен блок), ами даже и реда със затварящата скоба на мен ми е малко излишен (може би заради Python, но това е друга тема).
А отностно оцветяването на заглавието – това не е проблем на форматирането, а на цветовата схема която се ползва. При подходяща такава прекрасно си разбираш кое какво е.
Ето моя теория по въпроса.
В C отварящата къдрава скоба е многозначна. Тя може да означава като then в условен оператор, do в for..do или while цикъл, но така и begin във функция и процедура.
Затварящата къдрава, скоба обаче не е – тя изпълнява ролята на end/stop на блок от код, независимо дали този блок е процедура, условен клон или цикъл.
Традицията е begin инструкцията да се изписва на нов ред. Бих предположил, че това е заради по-голямото логическо значение на този блок от код.
От друга страна условния и оператора за цикъл са помощни инструменти, в контекста на самостоятелен блок от процедурен код. В тях смислената част е самия оператор, който е на нов ред, а не синтаксиса, който завършва началото на оператора (then или do).
За това, че начинът по който ти изглежда един код (сгъчкан, неестествен и прочие) е въпрос на навик си прав – аз минах от скоба на същия ред към скоба на нов ред преди много години и спомените ми са, че скоба на нов ред тогава ми се струваше също толкова неестествена и неприятна за четене колкото скоба на същия ред сега. Моето лично впечатление – скоба на нов ред по-отчетливо разделя визуално съдържанието на блока (действието което се изпълнява) от неговият „header“ (условието при което се изпълнява това действие). Това ми помага да се ориентирам по-добре при бързо скролване през голямо количество код. Виждал съм ‘скоба-на-същия-ред’ код в който в началото на всеки блок оставят по един празен ред, предполагам със същата цел.