У нас є функція 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
).