Разработчики часто не могут договориться о форматировании кода, и типичный рабочий день для многих начинает выглядеть так: кофе, кодинг, всё мирно и хорошо, — а потом, бац, и наступает код-ревью, на котором выясняется, что ты где-то поставил скобочки не так или не перенес что-то на новую строчку.
Год назад одна из команд в Skyeng сталкивалась с такими холиварами почти на каждом ревью. Но затем человек, у которого больше всех болело, сказал: «Теперь живем на Prettier'e, согласны?» За следующие месяцы ребята ни разу не поднимали вопрос о форматировании, а теперь эта штука стоит на всем монорепозитории фронтенда — и его использует каждая команда, которая туда заезжает.
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-го, ребята сэкономили кучу времени, перестав спорить из-за форматирования. А затем убедили остальные команды сделать так же.
Автор: Виталий Евтехов