Почему роботы должны форматировать код за нас

https://medium.freecodecamp.org/why-robots-should-format-our-code-159fd06d17f7
  • Перевод
image

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

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

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

Несколько примеров


После прочтения “The Programmers’ Stone”, я еще долгое время ставил скобки таким образом:

if (food === 'pizza')
{
    alert('Pizza ;-)');  
}
else
{  
    alert('Not pizza ;-(');
}

Но потом я понял, что я, наверное, единственный, среди пользователей, кто так делает. Все остальные придерживаются этого стиля:

if (food === 'pizza') {
    alert('Pizza ;-)');  
} else {
    alert('Not pizza ;-(');
}

Или этого

if (food === 'pizza') {
    alert('Pizza ;-)');  
}
else {  
    alert('Not pizza ;-(');
}

Так что я поменял свой стиль на вышеупомянутый.

Мне очень нравится использовать этот стиль для создания цепочек:

function foo(items) {
  return items
    .filter(item => item.checked)
    .map(item => item.value)
  ;
}

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

const food = [
  'pizza',
  'burger',
  'pasta',
]

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

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

Есть еще кое-что, что никто кроме меня не делает. Я всегда использую двойной пробел перед комментарием в конце строки.

const volume = 200;  // ml

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

Что делают разработчики JavaScript


К сожалению, у JavaScript нет официального стиля кодирования. Есть несколько популярных стилей написания кода, таких как Airbnb или Standard. Вы можете использовать их для того, чтобы ваш код выглядел знакомым для других разработчиков.

Вы можете использовать ESLint, чтобы задавать стиль кодирования и даже проводить автоформатирование кода. Но это не сделает вашу кодовую базу на 100% согласованной. ESLint c конфигурацией Airbnb упорядочат только первый мой первый пример и создадут противоречия в двух других.

Что должны делать разработчики JavaScript


В некоторых языках есть строгие стили кодирования, а также инструменты для форматирования кода. Таким образом, разработчики не тратят время на рассуждения о стиле кодирования. Взгляните на Refmt для Reason или на Rustfmt для Rust.

Кажется, что у JavaScript наконец-то имеется решение этой проблемы. Новый инструмент под названием Prettier переформатирует ваш код в соответствии со своими правилами. Он совершенно не учитывает изначальный вид кода.

Давайте опробуем работу Prettier на моих примерах:

if (food === 'pizza') {
  alert('Pizza ;-)');
} else {
  alert('Not pizza ;-(');
}

function foo(items) {
  return items.filter(item => item.checked).map(item => item.value);
}

const volume = 200; // ml

Вы можете оспорить этот стиль. Мне, например, не нравится размещение else, сомнения вызывает также написание функциональной цепи в одну строку. Однако я вижу огромные преимущества во внедрении Prettier’а:

  • нечего даже обсуждать — у Prettier’а несколько опций;
  • никаких споров о конкретных правилах, если вы работаете в команде;
  • вашим напарникам не нужно изучать стиль кодирования вашего проекта;
  • нет нужды исправлять стилевые ошибки, о которых сообщает ESLint;
  • есть возможность установить сохранение автоформата.

Заключение


Prettier уже используется некоторыми популярными проектами, такими как React или Babel. И я начинаю переделывать свои проекты, отходя от своего привычного стиля кодирования, в пользу Prettier’a. Я бы порекомендовал использовать его вместо стиля кодирования Airbnb.

В начале моей работы с Prettier’ом было много моментов, когда я думал “фу, это ужасно”. Но когда я думаю, что мне нужно было бы, например, вручную форматировать код JSX из однострочного вида в многострочный, если я добавляю еще один prop и это не умещается в одну строку — тогда я понимаю, что оно абсолютно точно стоит того.

image

Prettier форматирует ваш код, когда вы сохраняете файл.

Прочитайте, как внедрить Prettier в свой проект.

P.S. Посмотрите на мое новое средство, которое упростит добавление ESLint, Prettier и других инструментов в ваш проект, а также хранение и синхронизацию их настроек.



Перевод выполнен при поддержке компании EDISON Software, которая профессионально занимается разработкой сайтов на Amiro.CMS и WordPress и для крупных заказчиков.
Форматировать код…

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

