Начинающие разработчики часто встречают на ревью пул-реквестов очень дотошных ревьюеров, дающих кучу комментариев по теме чистоты кода. Меня зовут Мария Кондаурова, я фронтенд-разработчик в департаменте вычислительной биологии в BIOCAD. И у меня есть свои мысли на тему чистого кода и рефакторинга. Со временем у разработчика опытным путём или с чтением хорошей технической литературы нарабатывается чувство чистого кода — но что делать новичкам? В этой статье я не буду долго мучить теорией про чистый код и паттерны — об этом уже было в Симпсонах учебниках, конференциях и на Хабре в том числе. Но приведу примеры плохого (на мой взгляд) кода в приложениях на React и JavaScript и покажу, как его улучшить. Надеюсь, начинающим моя статья будет полезна, и после прочтения они смогут применить всё на практике. Если вы не хотите, чтобы ваш код читали так: ...эта статья для вас. Подробно о том, что такое чистый код, можно почитать в следующих источниках: Мартин Фаулер. Рефакторинг кода на JavaScript: улучшение проекта существующего кода. Стив Макконнелл. Совершенный код Борьба за человекочитаемость кода: опыт Хабра и т.д. Но если вкратце, я считаю, что чистый код — это легкочитаемый, понятный код, в который легко вносить изменения и расширять его. Это лично моё мнение и взгляд на то, как должен выглядеть хороший код. Я приведу примеры плохого (на мой взгляд) кода в приложениях на React и JavaScript и дам советы, как его улучшить. Допустим, у нас есть список пользователей и у них есть список айдишников любимых фильмов. И есть массив фильмов. Перед нами стоит задача в массиве пользователей вместо массива айдишников вывести массив фильмов Этот код работает и возвращает нам то, что нужно. Но какие у него проблемы? Название функции не отражает, что это функция. Больше похоже на переменную. Сокращенные названия переменных — здесь достаточно простая функция, но если она разрастётся, можно запутаться в этих a, b, e, i, j и т. д. moviesObject? Ни о чём не говорит… Давайте перепишем этот код: Что улучшилось: Название функции теперь отражает, что это функция, которая добавляет к пользователям фильмы. Убрали сокращения. moviesObject переименовали в moviesByIds, — из названия теперь понятно, что по id можно получить фильм. Основные общепринятые правила нейминга: Никаких сокращений. Типы и классы должны начинаться с большой буквы. Добавление префикса T/I в начале типа в JavaScript, по мне, излишне. Поясню свою позицию. В codestyl’e typescript’а нет ничего про префиксы T/I перед типом/интерфейсом, к тому же ключевые слова type и interface уже говорят о том, что это тип или интерфейс. Имя должно отражать смысл значения: Функции должны начинаться с глаголов (также можно добавлять префиксы действий get-/set-/map-/merge-) Нейминг переменной может содержать префиксы, например, is-/has-/should-/can- Нейминг переменной должен учитывать единственное/множественное число — user/users Функции — это строительные блоки вашего приложения. Одна функция — одно действие. Функции должны быть короткими и делать только что-то одно. Но иногда так хочется добавить новое условие в функцию или её расширить.. Это может привести к тому, что функция станет более сложночитаемой и не поддерживаемой. Например, вам понадобилось посчитать и вывести средний возраст пользователей: А потом понадобилось считать среднюю стоимость заказов пользователей: Может, пришло время сделать функционал расчета среднего значения реиспользуемым? Мы обработали кейс, когда в функцию пришёл пустой массив (чтобы не было деления на 0). Новая функция решает только одну задачу — принимает на вход массив значений, рассчитывает среднее значение и возвращает число. Никакой ответственности за вывод этого значения. Размер функции — достаточно холиварная тема. Чем меньше ваша функция, тем легче в неё вносить изменения и читать её. Хорошо если ваша функция влезает на один экран монитора. Typescript. Сложно представить сейчас проект без него. Typescript — это типизируемый язык программирования, компилирующийся в Javascript. Типы делают вашу жизнь проще во время разработки, спасая от части ошибок, а код становится более читаемым. Например, вот функция из примера выше: А вот эта же самая функция, но на Typescript: Первый взгляд на функцию (без погружения в тело) позволяет понять: с какими структурами работает функция; что возвращает на выход. IDE тоже отлично работают с typescript’ом. Если навести курсор на функцию или переменную, можно получить дополнительную информацию. Вот пример в Webstorm: Таким образом typescript от части “документирует” ваш код. Кроме того typescript гибко внедряется в проект. Вы можете как начать проект с нуля на нем, так и постепенно перевести существующую кодовую базу на него. Документация — это мощный инструмент, который делает ваш код более читаемым и понятным. Представьте, что придет другой разработчик, — поймет ли он, что происходит в коде? Что стоит документировать: бизнес-логику: большие функции: работу с публичными API; TODO/FIXME — важные префиксы для комментариев, при помощи которых вы можете обратить внимание на проблемный код; README — важная часть проекта. Открывая репозиторий по README, можно узнать краткую информацию о проекте и найти инструкцию по запуску. Всегда оформляйте README! Как документировать: Есть куча инструментов, позволяющих писать документацию. Но также есть встроенный инструмент — JSDoc. Вот пример задокументированной функции: Когда в IDE вы наведете курсор на вызов функции, то увидите следующее: Не проваливаясь в функцию, можно понять происходящее. Или можно пометить функцию как deprecated, то есть не рекомендованную к использованию. Если разработчик сделает импорт такой функции, он увидит, что она зачёркнута и при ховере появится подсказка: Не буду долго погружать вас в теорию тестирования. Это уже было в Симпсонах интернете: Как и зачем писать тесты Как тестировать современный фронтенд Доклад Саши Шинкевич про тестирование на Frontend Conf 2020 Если вкратце: для чего нужны тесты разработчику? Проверка себя (я написал функцию — она работает?). Стабильность (я улучшил/поменял/отрефачил/дополнил функцию — ничего не сломалось?) Покрытие редких кейсов (а если в качестве делителя юзер передаст 0?). Документация — тесты тоже документируют ваш код. Другой разработчик на примере теста может понять, как работать с написанной функцией. Основные виды тестов на фронте: Unit-тесты Тесты, которые проверяют работоспособность функций/утилит/модулей вашего кода. Пишутся при помощи jest и testing-library. Например, вспомним функцию из примера выше, которая считала среднее значение: Вот так могут выглядеть юнит-тесты для неё: Если наша функция корректна и тесты написаны верно, то мы увидим что все тесты прошли: Snapshopt-тесты Проверяют внешний вид компонента (буквально снимок компонента/верстки) Такие тесты могут нам просигнализировать, например, о том, что наш рефакторинг привел к изменению ожидаемого внешнего вида компонента. E2E-тесты Проверяют работоспособность приложения, отдельного функционала или пользовательского сценария (например, регистрация пользователя или добавление товара в корзину). Наиболее популярные библиотеки — Cypress или Puppeteer. Суть тестов заключается в том, чтобы проверить полноценный сценарий со стороны фронтенда. Например, описание теста, который можно написать для проверки пользовательского сценария регистрации. Зайди на сайт без авторизации. В шапке должна быть кнопка “sign up”. Кликни по ней. Должна открыться форма. Заполни её. Дождись замоканного с сервера ответа об успехе. Должен произойти редирект в личный кабинет. Есть ли у тестов минусы? Тесты увеличивают время на разработку. Их нужно поддерживать. Но тесты повышают стабильность вашего кода. Написанные тесты уменьшают вероятность выстрелить себе в ногу. Тесты — это хорошо. Пишите тесты. Prettier и Eslint могут сделать вашу жизнь лучше. Не пренебрегайте этими инструментами (даже если пишете маленький pet-проект). Eslint — статически анализирует ваш код и находит проблемы или помогает не совершать ошибки. Prettier — форматирует код, делая более приятным и читаемым. Необязательно в самом начале погружаться в конфиги — достаточно воспользоваться базовыми. Например, вот отличная инструкция по настройке. Настройка этих инструментов не занимает много времени, но делает ваш код приятнее как визуально, так и функционально, а также бьет вас по рукам, если вы хотите написать плохой код. Тут хотелось бы упомянуть несколько вещей. Количество строк в файлах Удобно ли читать файл длиной выше 1000 строк? Глаза устают бегать вверх-вниз, пытаясь уловить происходящее. В статьях и учебниках встречается разная рекомендованная длина файлов — от 100 до 500 строк (максимальное количество). По мне, 100 строк — это хорошо (без учета импортов). Если число строк в файле превысило лимит — задумайтесь над декомпозицией. Структура приложения, или организация файлов Можно скинуть все файлы проекта в одну в папку, можно разложить по папочкам. Как это лучше сделать? Есть ли стандарт? Существуют разные подходы к организации файлов в проекте. Приведу наиболее популярные: Domain Driven Design Business Logic Component Feature Sliced Design Для чего это? Стандартизация и упорядочивание. Вы можете познакомиться с указанными выше методологиями или прийти на проект, где используется существующая. Важно соблюдать организацию файлов. Алиасы По мере разрастания проекта и его файловой структуры можно встретить такую картину: Чтобы не плодить такие «гусеницы» импортов, можно настроить алиасы, которые будут вести к определенным папкам через сокращения, например: Лаконичнее, да? Алиасы можно прописать в tsconfig.json: Порядок импортов в файле. Старайтесь соблюдать порядок импортов в проекте: Рекомендованный порядок импортов: Сначала встроенные (главные) модули — если приложение на React, первым импортом будет идти React. Внешние импорты (модули и библиотеки из package.json). Внутренние абсолютные импорты (через алиасы). Внутренние относительные импорты. И отделяйте такие группы импортов между собой: Также добавлю, что это необязательно форматировать руками, можно настроить правило в eslint — sort-imports. Надеюсь, данные здесь советы помогут вам повысить качество вашего кода — писать более лаконичный, понятный другим разработчикам и поддерживаемый код, а также сократить число комментариев к вашим пул-реквестам. Для более глубокого погружения в тему рекомендую почитать указанные выше учебники. Всем приятного программирования!  Frontend developer