Сталкивался ли с непониманием что делает код
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Сталкивался ли с непониманием что делает код
Да, это совершенно нормальная ситуация в разработке. Я сталкивался с этим множество раз, и каждый раз это была ценная возможность для обучения и улучшения кода. Вот несколько конкретных примеров и как я их решал.
Случай 1: Сложная комбинация higher-order functions
Однажды я работал с функцией, которая выглядела так:
const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);
const addTax = price => price * 1.1;
const applyDiscount = price => price * 0.9;
const roundPrice = price => Math.round(price * 100) / 100;
const calculatePrice = compose(roundPrice, applyDiscount, addTax);
console.log(calculatePrice(100)); // 99
Первое время я не сразу понял, что функция делает и в каком порядке применяются трансформации. Решение: я добавил типы TypeScript и более понятные имена, а также разбил логику на этапы с логированием:
type PriceTransformer = (price: number) => number;
const compose = (...fns: PriceTransformer[]): PriceTransformer =>
(x: number) => {
console.log("Initial price:", x);
return fns.reduceRight((acc, fn) => {
const result = fn(acc);
console.log("After", fn.name, ":", result);
return result;
}, x);
};
Случай 2: Магические значения и числа
В одном проекте я нашел вот такой код:
const formatDate = (date) => {
return new Date(date.getTime() - date.getTimezoneOffset() * 60000)
.toISOString()
.split("T")[0];
};
Это был кошмар для понимания. Я потратил 20 минут на то, чтобы разобраться, что здесь происходит. Решение: мы переписали это с понятными комментариями и тестами:
/**
* Форматирует дату в ISO 8601 формат с учетом временной зоны
* @param date - JavaScript Date объект
* @returns {string} Дата в формате YYYY-MM-DD
*/
const formatDateToLocal = (date: Date): string => {
// Получаем локальную дату (корректируем смещение временной зоны)
const timezoneOffsetMs = date.getTimezoneOffset() * 60 * 1000;
const localDate = new Date(date.getTime() - timezoneOffsetMs);
// Преобразуем в ISO строку и берем только дату (часть до T)
return localDate.toISOString().split("T")[0];
};
// Тесты
test("formatDateToLocal", () => {
const date = new Date("2024-01-15T10:00:00");
expect(formatDateToLocal(date)).toBe("2024-01-15");
});
Случай 3: Регулярные выражения
В коде аутентификации я нашел вот это:
const isValidEmail = (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
Технически это работает, но сложно читать. Решение: добавили константу с объяснением:
// Простая валидация email: не пусто @ не пусто . не пусто
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const isValidEmail = (email: string): boolean => {
return EMAIL_REGEX.test(email);
};
// Или лучше используем встроенную валидацию
const isValidEmail = (email: string): boolean => {
try {
new URL(`mailto:${email}`);
return true;
} catch {
return false;
}
};
Случай 4: Непредсказуемое поведение при работе с замыканиями
Мне встретилась ошибка в React компоненте:
function ItemsList({ items }) {
return items.map((item) => (
<button key={item.id} onClick={() => console.log(item.id)}>
{item.name}
</button>
));
}
Это выглядело корректно, но при быстрых кликах случались странные результаты. Решение: я разобрался, что проблема была в более сложной версии с асинхронностью:
// Плохо: замыкание может захватить неправильное значение
function ItemsList({ items }) {
return items.map((item) => (
<button key={item.id} onClick={() => {
setTimeout(() => {
// К моменту выполнения item может быть другим!
console.log(item.id);
}, 100);
}}>
{item.name}
</button>
));
}
// Хорошо: передаем id как параметр
function ItemsList({ items }) {
const handleClick = (id) => {
setTimeout(() => {
console.log(id);
}, 100);
};
return items.map((item) => (
<button key={item.id} onClick={() => handleClick(item.id)}>
{item.name}
</button>
));
}
Мой подход для решения непонимания кода
Шаг 1: Логирование и отладка
Добавляю console.log на ключевые этапы выполнения кода:
function mystereyFunction(input) {
console.log("Input:", input);
const step1 = processInput(input);
console.log("After step1:", step1);
const step2 = transformData(step1);
console.log("After step2:", step2);
return step2;
}
Шаг 2: Разбиение на части
Если функция большая и сложная, разбиваю её на меньшие функции с понятными именами.
Шаг 3: Добавление типов
TypeScript помогает понять, какие данные в какой момент обрабатываются.
Шаг 4: Написание тестов
Тесты показывают ожидаемое поведение кода и служат живой документацией.
Шаг 5: Документирование
Добавляю JSDoc комментарии с объяснением логики:
/**
* Вычисляет итоговую стоимость с учетом налогов и скидок
* @param {number} basePrice - базовая цена
* @param {number} discountPercent - процент скидки (0-100)
* @param {number} taxPercent - процент налога (0-100)
* @returns {number} итоговая цена
*/
function calculateTotal(basePrice, discountPercent, taxPercent) {
const discounted = basePrice * (1 - discountPercent / 100);
return discounted * (1 + taxPercent / 100);
}
Почему это случается
- Плохие имена переменных и функций —
x,temp,dataничего не говорят - Отсутствие комментариев — непонятно, почему код написан именно так
- Сложная логика в одной функции — функция делает слишком много
- Отсутствие типов — сложно понять, какие типы данных обрабатываются
- Отсутствие тестов — непонятно, какое поведение ожидается
- Очень старый код — стиль и подходы уже давно устарели
Заключение
Непонимание кода — нормальный процесс разработки. Важно не бояться спрашивать, логировать, читать документацию и рефакторить код для улучшения читаемости. В хорошей команде такие ситуации помогают улучшить качество кода и документацию.