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

1. Пишите код так, будто сами будете проверять его в будущем

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

function process(x, y) {
  let temp = x * y;
  return temp + 5;
}

Более эффективный подход:

function calculateTotalPrice(itemPrice, quantity) {
  let totalCost = itemPrice * quantity;
  return totalCost + 5; // включает обработку для поставки
}

В оптимизированном коде имена itemPricequantity и totalCost сразу подскажут, что делает функция, и вам не придется пересматривать ее, чтобы понять ее назначение.

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

2. Четко определяйте каждый элемент

Разработчики со стажем знают, что дать корректное имя — половина успеха. Когда речь идет о переменных, функциях и классах, описательные имена — не роскошь, а необходимость. «Загадочные» имена вроде temp или data создают путаницу. Вместо этого четко определите, что представляет собой каждый элемент.

// Плохо
let temp = fetchData();

// Хорошо
let userData = fetchUserData();

Во втором примере очевидно, что делает fetchData(), в то время как первый порождает череду вопросов: хранит ли temp температуру, это временная переменная или что-то еще?

Неудачные имена заставляют читателей искать контекст, что замедляет работу.

3. Не повторяйтесь, но не напускайте «тумана»

Дублирование кода — печально известная болезнь, отбирающая много времени. Лучшее лекарство от нее — соблюдение принципа «DRY» (don’t repeat yourself — не повторяйся).

Плохая практика: 

function calculateTax(price) {
  return price * 0.13;
}

function calculateTotalWithTax(price) {
  let tax = price * 0.13;
  return price + tax;
}

Хорошая практика:

const TAX_RATE = 0.13;

function calculateTax(price) {
  return price * TAX_RATE;
}

function calculateTotalWithTax(price) {
  return price + calculateTax(price);
}

Извлечение константы TAX_RATE сделало код более ясным и удобным при повторном использовании, что упростит его модификацию в будущем (что если tax (налог) изменится на 15%?).

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

Плохая практика:

const calculate = (type, val1, val2) => type === 'sum' ? val1 + val2 : val1 - val2;

Хорошая практика:

const add = (a, b) => a + b;
const subtract = (a, b) => a - b;

4. Объясняйте в комментариях «почему», а не «что»

Каждый разработчик видел это:

i += 1; // увеличивает i

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

// Использование двоичного поиска для ускорения поиска в больших массивах
function findUser(arr, target) { ... }

Объясняя «почему», вы избавляете всех читателей кода от бесконечных вопросов по поводу вашей логики.

Код должен описывать,«что происходит», с помощью четкого именования и структуры. Комментарии нужны для того, чтобы обеспечить контекст.

5. Принцип единственной ответственности: используйте специализированные функции

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

Рассмотрим следующую функцию:

function fetchAndProcessAndSaveUserData() { ... }

Этот метод пытается выполнить несколько задач одновременно, а значит, отладка превращается в кошмар, а повторное использование становится невозможным.

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

function fetchUserData() { ... }
function processUserData(data) { ... }
function saveUserData(data) { ... }

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

Специализированные функции упрощают код и улучшают читаемость.

6. Контроль версий обязателен (но выполняйте его с осторожностью)

Случалось ли с вами такое: после внесения изменения нарушалась вся работа кода и вы не понимали, где все пошло не так?

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

Плохой коммит:

git commit -m "fixed bug"

Хороший коммит:

git commit -m "Fixed issue where user details weren't saved due to missing validation"

Описательные сообщения о коммитах помогут вам и вашей команде быстро понять суть изменений, не вникая в сам код. Такая практика позволяет избежать головной боли при отладке или просмотре изменений.

Относитесь к каждому коммиту как к записи в журнале, которая подробно описывает изменения в значимой форме.

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

7. Корректно обрабатывайте ошибки (поскольку сбои — признак непрофессионализма)

Представьте, что в приложении сбой, а сообщение об ошибке гласит: «Что-то пошло не так». Это недопустимо.

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

Плохая практика:

try {
  let data = fetchData();
} catch (error) {
  console.log(error);
}

Хорошая практика:

try {
  let data = fetchData();
} catch (error) {
  logError(error);
  showErrorNotification("Oops! Something went wrong. Please try again later.");
}

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

8. Пишите тесты

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

Тесты предотвращают регрессию, обеспечивают безопасность функций и дают уверенность при рефакторинге.

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

Плохая практика:

let price = calculateTotal(100);

// без модульных тестов

Хорошая практика:

describe('calculateTotal', () => {
  it('should return the correct total', () => {
    expect(calculateTotal(100)).toBe(115); // предположение налога 15 %
  });
});

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

9. Помните о зависимостях

Сталкивались ли вы когда-нибудь с проектом, для которого требуется 20 различных библиотек, причем невозможно понять, зачем нужна половина из них?

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

Плохая практика:

npm install lodash

Хорошая практика:

npm install lodash.debounce

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

Сокращение количества зависимостей означает меньше поводов для беспокойства, меньше сюрпризов при обновлении и более чистый и компактный проект.

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

import _ from 'lodash';
const isEqual = _.isEqual;

Вместо этого можно самостоятельно написать простое пользовательское решение, тем самым полностью устранив зависимость.

const isEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b);

10. Занимайтесь рефакторингом регулярно и тщательно

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

Плохая практика:

function processOrders(orderList) {
  for (let i = 0; i < orderList.length; i++) {
    if (orderList[i].status === 'pending') {
      // обработка заказа
    }
  }
}

Хорошая практика:

function filterPendingOrders(orderList) {
  return orderList.filter(order => order.status === 'pending');
}

function processOrders(orderList) {
  const pendingOrders = filterPendingOrders(orderList);
  pendingOrders.forEach(order => {
    // обработка заказа
  });
}

После разбиения процесса на две небольшие функции код стал модульным и более читабельным.

Подведение итогов

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

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Bishwa Poudel: 10 Coding Practices Every Senior Developer Swears By

Предыдущая статьяКэширование трендовых новостей в приложении TrendNow с помощью OkHttp Cache. Часть 6
Следующая статьяШаблон «Стратегия» на Go