Загадка комментариев: почему комментарии к коду могут быть признаком плохого кода
В мире разработки программного обеспечения ведутся давние споры о роли комментариев к коду. Хотя некоторые утверждают, что комментарии необходимы для ясности и документирования, другие рассматривают их как признак некачественного кода. Давайте рассмотрим аргумент о том, что комментарии к коду действительно могут быть признаком проблем, и узнаем, почему самодокументируемый код часто является лучшим выбором.
Определение запаха кода
Прежде всего, важно понять, что такое запах кода. Запах кода — это не обязательно ошибка, а скорее указание на то, что что-то может быть не так или может быть улучшено. Это намёк на то, что код может не соответствовать лучшим практикам или принципам чистого кодирования.
Проблема комментариев «что»
Комментарии, которые объясняют, что делает код, часто считаются запахом кода. Вот почему: если вашему коду нужен комментарий, чтобы объяснить его назначение, это, вероятно, означает, что сам код недостаточно ясен. Здесь возникает концепция комментариев «что»: это комментарии, описывающие, что происходит в определённом участке кода, которые могут маскировать другие запахи кода.
Например, рассмотрим следующий фрагмент кода:
# Рассчитать общую стоимость заказа
total = 0
for i in range(len(items)):
total += qty[i] * price[i]
return total
В этом примере комментарий «Рассчитать общую стоимость заказа» избыточен, потому что сам код должен быть достаточно ясным, чтобы передать эту информацию. Лучшим подходом было бы использовать описательные имена переменных и функций:
def calculate_total_cost(items, quantities, prices):
total_cost = 0
for i in range(len(items)):
total_cost += quantities[i] * prices[i]
return total_cost
# Использование
items = ["item1", "item2", "item3"]
quantities = [2, 3, 4]
prices = [10, 20, 30]
total_cost = calculate_total_cost(items, quantities, prices)
print(total_cost)
Здесь имя функции calculate_total_cost
ясно объясняет, что делает код, делая комментарий ненужным.
Ценность комментариев «почему»
Не все комментарии одинаковы. Комментарии, объясняющие, почему код написан определённым образом, бесценны. Эти комментарии «почему» предоставляют контекст, который может быть неочевиден из самого кода. Они помогают другим разработчикам (или даже тому же разработчику спустя месяцы) понять логику конкретной реализации.
Например:
# Если приведённый ниже код сработал, значит, веб-сокет, найденный в общей библиотеке, вышел из строя.
# Это указывает на то, что кто-то что-то сломал в общей библиотеке.
if websocket_connection_failed:
handle_failure()
В этом случае комментарий объясняет намерение и контекст кода, что имеет решающее значение для поддержки и понимания кодовой базы.
Методы написания самодокументируемого кода
Итак, как мы можем написать код, который будет самодокументироваться? Вот несколько практических приёмов:
Используйте осмысленные имена
Один из наиболее эффективных способов сделать ваш код самодокументируемым — использовать осмысленные имена для переменных, функций, классов и модулей. Вот пример сравнения плохих и хороших практик:
# Плохо
x = 5
y = 10
z = x + y
# Хорошо
number_of_items = 5
item_price = 10
total_cost = number_of_items * item_price
Использование понятных и описательных имён делает код более читаемым и понятным.
Пишите небольшие, целенаправленные функции
Разбиение сложной логики на более мелкие, целенаправленные функции — ещё один ключевой аспект самодокументируемого кода. Вот пример:
# Плохо
def process_data(data):
# Много сложной логики
return result
# Хорошо
def extract_relevant_fields(data):
# Извлечение релевантных полей
return relevant_fields
def apply_business_rules(relevant_fields):
# Применение бизнес-правил
return processed_data
def format_output(processed_data):
# Форматирование вывода
return formatted_result
Давая каждой функции отдельную задачу и описательное название, вы делаете код более читаемым и удобным в обслуживании.
Используйте системы типов
Системы типов, особенно в таких языках, как TypeScript, могут значительно улучшить самодокументирование вашего кода. Вот как вы можете использовать интерфейсы и перечисления, чтобы сделать свой код более выразительным:
interface User {
id: number;
name: string;
email: string;
}
enum PaymentStatus {
Pending = 'pending',
Completed = 'completed',
Failed = 'failed',
}
function getUserById(id: number): User | undefined {
// Реализация
}
function processPayment(status: PaymentStatus): void {
// Реализация
}
Используя интерфейсы и перечисления, вы определяете структуру своих структур данных и делаете код более понятным и понятным.
Роль тестов в документации
Тесты также могут служить формой документации. Организуя свои тесты таким образом, чтобы документировать поведение приложения, вы можете избежать необходимости в отдельных комментариях. Этот подход является частью разработки, управляемой поведением (BDD).
Вот пример того, как тесты могут документировать систему:
def test_calculate_total_cost():
items = ["item1", "item2", "item3"]
quantities = [2, 3, 4]
prices = [10, 20, 30]
expected_total_cost = 200
assert calculate_total_cost(items, quantities, prices) == expected_total_cost
В этом примере тест чётко документирует ожидаемое поведение функции calculate_total_cost
.
Заключение и призыв к действию
Комментарии к коду, особенно те, которые объясняют, что делает код, часто могут быть признаком некачественного кода. Сосредоточившись на самодокументируемом коде с помощью осмысленных имён, небольших целенаправленных функций и использования систем типов, мы можем сделать наш код более удобочитаемым и удобным в сопровождении.
Вот простая блок-схема, суммирующая этот подход:
Конечная цель — написать понятный, удобный в поддержке и самодокументированный код. Применяя эти практики, мы можем уменьшить потребность в комментариях и сделать работу с нашими базами кода более приятной.
Поэтому в следующий раз, когда вы будете писать комментарий, объясняющий, что делает ваш код, остановитесь и спросите себя: «Могу ли я заставить этот код говорить сам за себя?» Ответ может навсегда изменить то, как вы пишете код.