Эстетика в разработке, или Как качество кода влияет на успех бизнес-проекта

При разработке ИТ-продукта для бизнеса важен результат, но в погоне за скоростью и рентабельностью иногда забывают о главном – фундаменте проекта – качестве кодовой базы.

Эстетика в разработке, или Как качество кода влияет на успех бизнес-проекта

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

<i>Типичное лицо разработчика, зашедшего на такой проект</i>
Типичное лицо разработчика, зашедшего на такой проект

Все это в итоге может привести к тому, что команда будет выгорать, увеличится риск текучки на проекте. Если не уделять этому должного внимания, в конечном итоге это может грозить срывом спринтов и затягиванием времени выхода в продакшн. Чтобы сделать работу команды проекта удобнее и эффективнее, уменьшить процент багофикса, избежать хаоса и, в конце концов, «не запятнать» собственную репутацию в глазах коллег, необходимо соблюдать правила Code Style, применимые в профессиональном сообществе разработчиков.

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

Фокус на Coding conventions

Coding Conventions – это правила, которые важно использовать при написании кода, своего рода смысловое содержание кода. Чтобы система правильно считывала задачи, нужно соблюдать композицию, верные названия переменных и методов и т.п. Приведем примеры.

/*
Грамотное название переменных с отступами вокруг операторов ( = + - * / ):
*/

Эстетика в разработке, или Как качество кода влияет на успех бизнес-проекта

/*
Смысловое наименование функций/методов с отступами (обычно 2 или 4 пробела):
*/

Эстетика в разработке, или Как качество кода влияет на успех бизнес-проекта

/*
Композиция функций (вызов произвольного количества функций, возвращающих результат своего выполнения в другую функцию):
*/

Эстетика в разработке, или Как качество кода влияет на успех бизнес-проекта

Помощники в подготовке кода

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

В современных IDE (например, PHP/WebStorm, Visual Studio) есть и встроенные механизмы для форматирования кода.

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

Рассмотрим интеграцию модулей форматирования кода ESLint, Prettier, Husky и lint-staged для «чистого» проекта без учета особенностей выбранного JS-фреймворка.

Прежде всего, потребуется установить eslint и prettier, готовую конфигурацию (возьмем Airbnb) и плагины, чтобы связать prettier с eslint, а также «линтить» ошибки в инлайновых скриптах (внутри html) и конструкциях import/export:

npm i -D eslint prettier eslint-config-airbnb eslint-plugin-prettier eslint-plugin-html eslint-plugin-import

Далее в корне проекта создаем 2 файла: .eslintrc и .eslintignore.

В .eslintrc будет содержаться конфигурация нашего линтера:

{ "extends": ["airbnb/base"] }

В ключе “extends” содержится массив используемых конфигураций. В нашем случае мы используем базовую конфигурацию airbnb. Файл конфигурации может иметь и расширение .js, тогда внутри него нужно будет использовать CommonJS-конструкцию:

module.exports = { "extends": ["airbnb/base"] }

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

node_modules /.git /.vscode

Далее для удобства запуска линтера добавим в файл package.json команды:

... "scripts": { "lint": "eslint ./src", "lint:fix": "eslint ./src --fix --color" } ...

Далее для демонстрации работы линтера создадим в папке src файл с проектом app.js и добавим в него заведомо «криво» отформатированный код:

var a=33 function foo( name) { var lastName=name } var x =200; console.log(x)

И теперь в консоли можно запустить команду npm run lint:

Эстетика в разработке, или Как качество кода влияет на успех бизнес-проекта

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

Теперь запустим команду для автоматического исправления ошибок npm run lint:fix. Команда отработает, и наш исходный код примет следующий (исправленный) вид:

const a = 33; function foo(name) { const lastName = name; } const x = 200; console.log(x);

…а в консоли мы увидим:

Эстетика в разработке, или Как качество кода влияет на успех бизнес-проекта

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

const a = 33; function foo(name) { const lastName = name; return lastName; } foo('Vasya'); const x = 200; console.log(x, a);

Запустив повторно проверку проверку, получим в консоли одно некритичное замечание:

Эстетика в разработке, или Как качество кода влияет на успех бизнес-проекта

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

Следующий шаг в «эволюции» форматирования – умение настраивать проверку кода в момент совершения комита, а точнее непосредственно перед ним. Это необходимо, чтобы обезопасить репозиторий от несовершенного кода, не дав его закоммитить. Для этого можно использовать модули Husky и lint-staged.

Их принцип работы основан на срабатывании хуков git-репозитория, о которых можно почитать здесь. Нас интересует хук “pre-commit”.

На этом шаге уже должен быть проинициализирован репозиторий. Если это не сделано, можно запустить команду git init. Далее в консоли выполняем установку соответствующих модулей: npm i -D husky lint-staged

И для Husky, и для lint-staged можно создать отдельные конфигурационные файлы, но для простоты мы пропишем настройки непосредственно в package.json:

... "husky": { "hooks": { "pre-commit": "lint-staged" } }, "lint-staged": { "*.js": [ "npm run lint:fix", "git add" ] } ...

