Нужен ли стандарт разработки?

Автор оригинала: Avdi Grimm
Вольный перевод статьи «Should we use a coding standard?» из блога «Virtuous Code» Avdi Grimm. Мнение автора оригинальной статьи может не совпадать с мнением редакции.
Примечание переводчика: лично я согласен с автором.



Avdi, должны ли мы использовать стандарт разработки?

Да.

Какой стандарт нам использовать?

Не думаю, что есть какой-то один «правильный» стандарт. Каждый проект должен выработать свой стандарт на основе своих нужд и предпочтений разработчиков.

Думаю, что разнообразие стилей в сообществе хорошо. Это хорошо даже для большой организации.

Когда я работал в такой организации, у нас была пара рекомендованных стандартов для любого используемого нами языка. Но окончательный выбор стандарта для каждого нового проекта оставался на совести тимлида.

Я думаю, что выбор стандарта для каждого конкретного проекта — хорошая детализация. Таким образом, у каждого отдельно взятого репозитория и каждой команды может быть отдельный стандарт.

Как нам выбрать стандарт разработки?

Многие сообщества языков программирования уже выработали общие стандарты. К примеру, если вы пишете код на C, вы можете выбрать стандарт разработки GNU. Или если вы разрабатываете на Ruby, вы можете использовать стандарт сообщества, поддерживаемый Божидаром Бацовым: Bozhidar Batsov’s community-influenced standard.

Эти стандарты — плод мыслей и дебатов сообщества. Поскольку соглашения, входящие в эти стандарты, основаны на решении большинства, это хорошая точка отсчета.

Но некоторые решения в этих стандартах — глупые и неправильные!



Истина. Поэтому я и говорю, что стандарты сообщества — хорошая отправная точка. Когда у вашей команды есть четкие возражения по определенным соглашениям в стандартах — наступает время для модификации стандарта под свои нужды.

Наша команда разделилась пополам в выборе определенного пути! Как я могу убедить другую половину?

Будем честны: очень маловероятно, что команда действительно разделилась пополам. Обычно есть один-два человека с одной стороны и примерно столько же с другой, остальная же команда не выбирает ни одну сторону.

Хорошо, так как мне убедить этих людей по другую сторону баррикад?

Уверенность другой стороны могут поколебать хорошо обоснованные, реальные примеры того, что ваш вариант изящнее раскрывает суть кода, лаконичнее пишется или лучше показывает опасные места.

Это не так, просто мой стиль красивее. В любом случае, это более идиоматичный подход.

После многих лет знакомства с разными стандартами разработки я могу сказать, что сильнее всего на отношение к стандарту влияет знакомство с этим самым стандартом. Даже не помню, сколько раз я приходил в проект со стандартом, который я просто ненавидел, но после шести недель работы переставал об этом беспокоиться. Иногда я даже использовал его как новый стандарт для собственных проектов.

Например, когда я начинал разрабатывать на C++, я выравнивал фигурные скобки так, чтобы можно было посмотреть выше и сразу увидеть открывающую скобку в той же колонке:

int main(int argc, char** argv)
{
    std::cout << "Hello, world!";
}


Позже я встретился с кодом в стиле GNU/GNOME, где открывающая скобка стоит на строке с объявлением метода. Аргх!

int main(int argc, char** argv) {
    std::cout << "Hello, world!";
}



Я пожал плечами и продолжил. Вариант в GNU-стиле даже показался мне предпочтительнее.

Мне встречалось множество примеров кода вроде «А против Б», где вариант Б представляли объективно красивее варианта А. Большую часть времени мне было сложно увидеть разницу, которую автор полагал очевидной.

В Ruby популяризованное Rails соглашение о выборе между фигурными скобками и do...end, основанное на количестве строк кода внутри блока, немного глупо. Мне говорили, что одна из причин такого соглашения в том, что do...end на одной строке объективно выглядит ужасно:

h.fetch(:some_key) do raise ":some_key is required" end


Лично я не вижу ничего плохого в этой строке. Объективные эстетические суждения плохи в качестве правил.

Стоит помнить, что «стандартный» синтаксис языка обычно немного странный в начале. Например, в каждом основанном на C языке мы обозначаем «сообщение» или «аттрибут» примерно так:

farm_boy.fetch_me_that_pitcher()


Так как это слова на английском, давайте рассмотрим это с точки зрения английского языка.

Точка обычно указывает конец предложения, или разделитель между целой и дробной частью числа. Здесь она стоит на том месте, где обычно мы ставим запятую:

"Farm boy, fetch me that pitcher"


Или двоеточие:

"Farm boy: Fetch me that pitcher!"


Тем временем слова отделяются друг от друга символом, которого новички вообще не знают. Я уже даже не хочу думать о кавычках.

Окей, хорошо, стиль субъективен. Но некоторые вещи действительно делают код проще, или ошибки заметнее!

Да, думаю это так.

И мой тимлид делает неверный выбор!!

Возможно, что у вас действительно есть хорошие, целостные, ориентированные на качество кода аргументы в пользу определенного стиля. И вопрос выбора стандарта действительно может развести вас и вашу команду по разные стороны баррикад.

Есть один важный вопрос, который необходимо задавать себе, ратуя за выбор определенного стиля кода. Это настолько важно, что я напишу его отдельной строкой.

Как дорого проекту обойдется ваша правота?



Давайте посмотрим: вы полностью правы насчет выбора стиля или практики разработки. Ваши оппоненты неправы и глупы.

