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

1. Имена должны объяснять намерение

Хорошее имя переменной, функции или класса делает комментарий ненужным. Сравните:

Плохо Хорошо Почему
d elapsedDays Что такое d? Дата? Дистанция? Без контекста непонятно
process() calculateMonthlyRevenue() «Обработать» — это всё что угодно. Конкретное имя описывает действие
data userProfiles data — самое бессмысленное имя после temp
flag isEmailVerified Булевы переменные начинаются с is/has/can/should

Правило: если для понимания переменной нужно заглянуть в определение — имя плохое. Длинное имя лучше короткого, но непонятного.

2. Функции делают одно дело

Функция должна выполнять одну задачу и делать это хорошо. Признак нарушения — союз «и» в описании: «валидирует данные И сохраняет в базу И отправляет email». Это три функции, а не одна.

Оптимальный размер функции — 5–20 строк. Если функция не помещается на один экран — скорее всего, она делает слишком много. Выделите подзадачи в отдельные функции с понятными именами.

3. Избегайте магических чисел и строк

Число 86400 в коде — что это? Секунды в сутках, максимальный размер файла, ID пользователя? Замените на именованную константу SECONDS_IN_DAY = 86400. Это касается любых литералов, смысл которых неочевиден: статус-коды, лимиты, URL-адреса, конфигурационные значения.

4. Комментируйте «почему», а не «что»

Комментарий «увеличиваем счётчик на 1» к строке counter += 1 — бесполезен. Код уже говорит «что» происходит. Ценный комментарий объясняет «почему»: бизнес-правило, ограничение внешней системы, неочевидный выбор алгоритма.

Примеры хороших комментариев:

  • // Stripe API возвращает сумму в центах, конвертируем в доллары
  • // Таймаут 30с — требование SLA от платёжного провайдера
  • // Используем бинарный поиск вместо хеш-таблицы, потому что данные уже отсортированы

5. Ранний возврат вместо глубокой вложенности

Код с пятью уровнями вложенности if-else нечитаем. Используйте guard clauses — ранний возврат при невалидных условиях:

Вместо вложенных проверок «если пользователь существует, то если он активен, то если у него есть разрешение…» — инвертируйте условия: «если пользователь не существует — return ошибку, если неактивен — return ошибку, если нет разрешения — return ошибку». Основная логика остаётся на первом уровне вложенности.

6. DRY, но без фанатизма

Don’t Repeat Yourself — один из самых известных принципов, и один из самых переиспользованных. Дублирование — зло, когда два фрагмента кода меняются по одной и той же причине. Но если два похожих фрагмента обслуживают разные бизнес-домены — объединять их в одну абстракцию опасно.

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

7. Обрабатывайте ошибки явно

Пустые catch-блоки — техдолг, который рано или поздно выстрелит. Каждая потенциальная ошибка должна быть либо обработана (retry, fallback, сообщение пользователю), либо проброшена наверх с контекстом. Логируйте ошибку с достаточным контекстом для отладки: что произошло, с какими данными, в какой точке.

8. Пишите тесты как документацию

Хороший тест описывает поведение системы на человеческом языке. Используйте формат «given-when-then» в именах: test_expired_subscription_denies_access() сообщает больше, чем test_subscription_1().

Покрытие 100% — не цель. Покрывайте в первую очередь: бизнес-логику, граничные случаи, интеграции с внешними системами. Тесты на геттеры и сеттеры — пустая трата времени.

9. Структурируйте проект по фичам, а не по типам

Организация по типам файлов (/controllers, /models, /services) плохо масштабируется — при 50 файлах в каждой папке навигация превращается в кошмар. Организация по фичам (/users, /payments, /notifications) группирует связанный код вместе и упрощает работу с конкретной функциональностью.

10. Рефакторите постоянно и маленькими шагами

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

Не нужно переписывать проект, чтобы код стал чистым. Достаточно принять эти принципы как ежедневную привычку — и качество будет расти инкрементально с каждым коммитом.