Prettier в крупных проектах: тратим 20 минут на настройку, забываем о форматировании навсегда +14


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



Год назад одна из команд в Skyeng сталкивалась с такими холиварами почти на каждом ревью. Но затем человек, у которого больше всех болело, сказал: «Теперь живем на Prettier'e, согласны?» За следующие месяцы ребята ни разу не поднимали вопрос о форматировании, а теперь эта штука стоит на всем монорепозитории фронтенда — и его использует каждая команда, которая туда заезжает.

Что такое Prettier


Prettier – инструмент для автоформатирования кода с поддержкой кучи инструментов, включая наши любимые Angular и Typescript. Он не модифицирует код, не заменяет тернарные операторы на if’ы и не разбивает длинные строки на несколько конкатенированных (об этом уже должен думать разработчик), а просто выводит то, что есть, с нужным форматированием.

Как было раньше


На тот момент в Skyeng было уже несколько десятков разработчиков, и каждый месяц могли приходить по 10-20 новичков. Все работали (и работают) в небольших командах — каждая, фактически, считается независимой “боевой единицей” со своими задачами и договоренностями.

Давайте представим одну такую — безусловно, все совпадения случайны, — команду:

Борис – миддл, который пришёл к нам из другой большой компании. У них был свой стайл-гайд, но он старается переучиться на наш: в целом, справляется, но время от времени делает что-то по части форматирования не так и узнаёт об этом только на код-ревью. Мелочь, но неприятно.

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

Артур – перфекционист с философией «чистый код – понятный код»: вечно парится по поводу код-стайла. Безусловно, отклонит код коллег с кучей комментов «здесь перенесите фигурную скобочку на следующую строчку» — и Борис потратит время на правки, а Павел – на споры уровня «тебе не нравится, ты и меняй».



Как стало


Задача Prettier – заставить разработчика не думать о форматировании: в нем минимум настроек. Это и подкупило Павла, когда Артур кинул в чат команды ссылку на проект:

— поставил сам Prettier,
— поставил пре-коммит хук (подробнее),
— оставил в чате пару комментариев, что код-стайл там свой (например, логические операции в if’ах ставятся в конце строки, а не в начале).

Всё, так команда перешла на Prettier. Вот примеры промышленного кода до применения Prettier и после. Он чуть переформатирован, чтобы показать возможности этого инструмента.

До:

  public listenDndForFocusEvents(channel: string): Observable<boolean> {
    return this.drag
      .pipe(
        filter(
          event => event.channel === channel
        ), 
        filter(
          event => event instanceof DndDragStartEvent || event instanceof DndDragEndEvent
        ), 
        map(
          event => event instanceof DndDragStartEvent
        )
      )
  }

После:

  public listenDndForFocusEvents(channel: string): Observable<boolean> {
    return this.drag.pipe(
      filter(event => event.channel === channel),
      filter(event => event instanceof DndDragStartEvent || event instanceof DndDragEndEvent),
      map(event => event instanceof DndDragStartEvent),
    );
  }

Даже если бы это было написано в одну строку, оно всё равно бы переформатировалось так, как надо:

  public listenDndForFocusEvents(channel: string): Observable<boolean> {
    return this.drag.pipe(filter(event => event.channel === channel), filter(event => event instanceof DndDragStartEvent || event instanceof DndDragEndEvent), map(event => event instanceof DndDragStartEvent),);
  }

Ещё кусочек кода, уже без точек с запятой. До:

const lessonCount$ = this.studentLessonsCounterService
      .getCounter().pipe(map(featureInfo => featureInfo.lessonCount))
const isItTimeForNotification$ = lessonCount$.pipe(map(lessonCount => lessonCount % REAL_TALK_NOTIFICATION_LESSON_INTERVAL === 0))

После:

const lessonCount$ = this.studentLessonsCounterService
      .getCounter()
      .pipe(map(featureInfo => featureInfo.lessonCount));
const isItTimeForNotification$ = lessonCount$.pipe(
      map(lessonCount => lessonCount % REAL_TALK_NOTIFICATION_LESSON_INTERVAL === 0),
    );


Теперь код-ревью проходит быстрее, Борис не тратит кучу рабочего времени на форматирование уже написанного кода, Павел продолжает писать так, как и писал (но теперь с ним никто не ругается), а Артур наконец-то доволен, заходя в репозиторий и улыбаясь от красоты кода. Используя простой инструмент с февраля 2019-го, ребята сэкономили кучу времени, перестав спорить из-за форматирования. А затем убедили остальные команды сделать так же.




К сожалению, не доступен сервер mySQL