Code Quality and Best Practices

Code Quality and Best Practices

  • 5 июня
  • читать 20 мин
Александра Донцова
Александра Донцова Front-end Developer в Sigma Software, Преподаватель Компьютерной школы Hillel.

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

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

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

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

ДОГОВОРЁННОСТЬ О НАИМЕНОВАНИИ ПЕРЕМЕННЫХ

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

1. Базовые договоренности:

camelCase для переменных и функций.

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

Примеры:

// Переменные

letuserName="John";// Корректно

letuser_age=25;// Некорректно (использование нижнего подчёркивания)

 

// Функции

functiongetUserInfo() {

// Корректно

}

functionget_user_info() {

// Некорректно (использование нижнего подчёркивания)

}

PASCAL CASE ДЛЯ КЛАССОВ

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

Примеры:

classUserAccount {

constructor(userName, userAge) {

this.userName=userName;

this.userAge=userAge;

  }
 

displayInfo() {

console.log(`${this.userName}, ${this.userAge}`);

  }

}
 

// Использование класса

letuser=newUserAccount("John", 25);

user.displayInfo();

UPPER CASE ДЛЯ КОНСТАНТ

UPPER CASE — стиль, где все буквы пишутся прописными, а слова разделяются нижним подчёркиванием. Эта конвенция используется для именования констант.

Примеры:

constMAX_USERS=100;// Корректно

constmaxUsers=100;// Некорректно (не соответствует конвенции)

 

constAPI_KEY="12345-abcde";// Корректно

constapiKey="12345-abcde";// Некорректно (не соответствует конвенции)

2. ОПИСАНИЕ ПЕРЕМЕННЫХ ИЛИ DESCRIPTIVE NAMES

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

Примеры:

// Переменные

letx=10;// Некорректно (непонятное имя)

letuserAge=10;// Корректно (четко описывает цель переменной)

 

// Функции

functioncalc(x, y) { // Некорректно (неясно, что именно вычисляется)

returnx+y;

}

 

functioncalculateSum(a, b) {// Корректно (четко описывает, что делает функция)

returna+b; 

}

 

// Классы

classU {

// Некорректно (непонятное название класса)

}

 

classUser {

// Корректно (понятное название класса, описывающего объект пользователя)

}

3. ИЗБЕГАНИЕ АББРЕВИАТУР (AVOID ABBREVIATIONS)

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

Примеры:

// Переменные

letusrNm="John";// Некорректно (использованы аббревиатуры)

letuserName="John";// Корректно (полное слово)

 

// Функции

functioncalcUsrAge(dob) {

// Некорректно (непонятная аббревиатура)

letage=newDate().getFullYear() -dob.getFullYear();

returnage;

}

 

functioncalculateUserAge(dateOfBirth) {

// Корректно (полные слова, понятное предназначение функции)

letage=newDate().getFullYear() -dateOfBirth.getFullYear();

returnage;

}

 

// Классы

classPrd {

// Некорректно (непонятная аббревиатура)

}

 

classProduct {

// Корректно (полное слово, понятное название класса)

}

СТРУКТУРА КОДА (CODE STRUCTURE)

Правильная структура кода помогает сделать ваш проект более понятным, легким для поддержки и расширения. Вот некоторые основные принципы:

1. Модульность (Modularity)

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

Примеры:

// Большая функция с несколькими ответственностями (Некорректно)

functionprocessUserData(user) {

validateUserData(user);

letprocessedData=transformData(user);

saveDataToDatabase(processedData);

}

 

// Маленькие функции с единой ответственностью (Корректно)

functionvalidateUserData(user) {

// Логика валидации

}

 

functiontransformData(user) {

// Логика трансформации данных

returntransformedData;

}

 

functionsaveDataToDatabase(data) {

// Логика сохранения данных

}

2. ОРГАНИЗАЦИЯ ФАЙЛОВ (FILE ORGANIZATION)

Организация файлов состоит в логической группировке файлов, модулей и компонентов. Это делает кодовую базу более понятной и более лёгкой для навигации.

Примеры:

// Некорректная организация файлов

project/

├── script1.js

├── script2.js

├── script3.js

 

// Корректная организация файлов

project/

├── components/

│   ├── Header.js

│   ├── Footer.js

├── services/

│   ├── apiService.js

│   ├── authService.js

├── utils/

│   ├── helpers.js

3. РАЗДЕЛЕНИЕ ОТВЕТСТВЕННОСТЕЙ (SEPARATION OF CONCERNS)

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

Примеры:

// Без разделения ответственности (Некорректно)

functionrenderUserProfile(user) {

letuserData=fetchUserData(user.id);// Логика обработки данных

letuserProfileHTML=`<div>${userData.name}</div>`;// Логика UI

document.body.innerHTML=userProfileHTML;

}

 

// С разделением ответственности (Корректно)

functionfetchUserData(userId) {

// Логика обработки данных

returnuserData;

}

 

functiongenerateUserProfileHTML(userData) {

// Логика UI

return`<div>${userData.name}</div>`;

}

 

functionrenderUserProfile(userId) {

letuserData=fetchUserData(userId);

letuserProfileHTML=generateUserProfileHTML(userData);

document.body.innerHTML=userProfileHTML;

}

ЧИТАБЕЛЬНОСТЬ (READABILITY)

Читаемость кода является ключевой для его понимания и поддержки. Вот несколько важных аспектов:

1. Отступы (Indentation)

Отступы помогают организовать код и делают его более лёгким для чтения. Обычно используется отступ в 2 или 4 пробела.

