Понятный код - это код, который легко читать, менять и отлаживать. Ниже - чек-лист из 10 правил. Их удобно держать в голове при написании и ревью.
1) Имена должны отвечать на вопрос “что это” и “в каких единицах”
Плохо:
const x = 300;
const d = 5;
Лучше:
const timeoutMs = 300;
const daysCount = 5;
Если в проекте договоренность про единицы (Ms, Sec, Count) - код становится предсказуемее.
2) Одна функция - одна задача
Плохо: функция делает загрузку, преобразование и рендер.
async function loadAndRender() {
const response = await fetch("/api/items");
const items = await response.json();
const active = items.filter((x) => x.active);
document.querySelector("#out").textContent = String(active.length);
}
Лучше: отдельные функции по смыслу.
async function loadItems() {
const response = await fetch("/api/items");
if (!response.ok) {
throw new Error("HTTP " + response.status);
}
return response.json();
}
function countActive(items) {
return items.filter((x) => x.active).length;
}
function renderCount(root, value) {
root.textContent = String(value);
}
3) Ранний выход делает условия проще
Плохо: много вложенности.
function saveUser(user) {
if (user) {
if (user.name) {
return "ok";
} else {
return "no name";
}
} else {
return "no user";
}
}
Лучше: guard clauses.
function saveUser(user) {
if (!user) return "no user";
if (!user.name) return "no name";
return "ok";
}
4) Предсказуемые сравнения: === и явные проверки
Плохо: полагаться на приведение типов.
if (value == 0) {
// ...
}
Лучше: явное сравнение.
if (value === 0) {
// ...
}
Если ожидается число, лучше привести заранее.
const n = Number(value);
if (Number.isNaN(n)) return;
if (n === 0) return;
5) Сложные условия выносить в переменные с именами
Плохо: условие трудно читать.
if (user && user.role === "admin" && user.isActive && user.age >= 18) {
// ...
}
Лучше: читаемые части.
const isAdmin = user && user.role === "admin";
const isAllowedAge = user && user.age >= 18;
if (isAdmin && user.isActive && isAllowedAge) {
// ...
}
6) Не смешивать данные и представление
Плохо: функция логики возвращает HTML.
function buildHtml(items) {
return items.map((x) => "<li>" + x.title + "</li>").join("");
}
Лучше: логика возвращает данные, UI рисует отдельно.
function getTitles(items) {
return items.map((x) => x.title);
}
function renderList(root, titles) {
root.innerHTML = "";
for (const title of titles) {
const li = document.createElement("li");
li.textContent = title;
root.append(li);
}
}
7) Минимизировать мутации и побочные эффекты
Плохо: функция меняет входные данные неожиданно.
function sortNumbers(nums) {
return nums.sort((a, b) => a - b);
}
Лучше: копировать.
function sortNumbers(nums) {
return [...nums].sort((a, b) => a - b);
}
Побочные эффекты (DOM, сеть, localStorage) лучше держать в одном месте, а не “размазать” по всем файлам.
8) Делать “контракт” функции очевидным
Если функция ожидает объект определенной формы, это должно быть видно по коду.
Плохо:
function print(user) {
return user.name.toUpperCase();
}
Лучше: проверка входных данных или понятное имя.
function formatUserName(user) {
if (!user || typeof user.name !== "string") return "";
return user.name.toUpperCase();
}
9) Ошибки и ветки “неуспеха” должны быть видны
Для async-кода удобно:
- проверять
response.ok - выбрасывать ошибку с понятным сообщением
- ловить ее на верхнем уровне
async function loadJSON(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error("HTTP " + response.status);
}
return response.json();
}
async function run() {
try {
const data = await loadJSON("/api/data");
console.log(data);
} catch (e) {
console.log(e.message);
}
}
run();
10) Единый стиль: отступы, скобки, длина строк
Даже базовые договоренности делают код легче:
- одинаковые отступы (обычно 2 или 4 пробела)
- фигурные скобки в одном стиле
- одинаковые кавычки (например, только ”)
- понятные переносы строк, без “простыней” условий
Пример: лучше переносить цепочки и сложные вызовы.
const result = items
.filter((x) => x.active)
.map((x) => x.title);
Быстрый чек-лист перед коммитом
- Имена переменных понятны и не слишком короткие.
- Функции короткие и делают одну вещь.
- Вложенные if сведены к ранним выходам.
===используется по умолчанию.- Сложные условия вынесены в переменные.
- Логика не содержит DOM, UI не содержит правила.
- Мутации массивов/объектов осознанны или есть копии.
- Входные данные проверяются там, где это нужно.
- Ошибки обрабатываются и дают понятный сигнал.
- Стиль кода единый по всему проекту.