Принцип DRY в программировании: почему это не всегда лучший выбор

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

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

Без использования принципа DRY у вас могут быть две отдельные функции, подобные этой:

function applyPercentageDiscount(price: number, discount: number): number {
  return price - (price * (discount / 100));
}

function applyFixedDiscount(price: number, discount: number): number {
  return price - discount;
}

Пытаясь применить принцип DRY, вы можете решить создать одну функцию, которая обрабатывает как процентные, так и фиксированные скидки, используя дополнительный параметр:

type DiscountType = 'percentage' | 'fixed';

function applyDiscount(price: number, discount: number, type: DiscountType): number {
  if (type === 'percentage') {
    return price - (price * (discount / 100));
  } else {
    return price - discount;
  }
}

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

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

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

interface Student {
  name: string;
  birthYear: number;
}

interface Teacher {
  name: string;
  birthYear: number;
}

function calculateStudentAge(student: Student): number {
  const currentYear = new Date().getFullYear();
  return currentYear - student.birthYear;
}

function calculateTeacherAge(teacher: Teacher): number {
  const currentYear = new Date().getFullYear();
  return currentYear - teacher.birthYear;
}

Чтобы применить принцип DRY, вы можете создать одну функцию, которая вычисляет возраст пользователя независимо от его роли:

interface User {
  name: string;
  birthYear: number;
}

function calculateAge(user: User): number {
  const currentYear = new Date().getFullYear();
  return currentYear - user.birthYear;
}

// Usage:
const student: User = { name: 'Alice', birthYear: 2000 };
const teacher: User = { name: 'Bob', birthYear: 1985 };

console.log(calculateAge(student)); // Student's age
console.log(calculateAge(teacher)); // Teacher's age

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

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

Читаемость и простота

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

Абстракция?

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

Связь?

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

Оптимизация?

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

Гибкость?

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

Заключение

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

Если вам понравился этот пост, обязательно загляните в наш новый блог по адресу https://codeconservatory.com/blog/1, где вы найдете больше подобного контента! Мы стремимся опубликовать больше инструментов и ресурсов, которые помогут вам в вашем путешествии по программированию.

Первоначально опубликовано на https://codeconservatory.com.