Декларативный код — что и как
Структуры в коде — Структуры данных; persistence — ORM.
Декларативный стиль описывает желаемый результат; императивный — пошаговые команды "как добиться". Функциональный язык для этого не обязателен: цель — чтобы читатель видел намерение без разбора циклов и счётчиков. Связь с MAPPER: код читается как псевдокод предметной области.
См. также императивный стиль, функциональное программирование, async.
"Что" и "как"
| Императивно (как) | Декларативнее (что) |
|---|---|
for + if + push | filter / map / LINQ / comprehensions |
if (a && !b || c) без имени | if (isEligibleForDiscount(order)) |
| Ручной разбор JSON поле за полем | deserialize в тип + валидация схемы |
| Вложенные callback | async/await, Promise.all, pipeline |
Один уровень абстракции в функции: либо бизнес-правило, либо деталь I/O — не оба сразу (связанность).
Имена вместо логики в лоб
- Магические числа → именованные константы или enum (
MaxRetries,VatRate). - Дурацкие имена методов (
doStuff,processData) → глагол + объект домена (IssueInvoice). - Двойное отрицание (
if (!isNotValid)) → положительный предикатif (isValid).
Комментарий "увеличиваем i" в цикле — признак того, что цикл можно заменить итератором с именем (for (const line of lines)).
Итерации
Заменяйте явные циклы там, где язык даёт идиому:
// Императивно
const adults = [];
for (const u of users) {
if (u.age >= 18) adults.push(u);
}
// Декларативнее
const adults = users.filter((u) => u.age >= 18);
var total = orders.Where(o => o.IsPaid).Sum(o => o.Amount);
Цикл for остаётся уместным для горячих участков, индексов и низкоуровневого кода — но не для "пройти и отфильтровать" в доменном слое.
Скрытые предположения → явные
Вынесите допущения в именованные проверки или типы.
// Скрыто: координаты в градусах, заказ в копейках
function distance(lat1, lon1, lat2, lon2) { ... }
// Явно
function distance(a: GeoPoint, b: GeoPoint): Kilometers { ... }
См. примитивы и value objects.
Callback hell и асинхронность
Пирамида обратных вызовов — вложенные .then / callback без имён.
// Плохо: «как» на полэкрана
getUser(id, (err, user) => {
getOrders(user, (err, orders) => { ... });
});
// Читаемее: последовательность намерений
const user = await getUser(id);
const orders = await getOrders(user);
Для параллельных запросов — Promise.all / Task.WhenAll с явным списком задач.
Сообщения об ошибках
Ошибка для человека — что случилось и что сделать, без внутреннего жаргона.
Неверный формат даты «31.02.2020». Укажите дату как ДД.ММ.ГГГГ.
"Магические исправления" (return 0, catch {}) маскируют дефект; лучше быстрый провал с ясным исключением или Result.
Регулярные выражения
Regex без имени — нечитаем. Вынесите в константу с комментарием-спецификацией или в класс EmailPattern / используйте парсер библиотеки. Для списка допустимых значений — enum или таблица, а не "универсальный" regex.
Условия Йоды
Переписывайте условия в форме "утверждение о мире", без отрицаний и лишних скобок. Связь с условиями и null (меньше if).
Версионированные методы
calculateV1, calculateV2 в одном классе — путаница. Оставьте одну рабочую версию; старую удалите или спрячьте за feature flag с датой снятия (YAGNI).
Пустые строки и область видимости
- Узкая область для переменных; не переиспользуйте
resultдля разных смыслов. - Лишние пустые строки внутри функции не добавляют смысл; группируйте логические блоки методами.
Декларативность vs производительность
Выбирайте читаемость, пока профилировщик не показал узкое место (преждевременная оптимизация). LINQ, лишние аллокации в hot path — оптимизируют после измерения.
Краткий чек-лист
| Тема | Действие |
|---|---|
| Область видимости | Короткая жизнь переменных |
| Магические числа | Константы, enum |
| Итерации | map / filter / LINQ в доменном слое |
| Async | async/await, Promise.all |
| Ошибки | Понятное сообщение, без пустого catch |
| Regex | Именованный паттерн или тип |
Подробнее по симптомам — справочник тем.
Куда дальше
- Изменяемость — иммутабельность поддерживает декларативные цепочки данных.
- Однострочные приёмы — краткие идиомы, когда они понятны команде.
- Культура написания — стандарты и форматтер.