Но спросите себя, сэкономит ли ваша правота достаточно, чтобы компенсировать:
  • Потраченные часы всей команды на совещания касательно стиля, которые не заканчиваются ничем толковым?
  • Потерю хороших отношений как результат столкновений лбами на этих совещаниях?
  • Цену огромных цепочек в почте с обсуждениями плюсов и минусов разных стандартов?
  • Злость и гнев вашей команды, когда они будут вынуждены следовать стилю, который им не нравится, но который им в итоге навязали?


Некоторые стандарты разработки стоят всего этого. Но я рекомендую хорошо подумать, прежде чем бросаться в бой.

Стандарты разработки предохраняют от дурных привычек, но в чем их главный плюс?

Стандарты разработки дают программистам, особенно неопытным, определенную защиту от дурных привычек, но я не считаю это главным преимуществом. Для меня главный выигрыш от стандартов — это последовательность.

Сравним два блока кода на Ruby:

# Block #1
output = []
while word = input.shift
  unless STOP_WORDS.include?(word.downcase)
    output << word
  end
end


# Block #2
output = input.map(&:downcase) - STOP_WORDS


Очевидно ли на первый взгляд, что оба блока делают одно и то же? Более важно: очевидно ли, что несмотря на аналогичную функциональность, блоки имеют мелкое, но важное различие?

Реальная ценность стандарта разработки в том, что он делает похожие вещи похожими, а разные — разными. Такая последовательность помогает команде быстрее понимать суть написанного кода. В свою очередь это означает, что они могут работать на более высоком уровне абстракции большую часть времени.

Как это понимать для легаси-кода? Должны ли мы обновлять каждый файл в проекте под новый стандарт?

Одним словом — нет. Не вижу никакой пользы в том, чтобы потратить часы на обновление каждого файла в проекте строчка за строчкой согласно новому стандарту разработки. Это не стоит тех затрат времени и усилий, и может принести новые баги в легаси-код.

Что, если я вношу изменение в легаси-код? Должен ли я обновить весь файл, раз уж я за него взялся?

Мой ответ отличается от общепринятого мнения и порой удивляет людей.

Ответ — нет. Обновление стиля легаси-кода потребует времени, создаст большой diff и увеличит шанс случайной регрессии.

Значит ли это, что я должен использовать новый стиль только в новых или измененных участках кода?

Давайте конкретизируем вопрос. Представьте, что это кусок легаси-кода:

STOP_WORDS = [
  'i',
  'we',
  'if',
  'and',
  'the'
]


Предположим, ваша задача — добавить слово «they» в список. И по новому стандарту разработки все строки должны обрамляться двойными кавычками.

Нужно ли обновить весь список в процессе добавления нового слова?

STOP_WORDS = [
  "i",
  "we",
  "if",
  "and",
  "the",
  "they"
]


Или применить новый стандарт только для добавленной строки?

STOP_WORDS = [
  'i',
  'we',
  'if',
  'and',
  'the',
  "they"
]


Как я говорил раньше, для меня ценность стандарта — сохранение последовательности. Последовательность важна на уровне проекта, но она важна и на уровне файла. Поэтому я не думаю, что стоит следовать новому стандарту, когда вы обновляете файл, написанный по старому стандарту. Напротив, если в файле уже есть последовательный стиль оформления, вам стоит постараться выдержать его.

Это значит, что если слова в списке обрамлены одиночными кавычками, вы должны добавить новое слово в одиночных кавычках.

STOP_WORDS = [
  'i',
  'we',
  'if',
  'and',
  'the',
  'they'
]


Если вы часто обновляете файл с легаси-кодом, тогда мне кажется хорошей идеей запланировать обновление конкретно этого файла по новым стандартам. Но не думаю, что стоит превентивно обновлять малоиспользуемые файлы. И я не поддерживаю локально несогласованные изменения только ради того, чтобы оставаться в рамках стандарта.

___

Что думаете о стандартах разработки? Какие стандарты применяете? Рассказывайте.
GeekBrains
ОБРАЗОВАТЕЛЬНАЯ ПЛАТФОРМА

