У нас есть функция 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
).