Abbiamo una funzione API che suddivide un importo totale in importi mensili in base alle date di inizio e fine indicate.
// 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,
};
}
Di recente, un consumatore per questa API ha voluto specificare l'intervallo di date in altri modi: 1) fornendo il numero di mesi anziché la data di fine, oppure 2) fornendo il pagamento mensile e calcolando la data di fine. In risposta a ciò, il team API ha modificato la funzione nel modo seguente:
// 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),
};
}
Sento che questo cambiamento complica l'API. Ora il chiamante ha bisogno di preoccuparsi per l'euristica nascosti con l'implementazione della funzione nel determinare quali parametri prendono preferenza nell'essere utilizzato per calcolare l'intervallo di date (ad esempio in ordine di priorità monthlyPayment
, numMonths
, endDate
). Se un chiamante non presta attenzione alla firma della funzione, potrebbe inviare più parametri opzionali e confondersi sul motivo per cui endDate
viene ignorato. Specifichiamo questo comportamento nella documentazione della funzione.
Inoltre, ritengo che costituisca un precedente negativo e aggiunga all'API delle responsabilità che non dovrebbe riguardare (ovvero la violazione di SRP). Supponiamo che altri utenti desiderino che la funzione supporti più casi d'uso, come il calcolo total
dai parametri numMonths
e monthlyPayment
. Questa funzione diventerà sempre più complicata nel tempo.
La mia preferenza è mantenere la funzione com'era e invece richiedere al chiamante di calcolarsi endDate
. Tuttavia, potrei sbagliarmi e mi chiedevo se le modifiche apportate fossero un modo accettabile per progettare una funzione API.
In alternativa, esiste un modello comune per la gestione di scenari come questo? Potremmo fornire ulteriori funzioni di ordine superiore nella nostra API che racchiudono la funzione originale, ma questo gonfia l'API. Forse potremmo aggiungere un parametro flag aggiuntivo specificando quale approccio usare all'interno della funzione.
Date
- è possibile fornire una stringa e può essere analizzata per determinare la data. Tuttavia, in questo modo i parametri di gestione possono anche essere molto delicati e potrebbero produrre risultati inaffidabili. Vedi di Date
nuovo Non è impossibile fare la cosa giusta: Moment la gestisce meglio, ma è comunque molto fastidiosa da usare.
monthlyPayment
è dato ma total
non è un multiplo intero di esso. E anche come gestire eventuali errori di arrotondamento in virgola mobile se i valori non sono garantiti come numeri interi (ad esempio, provalo con total = 0.3
e monthlyPayment = 0.1
).