Переиспользование кода — Примеры
Пример 1 — Два блока, похожих на дублирование
Ревьюер предлагает слить два расчёта ниже в одну функцию с параметром ставки; скажите, что на самом деле означает каждая константа и безопасно ли слияние.
const retail = base * 1.20; // цена магазина, её задаёт маркетинг
const wholesale = base * 1.07; // цена сделки, согласуется по каждому договору
Решение
одна форма, разные правила: розничная наценка — решение маркетинга, а
оптовая маржа — условие договора, поэтому изменение одного не имеет
причин менять другое.
держите их порознь. Одну функцию оправдало бы третье появление того же
правила — цена сделки в счёте и в коммерческом предложении, где обе
всегда должны совпадать.
Две строки делят только арифметику и ничего больше: у чисел разные владельцы, они меняются по разным причинам и их проверяют разные люди. Слияние создало бы функцию, через которую должно проходить каждое будущее решение о ценах, а это дороже двух читаемых констант. Ловушка в том, что код выглядит одинаково, поэтому слияние кажется очевидно верным, — вопрос не в том, совпадают ли строки, а в том, будут ли они всегда меняться вместе.
Пример 2 — Помощник с флагом для одного вызывающего
Общая функция ниже обзавелась булевым параметром, чтобы один вызывающий мог пропустить проверку. Скажите, чего это стоит остальным шести вызывающим, затем перепишите её.
function saveOrder(order, options: { skipValidation?: boolean } = {}) {
if (!options.skipValidation) validate(order);
return db.insert(order);
}
saveOrder(order); // шесть вызывающих
saveOrder(importedOrder, { skipValidation: true }); // один вызывающий
Решение
function saveValidatedOrder(order: Order) {
validate(order);
return db.insert(order);
}
function saveImportedOrder(order: Order) {
return db.insert(order); // проверено на границе импорта
}
// шесть вызывающих используют saveValidatedOrder; импортёр — вторую
Флаг превращает одну функцию в переключатель, и теперь каждый вызывающий должен знать, что флаг означает и какое значение верно для него, — шесть вызывающих, ничего не передающих, несут решение, которого никогда не принимают. Две именованные функции прячут каждое поведение за своим именем, поэтому место вызова говорит, что оно делает, не открывая помощника. Ловушка в том, что флаг в тот момент казался меньшим изменением, а второй флаг всегда легче добавить, чем было обосновать первый.