У нас есть функция API, которая разбивает общую сумму на ежемесячные суммы на основе заданных дат начала и окончания.
// JavaScript
function convertToMonths(timePeriod) {
// ... returns the given time period converted to months
}
function getPaymentBreakdown(total, startDate, endDate) {
const numMonths = convertToMonths(endDate - startDate);
return {
numMonths,
monthlyPayment: total / numMonths,
};
}
В последнее время потребитель этого API хотел указать диапазон дат другими способами: 1) путем указания количества месяцев вместо даты окончания или 2) путем предоставления ежемесячного платежа и расчета даты окончания. В ответ на это команда API изменила функцию на следующую:
// JavaScript
function addMonths(date, numMonths) {
// ... returns a new date numMonths after date
}
function getPaymentBreakdown(
total,
startDate,
endDate /* optional */,
numMonths /* optional */,
monthlyPayment /* optional */,
) {
let innerNumMonths;
if (monthlyPayment) {
innerNumMonths = total / monthlyPayment;
} else if (numMonths) {
innerNumMonths = numMonths;
} else {
innerNumMonths = convertToMonths(endDate - startDate);
}
return {
numMonths: innerNumMonths,
monthlyPayment: total / innerNumMonths,
endDate: addMonths(startDate, innerNumMonths),
};
}
Я чувствую, что это изменение усложняет API. Теперь абонент должен беспокоиться о эвристиках спрятанных с реализацией функции в определении того, какие параметры принимают предпочтение в настоящее время используется для расчета диапазона дат (т.е. в порядке приоритета monthlyPayment, numMonths, endDate). Если вызывающий не обращает внимания на сигнатуру функции, он может отправить несколько необязательных параметров и запутаться в том, почему endDateигнорируется. Мы определяем это поведение в документации по функциям.
Кроме того, я чувствую, что это создает плохой прецедент и добавляет в API обязанности, которыми он не должен заниматься (то есть нарушает SRP). Пусть дополнительные потребители хотят функции для поддержки большего числа случаев использования, например, вычисления totalот numMonthsи monthlyPaymentпараметров. Эта функция со временем будет становиться все более и более сложной.
Я предпочитаю оставить функцию такой, какой она была, и вместо этого требовать, чтобы вызывающая сторона вычисляла endDateсебя. Тем не менее, я могу ошибаться, и мне было интересно, были ли внесенные изменения приемлемым способом разработки функции API.
В качестве альтернативы, есть ли общий шаблон для обработки подобных сценариев? Мы могли бы предоставить дополнительные функции более высокого порядка в нашем API, которые обертывают исходную функцию, но это раздувает API. Возможно, мы могли бы добавить дополнительный параметр флага, определяющий, какой подход использовать внутри функции.
Date- вы можете поставить строку и может быть проанализирована , чтобы определить дату. Однако этот способ обработки параметров также может быть очень привередливым и может привести к ненадежным результатам. Смотри Dateснова. Это не невозможно сделать правильно - Момент справляется с этим лучше, но это очень раздражает в использовании, несмотря на это.
monthlyPaymentзадан, но totalне является кратным ему целым числом. А также, как бороться с возможными ошибками округления с плавающей запятой, если значения не гарантируются как целые числа (например, попробуйте с total = 0.3и monthlyPayment = 0.1).