Как выявить дублирование кода?
Нет ничего плохого в том, что код дублируется. Но с небольшой оговоркой — он не должен дублировать знания. Поэтому, чтобы ответить на этот вопрос, сперва необходимо выяснить, является ли дублирование крода дублированием знаний. Это можно легко сделать проверив код на соответствие принципу единой ответственности (single-responsibility principle), который гласит (примерно): "функция должна иметь ровно одну причину для изменения".
Рассмотрим такой пример:
const validateFirstName = value => {
notEmpty(value);
lessThen100(value);
}
const validateLastName = value => {
notEmpty(value);
lessThen100(value);
}
Здесь мы видим две функции, которые, предположим, предназначены для валидации имени и фамилии при регистрации пользователя. Неопытным взглядом может показаться, что у нас тут одинаковые проверки и было бы неплохо вынести их в одно место, чтобы не дублировать код. Сказано — сделано:
// теперь код не дублируется и вынесен в отдельную функцию
const validateString = str => {
notEmpty(str);
lessThen100(str);
}
const validateFirstName = value => {
validateString(value);
}
const validateLastName = value => {
validateString(value);
}
Отлично? Сейчас выясним. Представьте, что от бизнеса пришло требование — проверять, чтобы фамилия состояла строго из одного слова. Можем ли мы внести это изменени, затронув только одну функцию? Почему бы и да:
const validateString = str => {
notEmpty(str);
lessThen100(str);
}
const validateFirstName = value => {
validateString(value);
}
const validateLastName = value => {
validateString(value);
theOnlyWord(value); // <= новая проверка
}
Отлично? Выясняем дальше. Теперь бизнес пришёл с новой задачей — увеличить возможную длину фамилии до 150 символов. Т.к. проверка длины находится в функции validateString
, которая в том числе участвует в валидации firstName
, то мы уже не можем поменять код так, чтобы он затрагивал только валидациюlastName
. Нам в любом случае придётся менять код так, что потребуются правки функции validateFirstName
.
Соответственно, мы не смогли поменять валидацию одного поля, не "задев" — другое. Проверка на SRP
не пройдена. Значит, такой код не является дублированием знаний и имеет полное право оставаться в исходном виде:
const validateFirstName = value => {
notEmpty(value);
lessThen100(value);
}
const validateLastName = value => {
notEmpty(value);
lessThen100(value);
}
Вместо заключения
Когда в коде встречается дублирование, то попробуйте ответить на вопрос: если нужно будет изменить этот код в одном месте, придётся ли менять его и в — другом? Если ответ — да, то это дублирование знаний и такой код нужно вынести в отдельное место. Если ответ — нет, то такой код не является дублированнием, а лишь в данный момент он выглядит точно так же, но несёт разные знания.
P.S. Нередко, когда я вижу дублирование, то ловлю себя на мысли, что его не стоит куда-то выносить. Для себя я объясняю это тем, что данный код невозможно выразить в виде абстракции, поэтому он намеренно дублируется. Благодаря этой книге я теперь могу спать спокойно, потому что нашёл своим действиям логическое обоснование.