Примеры:

// Отступление в 2 пробела (Корректно)

functioncalculateTotal(price, tax) {

lettotal=price+tax;

returntotal;

}

 

// Отступление в 4 пробела (Корректно)

functioncalculateTotal(price, tax) {

lettotal=price+tax;

returntotal;

}

 

// Неподходящее отступление (Некорректно)

functioncalculateTotal(price, tax) {

lettotal=price+tax;

returntotal;

}

2. ДЛИНА СТРОК (LINELENGHT)

Длина строк должна быть умеренной, обычно не более 80-100 символов. Это делает код более лёгким для чтения и просмотра.

Примеры:

// Короткие строки (Корректно)

functiongetUserInfo(userId) {

letuser=fetchUserFromDatabase(userId);

returnuser;

}

 

// Длинные строки (Некорректно)

functiongetUserInfo(userId) { letuser=fetchUserFromDatabase(userId); returnuser; }

3. КОММЕНТАРИИ (COMMENTS)

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

Примеры:

// Очевидные комментарии (Некорректно)

letuserName="John";// Переменная userName устанавливается значение "John"

 

// Пояснительные комментарии (Корректно)

letuserName=fetchUserName();// Получение имени пользователя из базы данных

 

// Сложная логика

functioncalculateDiscount(price, discount) {

// Проверка, скидка ли не превышает цену

if (discount>price) {

returnprice;

  }

returnprice-discount;

}

ИЗБЕГАНИЕ СЛОЖНОСТИ (AVOIDING COMPLEXITY)

Избегание сложности кода делает код более лёгким для чтения, понимания и поддержки. Вот несколько важных аспектов:

1. Упрощение логики (SimplifyLogic)

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

Преимущества:

- понятность: код становится более лёгким для чтения и понимания;
- поддержка: проще найти и исправить ошибки в меньшей функции.

Примеры:

// Глубокое вложение условий (Некорректно)

functionprocessOrder(order) {

if (order.isValid) {

if (order.items.length>0) {

if (order.paymentStatus==='paid') {

// Выполнить заказ

      }

    }

  }

}

 

// Разделение логики на меньшие функции (Корректно)

functionisOrderValid(order) {

returnorder.isValid&&order.items.length>0&&order.paymentStatus==='paid';

}

 

functionprocessOrder(order) {

if (isOrderValid(order)) {

// Выполнить заказ

  }

}

2. ПРИНЦИП DRY (DON'T REPEAT YOURSELF)

Принцип DRY (Don'tRepeatYourself) означает повторное использование кода везде, где это возможно во избежание дублирования. Выносите повторяющийся код в функции или модуле.

Преимущества:

- уменьшение кода: меньше кода для поддержки;
- лёгкость обновления: изменения следует вносить только в одном месте.

Примеры:

// Дублирование кода (Некорректно)

functioncalculateAreaOfRectangle(width, height) {

returnwidth*height;

}

 

functioncalculateAreaOfTriangle(base, height) {

return0.5*base*height;

}

 

// Использование общей функции (Корректно)

functioncalculateArea(shape, dimension1, dimension2) {

if (shape==='rectangle') {

returndimension1*dimension2;

  } elseif (shape==='triangle') {

return0.5*dimension1*dimension2;

  }

}

 

// Использование общей функции

letrectangleArea=calculateArea('rectangle', 5, 10);

lettriangleArea=calculateArea('triangle', 5, 10);

ОБРАБОТКА ОШИБОК (ERROR HANDLING)

Обработка ошибок является важной частью написания надёжного и устойчивого кода. Вот несколько ключевых аспектов:

1. Качественная обработка ошибок (ErrorHandling)

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

Преимущества:

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

Примеры:

// Качественная обработка ошибок

functionfetchUserData(userId) {

try {

letresponse=fetch(`https://api.example.com/users/${userId}`);

if (!response.ok) {

thrownewError('Network response was not ok');

    }

letuserData=response.json();

returnuserData;

  } catch (error) {

console.error('Fetch user data failed:', error);

return { error:'Failed to fetch user data. Please try again later.' };

  }

}

2. ВАЛИДАЦИЯ (VALIDATION)

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

Примеры:

// Валидация входных данных

functioncalculateTotal(price, tax) {

if (typeofprice!=='number'||typeoftax!=='number') {

thrownewError('Invalid input: price and tax should be numbers');

  }

returnprice+tax;

}

 

// Валидация пользовательского ввода

functionhandleFormSubmit(event) {

event.preventDefault();

letuserName=document.getElementById('userName').value;

if (!userName) {

alert('User name is required');

return;

  }

// Обработка формы

}

ПОЧЕМУ ЭТО ВАЖНО?

  1. Удобство чтения и понимания кода: использование согласованных наименований переменных делает код более понятным и более лёгким для чтения, особенно для новых членов команды. Чёткие и описательные имена, упрощенная логика и хорошо организованные файлы способствуют лучшему пониманию кода.
  2. Облегчение поддержки: когда весь код написан в одном стиле и структурирован логически, его легче поддерживать, обнаруживать и исправлять ошибки. Валидация и правильная обработка ошибок обеспечивают надёжность и стойкость приложений.
  3. Увеличение производительности: согласованность уменьшает время, потраченное на понимание кода, что позволяет разработчикам быстрее ориентироваться в кодовой базе и сосредоточиться на решении задач. Повторное использование кода (принцип DRY) уменьшает дублирование и облегчает поддержку.

РЕКОМЕНДАЦИЯ

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

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

Рекомендуем курсы по теме