В нашей конфигурации для Husky мы указали команду, запускаемую “pre-commit”. Там же описали конфигурацию запуска “lint-staged”, указав ему выполнять для JS-файлов набор перечисленных команд, которые раньше делали бы вручную. Теперь при попытке закоммитить неправильный файл, коммит прервется и выведет в консоль список ошибок.

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

Подробнее можно почитать в оригинальной документации:

https://eslint.org/

https://prettier.io/

https://typicode.github.io/husky

Как создать проект, который можно поддерживать и масштабировать в перспективе?

Ответ – соблюдать принципы объектно-ориентированного программирования: абстракция, инкапсуляция, наследование, полиморфизм. Это позволит при возможных проблемах или изменениях быстро внести правки, легко расширить имеющийся функционал, скрыть детали реализации отдельных модулей, и еще предоставит много других преимуществ, что, в свою очередь, облегчит жизнь разработчикам.

Также полезным может оказаться умение применять подходящие под задачу паттерны программирования. В проекте может быть использовано сразу несколько паттернов, решающих определенные задачи. С основными из них можно ознакомиться в этой «шпаргалке». Например, для реализации логики выпадающего меню с разными состояниями (раскрыто, свернуто, недоступно и пр.), которое переходит из одного состояния в другое по определенным законам, идеально подойдет поведенческий паттерн “Состояние” (State pattern).

Свежий взгляд: Code Review

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

На код ревью необходимо закладывать дополнительное время и бюджет заказчика. Логично возникает вопрос, зачем это клиенту. Дело в том, что код-ревью, во-первых, не занимает столько времени, сколько может быть потрачено, например, на разработку новой фичи. Во-вторых, как мы упоминали выше, код становится понятным всем участникам команды, что в свою очередь может предотвратить неприятные сюрпризы в случае, если один из разработчиков, например, уходит в отпуск или на больничный, а другому предстоит дописывать его код. Впоследствии это еще и сокращает время разработки. Поэтому процесс code review важен как для поддержания чистоты кода, так и для избежания форс-мажорных ситуаций на проекте.

Также существуют программы для ревьюинга:

Их преимущество – в автоматизации процесса проверки кода, что существенно облегчает его оптимизацию.

«Палочка-выручалочка» в виде комментариев

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

/** * Возвращает статистику пользователя. * * @param {number} userId: Идентификатор пользователя * @param {string} type: тип статистики (enum {day, month, year}) * @param {string} object: предмет статистики * @param {number} dateStart: начальная дата (timestamp) * @param {number} dateEnd: конечная дата (timestamp) * @return {array}: массив записей со статистикой */ function getUserStat(userId, type, object, dateStart, dateEnd) { ... }

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

Во время собеседования на проект стоит уделить этому внимание. Можно уточнить, как разработчик оставляет сообщения в коммитах, достаточно ли они описывают, что было сделано, добавляет ли описание в пулл-реквесты и как иллюстрирует выполненный объем работ в задаче в таск-трекере, прикрепляет ли к ней в комментарии ссылку на пулл-реквест. Отчасти это может стать ключом к пониманию, есть ли у кандидата на проект подобная «вредная привычка».

Итоги

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

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

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

5353
73 комментария

Код должен решать задачу.
Оптимальным способом с минимальными издержками.
Не должен он быть эстетичным. Не должен быть красивым. Не должен радовать глаз разработчика.
Задачу он, блэт, поставленную должен решать.
Красивый и «эстетичный» код не гарантирует и даже не коррелирует с качеством.
Чистота кода может снижать издержки (стоимость поддержки и сложность онбординга), и то не всегда.
Но в огромном количестве случаев для бизнеса нести эти издержки выгоднее, чем «делать красиво».

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

7
Ответить

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

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

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

Правда есть два момента.
1. Далеко не всегда мы пишем с нуля, иногда приходим в функционирующий слипшийся спагетти-монолит. Тут конечно надо придерживаться золотой середины и не рефакторить весь проект в рамках первой же задачи.
2. Среди разрабов много таких, кто понятия не имеет, какой код - «красивый», но упорно его делает. Конечно, это потеря времени. Потом приходит другой и переделывает. Это проблема.

В общем, красивый код - важно даже не в долгосрочной, а в очень даже краткосрочной перспективе именно потому, что ресурсов на его поддержку (а 80% времени мы поддерживаем и развиваем) тратится гораздо меньше.

14
Ответить

а потом оказывается как у тинька "клиенты необоснованно обогатились на обмене валют"

Ответить

а потом разрабы в команде друг друга душат и дедовщину новичкам устраивают по "качеству" кода

хотя с частью тезисов я полностью согласен, просто у этого подхода полно минусов

2
Ответить

По новичкам - тяжело в учении, легко в бою 😉 Грамотный тимлид не допустит дедовщины на проекте!
"Душат друг друга" и "дедовщина" – это показатель слабой культуры разработки, неслаженной команды и/или отсутствия лидера, который вовремя может остановить перегибы. Мы считаем, что описанные в статье вещи способствуют порядку, при этом их выбор в каждой команде, конечно, свой)

5
Ответить

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

1
Ответить

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

Ответить