Комментарии 108

    +3
    Я думаю, что все общепризнанные стандарты имеют право на существование. А вот что не надо делать — так это изобретать свои стандарты, например, один мой коллега закрывающие фигурные скобки пишет в одной строке. Читается это противно. А другой коллега напротив КАЖДОЙ строки пишет комментарий, что она делает — по сути дублирование кода на русском языке. Читается еще противнее.
      0
      Вы просто привязались к своему стандарту. Автор хорошо сказал: «сильнее всего на отношение к стандарту влияет знакомство с этим самым стандартом». То, что вы считаете свое мнение константой — в корне неверно.
      К примеру мне нравится, когда комментарии есть напротив каждой строки также, как и краткое описание класса до его начала.
        +1
        Я привязался не к своему стандарту, а общепризнанным. Даже венгерскую нотацию и то признаю. А теперь представьте реальный проект, в котором напротив каждой строки идет комментарий. Как минимум, это усложняет внесение правок: помимо правки кода, я должен изменить комментарий, а также выровнять их по горизонтали. Комментарий должен пояснять код и разъяснять неочевидные места, а не дублировать весь код:
        int calcSum(int[] elements)                         // Метода для подсчета суммы элементов в массиве
        {
            int result = 0;                                 // Объявим результирующую переменную result
            for (int i = 0; i < elements.Length; i++)       // Для каждого i от 0 до длины массива elements
            {
                result += elements[i];                      // Прибавим к result i-тое значение массива elements
            }
            return result;                                  // Возвратим значение result
        }
        
          0
          Смотря какой язык. Для мнемокода (ассемблер) это почти стандарт.
            0
            Да, но здесь речь не про асм идет.
      +8
      Могу сказать только о том, что каждый раз, когда я делаю ревью древнего legacy-класса, в котором какой-то добрый человек автоформаттером IDE подогнал всё под текущие стандарты, у меня неистово бомбит.
      Хотя бы потому, что конкретные изменения по таску найти сложновато.
        +4

        Для этого для автоформата legacy обычно делают отдельный коммит.

          +2
          Ключевое слово «обычно».
            0
            ключевое слово «делают» :)
          +1
          Надо в 2 коммита делать. 1 коммит — работа автоформаттера (которую ревьюить смысла нет), второй коммит уже, собственно, изменения.
            0

            Это полбеды. Когда еще заботливый форматтер переставляет декларации в файле в "правильном" порядке, какие-либо изменения вообще отследить невозможно, ломается даже "Show Git history for method"

          • НЛО прилетело и опубликовало эту надпись здесь
              +1
              А можно конкретнее чем json непригоден?
                +5

                Отсутствие комментов, один вид кавычек, необходимость эти кавычки ставить в ключе, отсутствие trailing comma (это когда нельзя делать так: [1, 2, 3,]), скудность типов. Это из того, что сразу вспомнилось.

                  +3
                  Вы перечислили несколько важных преимуществ JSON'а, которые, собственно, людей к нему и привлекают и облегчают его использование — в чём проблема-то?

                  P.S. Вы, возможно, хотели сказать, что JSON не слишком удобен для написания его человеком — что, отчасти, правда, но… наши недостатки — продолжение наших достоинств. Там где удобство чтения/разбора важнее удобства напиcания (то есть почти везде) всё, что вы перечислили — достоинства.
                    +2
                    Отсутствие комментов

                    1. Комментарии свели бы всю красоту лаконичности формата к нулю.
                    2. Формат является «обрезанным» способом записи объектов в JS и предназначается скорее для общения техники, нежели людей.
                    3. В JS комментарии были.
                    4. Пришлось бы изобретать еще одну форму записи.
                    5. Привело бы к усложнению (и замедлению) парсеров.
                    6. Поскольку формат свободный (в том смысле, что нет аналога схем xsd и dtd), то ничто не мешает добавить «лишние» данные в качестве комментариев.
                    один вид кавычек

                    Единообразие — прекрасно! Кстати, в статье обсуждался этот вопрос, в абзаце про legacy.
                    необходимость эти кавычки ставить в ключе

                    Скорее, для совместимости с JS, чтобы не ломать голову ни человеку, ни машине, как интерпретировать ключ.
                    отсутствие trailing comma

                    Опять же, для упрощения интерпретации, обход возможных неоднозначностей (не понимать ли запись ",]" как еще один пустой элемент?)
                    скудность типов

                    А зачем в данных разнообразие типов? Не думаю, что в JSON очень уж нужно различать знаковые и беззнаковые целые, например.

                    Т.е. JSON как формат, не слишком нуждающийся в упаковке (скажем, сравните с избыточностью XML) прекрасно справляется со своей функцией краткой записи данных и простоты разбора\генерации, не потеряв при этом в читабельности. Это как раз то, почему он так популярен, вовсе не «Совершенно непригодный для промышленной разработки академический стандарт».

                    Кроме того, он совсем не мешает жить другим не менее популярным форматам, таким, как HAML\YAML, например. Тем не менее, и они имеют свои преимущества и свои недостатки, а потому и используются совсем не там, где JSON, там бы они не подошли.

                    Ну и наконец, популярность != засилие, не надо, пожалуйста, вот этого " И как будто так и надо. Пофигизм и безволие."
                    • НЛО прилетело и опубликовало эту надпись здесь
                        +1
                        Соглашусь, что так было бы удобнее… Если бы было… Ну а на «нет» и суда нет, как уж получилось.
                          0
                          Не было бы так «удобнее». Вот как раз все рассуждения выше выдают их академичность. «В траффик» он их пускать не будет, ага. Свободы и стандарта он хочет. Какого стандарта? Такого?
                          <html>
                              <body>
                                  <script type="text/javascript">
                                      //<!--
                                      document.write("Hello World!");
                                      //-->
                                  </script>
                              </body>
                          </html>
                          

                          А ведь недавно куча сайтов так выглядели — и в книжках именно так рекомендовали писать.

                          Ещё раз: либо комментариев у вас в стандарте и в соответствующих документах нет (а тогда и вырезать нечего), либо они есть — а тогда их под что-нибудь важное приспособят (и тогда они, по большому счёту, перестанут быть комментариями — но мы вроде о практике тут говорим, а не об академических изысках).

                          Отсутствие комментариев в JSON — это очень важное практичнеское преимущество этого стандарта. Если конкретно в вашей программе вы хотите-таки иметь комментарии — ну так разрешите их, это-то как раз несложно.

                          Но таки именно то, что куча парсеров не признают комментариев и гарантирует, что всевозможные шаблонизаторы (где комментарии могут быть как раз вполне уместны) вырежут комментарии до того, как файл превратится в конечный JSON, который вы будете отдавать кому-то ещё и «в траффик» они не пойдут — что может быть практичнее?

                          Кстати о практичеости. Заметьте, что JSON пришёл в мир, где всё уже было «предрешено»: «все идут в XML, всё идёт в XML, везде будет XML». В 2001м, когда JSON появился, уже были и XML-RPC/SOAP и XHTML и куча других вещей. И там было и «разнообразие» и «валидация» и много всего другого. И даже комментарии, кстати.

                          А потом появился JSON — и прочие языки обмена данными стали почему-то менее популярны. Можно долго спорить — почему это произошло, но говорить о том, что это «академический стандарт» — это уже Оруэлл: JSON был «слеплен из того, что было» и решал практические задачи — какая ж тут академичность?

                          Вот «хотелки» не решающие ровным счётом ни одной задачи и исходящие из того, что люди будут обладать свободой и при этом будут соблюдать стандарты (ага, щаз: это же люди, а не ангелы) — вот это как раз «академичный подход», не имеющий к практике никакого отношения.

                          Потому что у вас получается, что если Google переводит GData в 2005м с XML на JSON, то это происходит потому, что JSON в 2016м используются «буквально везде». У нас тут не Океания пока и логика «Океания всегда воевала с Остазией» не работает: всё-таки причина появляется перед следствием. Если в 2005м GData начинает поддерживать JSON — то это происходит потому, что он был удобнее, чем альтернатива, а не потому, что в 2016 JSON используется «буквально везде».

                          P.S. Используется «буквально везде» — кстати отличный пример практического довода. И хотя он не перешибает всех других доводов (иначе бы и на JSON никто переходить не стал и переход на IPv6 не происходил бы), но он — действительно весьма весом. Когда вы приходите со своими идеями «а давайте миллионы компаний потратят миллиарды долларов, чтобы я смог получить экономию в три секунды и десять центов», то ваши предложения отвергаются не из-за того, что кругом «пофигизм и безволие», а просто потому что людим кругом умеют считать деньги и время. Чего вы, похоже, babylon делать не научился пока.

                          P.P.S. Кстати форматы далеко не все остаются в неизменном состоянии. В качестве примера — посмотрите на Markdown и его превращение в CommonMark. Вот там совместимость — не была основным достоинством формата и потому расширения было делать проще. Однако в конце-концов это изрядно всех «достало» и стандарт всё же появился. Посмотрим — приживётся ли. А у JSON'а — его простота, лаконичность, неизменность и совместимость (сначала с JavaScript/ActionScript, сейчас — с сотнями, если не тысячами, парсеров) — это основное достоинство. Неудивительно, что идеи отказаться от него в угоду секундной экономии отвергаются! Где вы тут видите «академичность»?
                        0
                        >А зачем в данных разнообразие типов?
                        Попробуйте написать проект, где вам нужны даты/timestamp, которых в json нет. Скорее всего ваше мнение изменится довольно быстро.

                        Целые тут ни при чем совершенно — речь про то, что те типы, которых в языке нет, очень сложно однозначно восстановить при разборе, потому что я JSON нет и метаданных для типа, в том числе. Т.е. без схемы вы не можете понять, это вам пришло число, или дата в виде количества миллисекунд от начала эпохи, пришла строка или опять же дата в формате ISO 8601.
                          0
                          Таки да, JSON не предназначен для разрбора программой, которая о нём ничего не знает. И? Любой другой формат может добиться такого же успеха. Ну знаете вы, что в формате есть поле useWord97LineBreakRules и у него два значения — дальше что?
                    +1
                    Нет ничего идеального. Но альтернатив с подобным соотношением простота/удобство/понятность/читаемость/однозначность как-то не видно. XML это ад в сравнении с JSON.
                      –4
                      Например yaml.
                        +1
                        yaml еще хуже, там нужно пробелы правильно расставлять. JSON в этом плане в миллион раз удобнее.
                    +3
                    There are a two kind of people
                    Простите, это на каком языке?
                      +2
                      Очевидно, на английском. Возможно, на английском с ошибками. Вероятно, должно было быть ...kinds…
                        +4
                        По идее, ещё артикль лишний. Мысль о том, что в статье, переведённой с английского, на видном месте большими буквами может красоваться надпись на том же английском сразу с двумя ошибками, показалось мне настолько невероятной, что я решил уточнить, правильно ли определил язык.
                          0
                          Возможно, у них программисты тоже имели не самую высокую оценку по английскому языку в школе)
                          Возможно, картинка была подготовлена рано утром или поздно вечером. Я тут в обед прочитал, что я написал рано утром на форуме — так у меня там тоже возникли вопросы к себе, насчет того, является ли русский язык мне родным или нет… Было стыдно.
                      +2
                      three

                      if cond:
                        return
                      
                        0
                        а так же
                        if (cond) return;

                        и
                        return if cond;
                          0
                          Это вообще не то
                            +3
                            Мой любимый пример из личной практики на тему фигурных скобок в однострочниках:
                            if (logger.isLoggable(Level.DEBUG))
                            // level.debug("someDebugMsg");
                            doSomethingValuable();
                            

                            Собственно, когда система вышла в production и настройки логгинга были изменены, баг внезапно и вылез.
                            Что касается конкретно Вашего примера — тут в целом ок, т.к. условие и действие в одну строку.
                              –2
                              Такие вещи должны тестами ловиться.
                                +5
                                каждую сточку тестами не покроешь.
                                  0
                                  это do_something_valuable вы тестами не поймаете? тогда это совсем не valuable.
                                    0
                                    имхо, вы неправильно тестируете, если считаете что тест — это проверка каждой строки функции на то, выполнилась ли она
                                  +7
                                  Это как раз типичный пример того, когда простейшее стилистическое правило (всегда использовать фигурные скобки для блоков) позволяет избежать целого класса проблем.
                                    –2
                                    Это как раз прекрасный пример где тест должен проверить что функция do_something_VALUABLE вызывается. Может вы еще правило йоды юзаете?
                                      +1
                                      Вы реально пишете отдельный тест на каждый вызов в каждой функции? (Я подразумеваю, что типичные сценарии работы и так покрыты тестами).

                                      И вы реально предпочитаете вместо чуть другого стиля кода писать дополнительные тесы дополнительными тесты?
                                        +1

                                        подразумевается, что если это действительно valuable, то оно должно быть покрыто хоть каким-нибудь (unit/integration/acceptance) тестом

                                          0
                                          Хорошо, если там действительно существенная часть бизнес-логики, то да, она будет покрыта тестами и пролема отловится. Но что, если там что-то второстепенное? Например освобождение памяти или другого ресурса? Т.е. тоже valuable, но, возможно, не покрытое непосредственно тестом?
                                            0
                                            Тесты на утечку памяти…
                                          • НЛО прилетело и опубликовало эту надпись здесь
                                      +1
                                      Конкретно в этом куске кода тест скорее всего был бы успешен (в тестах обычно дебаг-логирование)
                                        0
                                        Хорошие инструменты для измерения покрытия показывают еще и покрытие кода по условиям.
                                          0

                                          не всегда. тесты должны быть максимально приближены к живому коду, иначе теряется их смысл

                                        –1
                                        Могу поделиться своим стандартом. Фигурные скобки ставить не надо только если if без else, если условие короткое и тело короткое. При этом перенос на новую строку не делается. Если делается перенос на новую строку или присутствует else — фигурные скобки обязательны. Т.е.
                                        if (x == 1) return;
                                        if (x == 1 || x == 2 || x > 100 && x < 1000) {
                                          performSomethingComplex(x + 100, x - 100, x * 100, x / 100);
                                        }
                                        if (x == 2) {
                                          f();
                                        } else {
                                          g();
                                        }
                                        


                                          +2
                                          А потом кто-то применит автоформатирование с другим стилем, закоммтит и оппа — мы получили кейс как выше.
                                          Правила без исключений лучше работают.
                                            0
                                            Автоформатирование с тем же успехом уберёт фигурные скобки вокруг блока из одной инструкции. Стиль должен был един и его соблюдение должно автоматически проверяться при коммите или слиянии.
                                            –9
                                            нафига вы этот сиподобный хелл кидаете? я тут вообще о другом
                                              0

                                              Ставить фигурные скобки в однострочных выражениях даже в ГОСТ прописано. Знаете почему? ;)

                                                –1
                                                ГОСТ на что?
                                              +1
                                              У нас в фирме, например, очень строгое правило — закомментированного кода быть не должно. За 4 года было 2 исключения и каждое подробно описывалось рядом, почему и как.
                                                +3
                                                Можно пример, когда закомментированный код посчитали нужным?
                                                  +1
                                                  Единственный вариант, который я видел — это когда рядом с закомментированным кодом есть ещё комментарий, который описывает почему такой способ не работает и приводит к ошибке, и почему не стоит на него заменять текущий менее красивый код.
                                            +1
                                            Это на каком языке?
                                              +2

                                              Как минимум, python

                                              +2
                                              еще

                                              if(cond)
                                              {
                                              return;
                                              }
                                                +3
                                                Более того, в Питоне почти не бывает вопросов по поводу стилей кода, а всё потому, что фактически с самого начала есть подробный стандрарт: PEP8. Если подумать — это просто отличное решение. Сэкономило кучу времени куче людей.
                                                  0
                                                  +1
                                                +1

                                                Хорошо, когда можно сделать go fmt и никаких споров :)

                                                  +1

                                                  И Ctrl + Alt + Shit + L в JetBrains IDE с попутным тыканьем новичков в доки по PSR (в стане PHP разработчиков), например.


                                                  Наверное go и php (современный) — это единственные языки, где никогда не возникает споров по поводу кодстайла.

                                                    +2
                                                    У меня только один вопрос — зачем } else { на той же строке, что и закрывающая скобка?
                                                      0

                                                      Вопрос не верный, не "зачем", а "почему". Потому что PSR основан на самых популярных практиках самых популярных продуктов. Вот и весь ответ, никакого смыслового значения "зачем" в самом стандарте нет. Взяли и основали стандарт на том, что используют большинство.


                                                      Если искать смысл в самих корнях, то подобные практики пошли, я почти уверен, из миров java, haxe, c++ и прочих. Где подобное является стандартными вещами (ну в C\C++ несколько стандартов, так что моё утверждение на счёт подобной практики в этом языке лишь частично верное).


                                                      Размышления на тему: Положа руку на сердце, может это просто привычка использовать именно этот стандарт во всех языках, которые использовал (haxe, java, js\es, sass, less, php), но мне кажется что подобное лучше выглядит, нежели размазывание одного метода на 100500 строк. "Воздух" добавляется за счёт переносов строк, а законченное по смыслу логическое выражение, включающее этот самый "else" более компактно и лучше бросается в глаза, нежели если скобки переносить на новую строчку. Фиг знает, споры о кодстайле могут продолжаться вечность и "лучшего" всё равно не найти.

                                                        +1
                                                        Я смотрел голосование по этой теме в PSR:
                                                        А) 10 голосов за
                                                        if () {
                                                        ...
                                                        } else {
                                                        ...
                                                        }
                                                        

                                                        Б) 6 голосов за
                                                        if () {
                                                        ...
                                                        } 
                                                        else {
                                                        ...
                                                        }
                                                        

                                                        Так что да, большинство, но очень не хватает их обоснований. По каким причинам этот голос. Потому что у меня есть несколько обоснований относительно варианта Б и слабые обоснования для А.
                                                          +2
                                                          Мне, например. вариант Б просто режет глаза. И я объясню почему: if..else это одна единая конструкция. Поэтому "} else {" выглядит как продолжение конструкции, а «else {» с новой строчки больше похоже на новую конструкцию, никак не относящуюся к предыдущему if-у. То же самое и с фигурной скобкой на той же строчке, что и сигнатура метода: код метода непосредственно относится к его сигнатуре.
                                                            0
                                                            Можно и в обратную сторону рассуждать: if..else — это единая конструкция, а }else{ — нет, потому что {}, т.н. блок — отдельная сущность.
                                                              0
                                                              Любая конструкция состоит из блоков, одного или несколько. Причем тут блоки? Я говорю именно про визуальное восприятие. Не пойму чем тогда по вашей логике отличается "}else{" от «else{»?
                                                                0
                                                                Конструкция так называется — «блок».
                                                                Есть условный оператор, есть операторы цикла, есть выбор по ключу, есть блок.
                                                                Вы же можете написать
                                                                for (...)
                                                                ;
                                                                А можете в теле использовать не один оператор action, а блок.
                                                                  0
                                                                  Если вы понимаете под блоком именно фигурные скобки, то согласен. Я понимаю под блоком кода, как ни странно, блок кода, ему не обязательно быть обрамленным в фигурные скобки и он может быть пустым, как в вашем примере с «for». Так что в действительности любая конструкция(будь то if, for или еще чего) не имеет смысла без блока кода.
                                                                  Т.е. получается такая иерархия: лексемы -> выражения -> блоки -> конструкции.
                                                                    0
                                                                    Не я понимаю; так называется. Оно же — «составной оператор».
                                                                    Например, КиР:
                                                                    3.1 Statements and Blocks…
                                                                    Braces { and } are used to group declarations and statements together into a compound statement, or block, so...There is no semicolon after the right brace that ends a block.


                                                                    3.2 If-Else
                                                                    The if-else statement is used to express decisions. Formally the syntax is
                                                                    if (expression)
                                                                    statement1
                                                                    else
                                                                    statement2
                                                                    where the else part is optional.

                                                                0
                                                                Если у вас блок — отдельная сущность, вы придёте к GNU стандарту:
                                                                if (...)
                                                                  {
                                                                    ...
                                                                  }
                                                                else
                                                                  {
                                                                    ...
                                                                  }
                                                                

                                                                Мне лично не такой вариант не нравится (слишком много места пропадает зря из-за чего в GNU проектах любят не использовать фигурные скобки для однострочных выражений — и потом ясно, чем это кончается), но определённая логика тут есть.

                                                                Вариант же с «else {» — ужасен просто потому что у вас оказывается две отдельные, никак не связанные друг с другом конструкци: «if» и «else».

                                                                Вот «else { blah-blah-blah }» как прикажете понимать? Это вообще что такое? Это куда? Это зачем? Как так вообще можно писать???
                                                                  0
                                                                  Вас же не смущает конструкция «default: blah-blah-blah; break;». Ветки оператора switch пишутся отдельно друг от друга, и выглядят как отдельные не связанные конструкции. Почему бы и if так не писать?
                                                                    0
                                                                    весь switch — это одна конструкция, состоящая из нескольких case, которые, как вы правильно заметили, не связаны никак друг с другом. Поэтому так и пишутся :)
                                                                    Я имею ввиду, что каждый следующий case не является продолжением другого, и один case может существовать без предыдущего. else в свою очередь не может существовать без предыдущего блока.
                                                                      0
                                                                      Тогда и try / catch надо отдельными блоками писать, потому что там catch не связаны между собой.
                                                                      Цепочка if / elseif / elseif / else похожа на оператор switch, и elseif там тоже не связаны. case не может существовать без switch, catch не может существовать без try, else не может существовать без if.

                                                                      PS: Писал так в одном проекте, когда ветки if идут отдельными блоками. Вполне нормально смотрится, код в блоках не сливается с предыдущими, особенно если условия длинные.

                                                                        0
                                                                        Тогда и try / catch надо отдельными блоками писать, потому что там catch не связаны между собой.
                                                                        Связаны. Если один оператор catch сработал, то другой — уже ничего перехватить не может. Логически — это цепочка обработчиков (хотя внутри, конечно, компилятор может оптимизировать).

                                                                        Цепочка if / elseif / elseif / else похожа на оператор switch, и elseif там тоже не связаны.
                                                                        Связаны — тем же самым способом. Нельзя одну ветку рассматривать в отрыве от других.

                                                                        case не может существовать без switch
                                                                        Case и switch — это просто "goto под прикрытием". Он может скакать на любую глубину вложенности (правда не может мимо конструкторов и «наверх»), иерархии меток никакой нету. if/elseif/else и try/catch — устроены совсем не так.

                                                                      0
                                                                      У оператора switch нет никаких «веток», извините. Когда вы используете низкоуровневую конструкцию с оператором goto, что часто у вас просто нет выбора.

                                                                      Как вы предлагаете скобки в чём-то типа следующего расставлять:
                                                                      switch (i % 8) while (i > 0) {
                                                                        case 0: x += a[ i-- ];
                                                                        case 7: x += a[ i-- ];
                                                                        case 5: x += a[ i-- ];
                                                                        case 4: x += a[ i-- ];
                                                                        case 3: x += a[ i-- ];
                                                                        case 2: x += a[ i-- ];
                                                                        case 1: x += a[ i-- ];
                                                                      }


                                                                      В случае же с if'ом у вас есть две ветки, которые очевидным образом связаны между собой.
                                                                      0
                                                                      Если у вас блок — отдельная сущность

                                                                      Так не у меня, так определяется стандартом, нет?

                                                                      О, оказывается, самый логичный и верный на мой взгляд вариант имеет имя — GNU стандарт. Спасибо!

                                                                      из-за чего в GNU проектах любят не использовать фигурные скобки для однострочных выражений

                                                                      Ох, и тут совпадение.

                                                                      Я бы сказал, что это очень старомодный стандарт, потому что легкочитаем без подсветки, в монохроме/на бумаге.
                                                                        0
                                                                        Так не у меня, так определяется стандартом, нет?
                                                                        Ну так стандарт и в выражении a = b + c; несколько сущностей выделяет. Это не значит, что нужно в пять строк это писать.

                                                                        Я бы сказал, что это очень старомодный стандарт, потому что легкочитаем без подсветки, в монохроме/на бумаге.
                                                                        Угу — вот только часто получается, что читается и работает — программа по разному. Это — очень большая проблема.

                                                                        P.S. Вообще, конечно, очень жаль что на проблему, которая, вообще-то, яйца выделенного не стоит, мы тратим столько времени. Причём забавно что в языках типа Make, которые, являются, в других отношениях, весьма убогими этой проблемы нет. Естественная расстановка отступов в блоке ifeq/else ifeqelse/ — существует только одна, а споров о сущности «блоков» нету потому что никаких «блоков» нету. Это одна из вещей, которые в C/C++ сделаны отвратительно — но при этом, почему-то, это кривое и неудобное решение копируется везде и всюду…
                                                                          0
                                                                          Ну так стандарт и в выражении a = b + c; несколько сущностей выделяет. Это не значит, что нужно в пять строк это писать.

                                                                          Это натяжка, ну да ладно.

                                                                          Угу — вот только часто получается, что читается и работает — программа по разному. Это — очень большая проблема.

                                                                          В случае с
                                                                          if <>
                                                                          {
                                                                          }
                                                                          else
                                                                          {
                                                                          }

                                                                          Исполняется так, как читается.

                                                                          Вообще, конечно, очень жаль что на проблему, которая, вообще-то, яйца выделенного не стоит, мы тратим столько времени

                                                                          Я просто порадовался, что такой стандарт есть, только и всего.
                                                                          Это одна из вещей, которые в C/C++ сделаны отвратительно — но при этом, почему-то, это кривое и неудобное решение копируется везде и всюду…

                                                                          В Паскале аналогично, только в силу обозначения составного оператора(блока) словами, споров вполовину меньше.
                                                                            +1
                                                                            В случае с
                                                                            if <>
                                                                            {
                                                                            }
                                                                            else
                                                                            {
                                                                            }

                                                                            Исполняется так, как читается.
                                                                            Как я уже сказал — этот стандарт мне не нравится, но я его понимаю. А вот
                                                                            if <...> {
                                                                              ...
                                                                            }
                                                                            else {
                                                                              ...
                                                                            }
                                                                            
                                                                            я просто не понимаю откуда может взяться и кому может нравится. Выглядит так, как если бы if был отдельно и else — отдельно. И вот этого я не понимаю. «Отдельно живущий блок» — это ещё туда-сюда, но «отдельно живущий» else — это какая-то очень странная сущность.
                                                          0
                                                          Угу. Для C/C++ есть clang-format, но у него есть большая беда: не все его используют.

                                                          Впрочем в проектах, его использующих, жить всё равно легче. Мне, в общем, всё равно как стоят пробелы (потому что почему-то тот вариант, который нравится мне редко нравится кому-либо ещё) и я ненавижу Style Guide'ы (по той же причине) — но спокойно отношусь к вещам подобным go fmt.

                                                          Просто потому что когда мне дают go fmt — то мой код делают хуже понимаемым лично мной, но взамен экономят немножко моё время. Это я ещё могу терпеть. Но когда мне навязывают какой-то Style Guide и не дают инструмента, то это значит, что меня заставляют тратить время и делать работу, которая мне же и сделает хуже! Это — уже перебор.
                                                            +1

                                                            Это абсолютно верная позиция, когда вы над кодом сидите один и никому не показываете. Но когда в команде больше 3х человек — не думаете ли, что подобные принципы немного эгоистичны? И что лучше использовать один стандарт, пнуть себя в мягкое место и переучиться (это тяжело, я прекрасно это понимаю, у каждого есть подобный опыт), который доступен и привычен большинству, нежели свой супер-удобный вариант, доступный только для таких, бесспорно замечательных разработчиков, как вы? =)

                                                              –1
                                                              Нет, не проще. Заметьте: я не настаиваю на том, чтобы кодить игнорируя все и всяческие стандарты. Но. Стандарт либо содержит объективно-проверяемые вещи, либо нет.

                                                              Первое — автомат типа go fmt способен проверить (а зачастую и исправить), второе — будет постоянным источником споров и разногласий независимо ни от чего.
                                                                –1

                                                                Ну меня просто смутила фраза "ненавижу всяческие стайлгайды", я рад что ошибся в вашей позиции. А стайлгайды, по-моему наоборот хорошо когда есть, главное чтобы он был один. Нравится ли он или нет — не важно, главное чтобы один, иначе холивары и всё такое. Короче, почти что как сейчас в комментах к посту.

                                                          –1
                                                          Еще два типа:
                                                          return 
                                                          
                                                          vs
                                                          return;
                                                          
                                                            +2

                                                            приведение к стандарту просто надо выполнять отдельным коммитом imho.

                                                              0
                                                              Но история всё равно портится.

                                                              Я обычно следую правилу, что если приходится править старый код, то форматирование меняю только на уровне отдельных методов, причем если в них изменилась довольно большая доля кода. Т.е. если поправили пару строчек в большом методе — оставляем стиль прежний. Если поправили треть метода или больше — тогда уже можно переформатировать весь метод.
                                                                0
                                                                Мы использовали git filter-branch, чтобы привести всю историю к единому стандарту. Заодно избавились от части конфликтов при слиянии.
                                                                  +1
                                                                  А, т.е. ретроспективно исправили стиль во всём проекте как если бы он изначально писался с правильным стилем? Интересное решение.

                                                                  Минус, конечно, что история меняется, но конкретно в плане исправления стиля — вроде и не страшно.
                                                                    0
                                                                    Поскольку круг людей, которые используют репозиторий, точно известен, переписывание истории прошло довольно спокойно
                                                                      0
                                                                      Да, с закрытым проектом такое вполне можно провернуть. И сама идея мне нравится.

                                                                      Но, увы, если проект публичный, то скорее всего замена истории приведет к слишком серьезным проблемам. Аналогично будут проблемы при наличии интераграции с внешними инструментами (всякие Jira, Stash/FishEye и проч.).
                                                              +1
                                                              Есть ещё такая точка зрения: если применять новые стандарты только к новому (изменённому) коду, то со временем будет повышаться читаемость часто модифицируемых кусков. Нетронутыми же останутся те, которые либо "просто работают", либо никому не нужны. Со всех сторон одни плюсы — и без лишних телодвижений и польза в нужном месте.
                                                                +2
                                                                У нас есть стандарт. Он фиксирует спорные моменты по которым были разногласия, периодически дополняется. К проекту есть еще архитектурные заметки, из серии если вы в коде столкнулись с указанными областями, то с ними следует поступать вот так.
                                                                Описывать всё и вся не вижу смысла — всегда проще договориться и найти пример в существующем коде. Чем большее количество человек работают над одной базой кода, тем строже должен быть стандарт.
                                                                  0
                                                                  Отлично выразил, ЕМНП, Роберт Мартин:
                                                                  не важно какое соглашение о стиле кодирования вы примите, важно чтобы вы его приняли!


                                                                  PS: Как славно что в PHP есть PSR =) Сколько безсмыленных холиваров этим предотвращено!
                                                                    0
                                                                    половина упоминаний о PSR на хабре заканчивается холиварами о кодстайле с аргументацией о том, что psr — рекомендация, а не стандарт. Увы, не все понимают соль принятия единого стандарта (см. цитату Мартина).
                                                                    0
                                                                    Очевидно ли на первый взгляд, что оба блока делают одно и то же?

                                                                    Не хочу показаться занудой, но shift же изменяет массив.
                                                                      0

                                                                      наверное это и есть тем "мелким, но важным различием"

                                                                      0

                                                                      ИМХО Не так уж важно как пробелы и переводы строк расставлять. Не вижу даже ничего суперстрашного если разные файлы форматированы по разному — все равно все будет понятно. Лучше концентрироваться на сути, например для плюсов: заставлять использовать RAII, создавать новые типы исключений вместо использования системных, порядок инклюдов, запрет using namespace в хедерах, запрет блокирующих вызовов и т.д.

                                                                        0
                                                                        А можно подробнее про «порядок инклюдов»?
                                                                        0
                                                                        А потом вдруг надо чей-то файл подредактировать, а в нем разрброд и шатание. И вместо того, чтобы сконцентрироваться на коде, ты сидишь и думаешь, как бы так расставить скобочки, чтоб было консистентно с остальным проектом.
                                                                          0

                                                                          Кривой/неконсистентный стиль можно быстро и массово поправить каким-нибудь clang-format, а затем сделать проверку стиля в CI. Все. Проблема решена. Зачем ей посвящать столько времени и сил в холиварах?


                                                                          Куда сложнее читать и фиксить спагетти код функции на 400 строк с однобуквенными переменными без комментариев и кучей хаков. Который еще и не работает если пойти чуть в сторону. Вот за что нужно убивать.

                                                                        +2
                                                                        Хмм… стандарт разработки — не то же самое, что стандарт форматирования кода кмк.
                                                                          0
                                                                          Вечная тема. Если прокрутить Google страницы W3C валидатором, то покажет кучу ошибок… И это Google. Все очень индивидуально.

                                                                          Важно наверное стандарты безопастности, а остальное уже на любителя.
                                                                            0
                                                                            Если считать, что статья про стиль форматирования, а не про стандарты программирования, то у меня есть примерно такие раздумья:
                                                                            1) утвердить какой-то любой стиль для коммитов.
                                                                            2) наладить процесс так, чтобы участник после взятия мог запустить настроенный под себя beautifier.
                                                                            3) а перед коммитом запустить beautifier обратно на утверждённый стиль (можно даже запретить коммит, если на сервере beautifier вернул код «ошибки»)
                                                                            4) при этом опасные преобразования, типа уничтожения скобок, запретить по всей команде.
                                                                            • НЛО прилетело и опубликовало эту надпись здесь
                                                                                0
                                                                                пытаться насаждать свой любимый стандарт стиля программирования — это лишь бесить всех, т.к. все точки зрения субъективны, а вот иметь стандарт структуры когда, куда как важнее

                                                                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                Самое читаемое