Edison 382,57
Изобретаем успех: софт и стартапы
Поделиться публикацией
Комментарии 64
  • +2

    Ммм… Потому что могут?

    • +3
      Так же работаю с Prettier, но заметил, что эта штука не до конца понимает чейны и уж слишком разворачивает объекты конфигураций json
    • +1
      Многие хотят писать так как хотят, я в их числе.
      • +4
        Добавил опрос, посмотрим сколько это «многие»
        • +2
          У меня для вас плохие новости. На момент написания это комментария вы находитесь в меньшинстве.
          • –2
            Почему плохие? Миллионы мух не могут ошибаться?
        • 0

          Спасибо, не надо.


              <div
                className="HelloWorld"
                title={`You are visitor number ${num}`}
                onMouseOver={onMouseOver}
              >

          (из официального примера)

          • +3

            Придерживаемся такого стиля в форматировании xml в Android. Сначала было непривычно, потом стало норм. Особых минусов нет.

            • +4
              очень удобный стиль — когда надо добавить или удалить свойство — просто добавь или удали строку, да и в jsx свойств может быть очень много
            • +2

              Единственное, что меня смущает в а автоматических форматтерах — то, что они не могут распознавать случаи, когда программист сам выставляет пробелы для форматирования. Они их убирают и код наоборот становится нечитаемым.

              • +1

                Для таких случаев можно поставить коммент prettier-ignore. Prettier оставит форматирование этого куска как и было:


                // prettier-ignore
                matrix(
                  1, 0, 0,
                  0, 1, 0,
                  0, 0, 1
                );
              • +1
                В Java стиль чистого кода появился с лёгкой руки Боба (Robert Martin), и не говоря про JavaCodeConvention.
                Возможно, и у JavaScript появиться свой евангелист…
                • +1
                  AStyle при сохранении, но опции мои.
                  • +4
                    Ctrl+KD в студии и таких вопросов даже не возникает.
                    • +2
                      Так привыкла писать код с определенными стилевыми правилами, что уже делаю это на автомате.
                      Кода вижу что-то вроде этого:
                      function getTotalPrice(sum){
                      	var price=sum || 0,
                      		tax = 5;
                      	price+= tax;
                      	var delivery = 3;
                      	if(price<10) price += delivery;
                      	return price;
                      }
                      

                      Не могу удержаться и не переписать с «правильными» пробелами, скобками и тд:
                      function getTotalPrice(sum) {
                          var price=sum || 0,
                                tax = 5,
                      	  delivery = 3;
                      
                          price += tax;
                      
                          if (price < 10) { 
                              price += delivery;
                          }
                      
                          return price;
                      }
                      

                      Есть главы в книгах Стефанова «JavaScript. Шаблоны » и у Крокфорда «JavaScript. Сильные стороны»(где он про JSLint пишет) рекомендации как оформлять код.
                      • +3
                        В итоге один оператор равенства отбит пробелами, а самый первый — нет.
                        • –1

                          Было бы лучше, так:


                          function getTotalPrice(sum) {
                              var price    = sum || 0,
                                  tax      = 5,
                                  delivery = 3;
                          
                              price += tax;
                          
                              if (price < 10) { 
                                  price += delivery;
                              }
                          
                              return price;
                          }
                          • +6

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


                            Потом придется добавить еще одну переменную с именем подлиннее, и придется переформатировать весь блок кода, создавая большой diff и потенциальные merge-конфликты.

                        • +2
                          нечего даже обсуждать — у Prettier’а несколько опций;

                          Это не совсем правда. Опций немного, но они очень холивароспособствующие.


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

                          • +1
                            Несовсем понятно, с чего вдруг холивару начатся — как техлид сказал код оформить, так все и сделали, точка. Никакого холивара, все заняты работой, а не ерундой.

                            Про development standards никогда не слышали? Простой документ с элементарным набором правил по разработке (включающий, но не ограниченный, naming conventions и тем самым форматированием), который почетно вручается каждому программеру, пришедшему на проект/в компанию. Тому, кто не блюдет — по шапке. Проблемы?
                            • +1

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


                              Но почему-то так не происходит, а любой пост на эту тему набирает немало комментариев, например, вот этот.

                              • +1

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

                          • 0
                            Подскажите пожалуйста, название темы для sublime, на изображении к посту.
                            • 0
                              Стилизаторы кода рулят)
                              • +1
                                Есть мысль, что возможно следовало бы просто учитывать это всё в самом языке.

                                Например вот сейчас в Питоне можно написать

                                def f(a, b,  c):
                                    pass
                                

                                а можно

                                def f(a,
                                    b,
                                    c):
                                    pass
                                

                                или даже

                                def f(a, b,
                                    c):
                                    pass
                                


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

                                Не лучше ли было бы, если бы второй или что-то типа него было бы единственно разрешённым? Разнообразие в этом лично мне кажется «untidy», а третий вариант (который зачастую выбирают IDE при автоматическом форматировании) как по мне и вовсе исчадие «ада перфекциониста».

                                Ни в коем случае не настаиваю и сам не уверен, просто подумалось, решил вынести на суд коллективного разума.
                                • –2

                                  А как же минификация?

                                  • 0
                                    def f(a, b,  c):
                                        pass

                                    — хороший вариант, если нет комментариев


                                    def f(a,
                                        b,
                                        c):
                                        pass

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


                                    def f(a, # комментарий a
                                        b, # комментарий b
                                        c): # комментарий c
                                        pass # итоговый комментарий

                                    PS с Питоном не знаком, просто нагуглил аналог // из C++

                                  • +1
                                    Любопытно, кстати, почему люди вообще до сих пор используют текстовое представление для хранения программ. По-моему тут на лицо сращивание данных и форматирования в одну сущность, которого вроде всегда стоит стараться избегать. Почему вместо этого не хранить типы, переменные, функци и т.п. в качестве записей, скажем, в реляционной БД, с указанием отношений между ними, имён и инициализационные значений как отдельных полей, а для каждого разработчика рендерить как ему больше нравится?
                                    • 0

                                      Тогда уж хранить код в виде AST, а в редакторе разворачивать с применением персонального файла стилей.
                                      Минус данного подхода: как хранить AST в системе контроля версий?

                                      • 0

                                        Так и хранить, отформатированным в виде текста.

                                        • 0
                                          И страдать из-за непонятных git-diff?
                                          • 0
                                            А что мешает сделать diff для AST? А уж если некий формат описания AST станет стандартным то и вообще все будет замечательно.
                                            • AFAIK, самая большая проблема — это время обработки:
                                              1. Размер деревьев. Число токенов на порядок-два (зависит от ЯП) больше числа строк.
                                              2. Деревья — двумерные структуры. СКВ работают преимущественно с классическими операциями Левенштейна (добавить, удалить, заменить строку). Много ли Вы знаете СКВ, которые бы отличали <удалить строку A №5 + вставить строку A перед строкой B №4> и <поменять местами строки B №4 и A №5> и корректно сливали эти патчи с другими? Для AST необходимо же исходно поддержить как горизонтальные операции (добавление/удаление дочернего поддерева), так и вертикальные (замена поддерева его дочерним поддеревом/замена поддерева T на C[T] для некоторого контекста C[] с одним подстановочным местом). Вроде бы это обстоятельство меняет асимптотическую сложность.

                                              И ещё обращаю внимание, что получение диффа — более простая задача, чем построение модели (в т.ч. с конфликтным/бесконфликтным слиянием патчей) СКВ.

                                              P.S. Я полностью согласен с последним: если когда-то СКВ научатся работать с AST и будет унифицированный формат деревьев, инструменты программирования шагнут на принципиально другой уровень удобства.
                                            • +1

                                              Современные системы контроля версий ориентированны на текст, очевидно нужна новая система, ориентированная на AST.

                                              • +1

                                                Как-то решение сразу не пришло в голову.
                                                Можно сформировать отдельный файл стилей для хранения.
                                                При загрузке переформатировать в пользовательский формат, при сохранении — в машинный.

                                              • 0
                                                Еще при изучении и рефакторинге больших программ хочется уметь работать с кодом чем-то типа SQL или SPARQL запросов.
                                              • 0
                                                Использую автоформатирование, которое даёт мне JetBrains. Неплохо справляется со своей задачей. И ESLint сбоку ещё повесил, чтобы в случае косяков со стороны IDE форматтера, я мог это сразу увидеть. Поэтому для себя не вижу смысла использовать ещё и Prettier.
                                                • +1
                                                  Суть prettier в том, что ты пишешь код как пишешь, а потом одной комбинацией клавиш приводишь его вид к общему стандарту в команде
                                                  • +1

                                                    Я тоже пишу код, как хочу, а потом нажимаю Ctrl+Alt+L (В поиске: Reformat Code) и привожу его к общему стандарту. Помимо этого, PHPStorm неплохо синхронизируется с настройками .eslintrc.json.

                                                • 0
                                                  Сейчас изучаю язык ELM, в котором есть стандартный форматер elm-format, вставляющий кучу лишних пустых строк и разбивающий строки без пользы для читаемости. Не все любят такой стиль, и появился сторонний продукт elm-format-short, который более экономно относится к месту на экране. Мне удобно видеть сразу больше кода, держать в уме не поместившееся на экран памяти не хватает, я быстро перешел на него. При этом идея сделать форматер настраиваемым в комьюнити поддержкой не пользуется.
                                                  Я вот думаю, хорошо бы если бы IDE при сохранении форматировала стандартным образом, а при загрузке — по настройкам пользователя. Тогда бы и взаимодействие в команде не страдало бы, и редактировать код в своем стиле было бы удобнее.
                                                  • 0

                                                    Делайте форматирование по стандартам в pre commit hook, а каждый разработчик настроит в своей IDE автоформатирование по своему вкусу.

                                                  • –1
                                                    очень раздражает автоформатирование GO. он просто заставляет следовать егоному стилю.
                                                    так и стремится удалить лишние строки, пробелы, выстроить выражение по своему образцу.
                                                    лучше бы сделали подобную опцию опциональной. ломать через колено это неприятно, после других то языков.
                                                    • 0
                                                      Пишу на Java в Intellij IDEA, и там код можно автоматически отформатировать одним сочетанием клавиш. Довольно удобно. Неужели для JS нет такой же удобной IDE? (WebStorm, не?)
                                                      PS Хотя и вручную я тоже стараюсь придерживаться какого-то (чаще всего наиболее читабельного) форматирования кода.
                                                    • 0
                                                      Причина, по которой приходится использовать стандартное авто форматирование кода это использование систем контроля версий (git, svn и пр.), которые универсальные и работают с текстом. Если форматирование изменится, то это будет уже новая версия кода. Поэтому для командной разработки кода лучше всего применять авто форматирование.
                                                      • +1
                                                        Первый и второй вариант одновременно — большая часть форматируется «роботом», если где-то было трудно это сделать руками, меньшая — руками, так как там форматирование улучшает понимание, а «робот» его портит.
                                                        • +1
                                                          В конце концов понял, что мне в целом все равно (хотя конечно же есть вид, который мне нравится), и, гораздо важнее, чтобы стиль был одинаковый у людей, с которыми работаешь. Иначе сбиваешься при чтении в разных местах проекта.
                                                          То есть важнее договориться одинаково, чем сделать как то особенно правильно.
                                                          В этом смысле имеет смысл смотреть на стандарты для языка — от мейнтейнера, популярной ide или стандартных модулей.
                                                          • +1

                                                            Перешел на prettier с standardJs — Это просто божественно — да, в нем мало настроек, по началу это бесило (например нельзя в реакте сделать ковычки на пропсах одинарными) — но сейчас я понимаю что вообще больше руками не форматирую код — все делается автоматически за меня.


                                                            Я не представляю себе ситуацию чтоб я вернулся к ручному форматированию.


                                                            Но у преттиера есть минус — он немного сырой и кое-где ведет себя странно, с теми же промисами

                                                            • +2
                                                              У нас практика показала, что если prettier что то форматирует странно, это значит изначально код написан сильно криво. Я своих ребят ещё какое-то время отучал от фраз типа «это претир так сформатировал». Писать надо так чтобы форматировалось нормально. Выносить вычисления в константы, не совмещать вычисления с возвратами, особенно тринарники. И всё сразу нормально форматироваться начинает.
                                                              • 0

                                                                Дак нет, он реально плохо чайнит промисы.
                                                                Вроде в новых версиях это поправили каким-то костылем, что-то типа "если есть слово than значит чайним все на новую строку, если слова нет то чайним в одну если помещается и меньше двух точек, инача все на новую строку"


                                                                Собственно из-за этого он переносит в моем случае адрес запроса на новую строку


                                                                api
                                                                    .get(`/ajax/report/${id}/info`)
                                                                    .then(res => {
                                                                      // Handle

                                                                Хотя я привык к чему-то типа


                                                                api.get(`/ajax/report/${id}/info`).then(res => {
                                                                      // Handle
                                                          • +2
                                                            В одной американской компании, в которой работал шесть лет был первый упомянутый стиль оформления для кода на C++.
                                                            Заголовок спойлера
                                                            if (food == 'pizza')
                                                            {
                                                                print('Pizza ;-)');  
                                                            }
                                                            else
                                                            {  
                                                                print('Not pizza ;-(');
                                                            }
                                                            

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

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

                                                            Например с точки зрения python pep8 рекомендуется как раз делать два (как минимум) пробела перед # в инлайн-комментариях.
                                                            выдержка из pep8
                                                            An inline comment is a comment on the same line as a statement. Inline comments should be separated by at least two spaces from the statement. They should start with a # and a single space.



                                                            В итоге, не стоит полагаться на какие-то абсолютные правила, а имеет смысл договориться в и приянть стиль оформления в своей команде. Не вижу проблем, разработчики не будут явно придумывать обфускаторы, а сделают так, как читабельнее для них, и пусть это будет отличаться он неких догматических «стандартов».
                                                            • –6

                                                              Намного лучше и удобнее


                                                              if (food == 'pizza'){//комментарий if
                                                                  print('Pizza ;-)');}
                                                                else{//комментарий else
                                                                  print('Not pizza ;-(');}
                                                              another.code();//следующий код с начала строки

                                                              — выделяется целиком весь блок if-else, и видно, где он кончается
                                                              — выделяется, где else
                                                              — компактно, и на экране можно одним взглядом охватить больше кода

                                                              • +3
                                                                А уж как «удобно» мержом добавлять новую строчку перед закрывающей скобкой!
                                                                • +1

                                                                  Можно и так:


                                                                  if (food == 'pizza'){//комментарий if
                                                                      print('Pizza ;-)');}
                                                                    }else{//комментарий else
                                                                      print('Not pizza ;-(');
                                                                    }
                                                                  another.code();//следующий код с начала строки

                                                                  PS судя по минусам в Карму, у Вас явно не хило бомбануло, от указания недостатков варианта:


                                                                  if (food == 'pizza')
                                                                  {
                                                                      print('Pizza ;-)');  
                                                                  }
                                                                  else
                                                                  {  
                                                                      print('Not pizza ;-(');
                                                                  }
                                                                  • +1

                                                                    Вариант


                                                                    if (food == 'pizza')
                                                                    {
                                                                        print('Pizza ;-)');  
                                                                    }
                                                                    else
                                                                    {  
                                                                        print('Not pizza ;-(');
                                                                    }

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

                                                                    • +1

                                                                      Удобнее всего


                                                                      if (food == 'pizza'){
                                                                          print('Pizza ;-)');  
                                                                      }
                                                                      else{  
                                                                          print('Not pizza ;-(');
                                                                      }

                                                                      Тогда при сворачивании блока я вижу его первую строку, строка с "{" не маячит. А в развёрнутом виде хорошо видна структура блока.

                                                                      • +1

                                                                        Отличная идея! Про сворачивание я-то и не подумал...

                                                            • 0
                                                              промахнулся…
                                                              • +1
                                                                С моей точки зрения идеальным вариантом, исключающим большинство холиваров, был бы такой подход: при загрузке в редактор — персональное автоформатирование, а при сохранении/коммите — стандартизированное форматирование. В обоих случаях должно происходить полное переформатирование без учета текущего формата. Исключением могут быть специально обозначенные блоки, которые никогда не переформатируются, только вручную. Тогда каждый будет работать с удобным и привычным ему лично форматом, а стандартизированный формат позволит более корректно проводить мерджи и позволит избежать различных проблем, присущих, например, JS. Причем персонализированный формат должен быть максимально настраиваимым, а стандартизированный наоборот не должен иметь натроек совсем.
                                                                • +1
                                                                  Я бы даже сказал, что это чем-то напоминает загрузку и сохранения файлов в текстовых редакторах, где сам файл представляет некий стандартный формат, а в редакторе виден удобный для работы текст.
                                                                • +1
                                                                  Вы еще форматируете руками? Тогда мы едем к вам!
                                                                  • 0
                                                                    В С-подобных языках открывающая фигурная скобка избыточна. Все операторы, кроме отдельного блока, и так имеют четкое начало — ключевое слово и следующее за ним условие, выделенное скобками.

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

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

                                                                    Самое читаемое
                                                                    Интересные публикации