Tenemos una función API que desglosa un monto total en montos mensuales en función de las fechas de inicio y finalización.
// 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,
};
}
Recientemente, un consumidor de esta API quería especificar el rango de fechas de otras maneras: 1) proporcionando el número de meses en lugar de la fecha de finalización, o 2) proporcionando el pago mensual y calculando la fecha de finalización. En respuesta a esto, el equipo de API cambió la función a la siguiente:
// 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),
};
}
Siento que este cambio complica la API. Ahora la persona que llama tiene que preocuparse por la heurística ocultos en la implementación de la función en la determinación de los parámetros que tienen preferencia en la que se utiliza para calcular el intervalo de fechas (es decir, por orden de prioridad monthlyPayment
, numMonths
, endDate
). Si una persona que llama no presta atención a la firma de la función, puede enviar varios de los parámetros opcionales y confundirse sobre por qué endDate
se ignora. Sí especificamos este comportamiento en la documentación de la función.
Además, creo que sienta un mal precedente y agrega responsabilidades a la API con las que no debería preocuparse (es decir, violar SRP). Suponga que consumidores adicionales desean que la función admita más casos de uso, como el cálculo a total
partir de los parámetros numMonths
y monthlyPayment
. Esta función se volverá cada vez más complicada con el tiempo.
Mi preferencia es mantener la función como estaba y, en cambio, exigirle a la persona que llama que se calcule endDate
. Sin embargo, puedo estar equivocado y me preguntaba si los cambios que hicieron fueron una forma aceptable de diseñar una función API.
Alternativamente, ¿hay un patrón común para manejar escenarios como este? Podríamos proporcionar funciones adicionales de orden superior en nuestra API que envuelvan la función original, pero esto aumenta la API. Tal vez podríamos agregar un parámetro de indicador adicional que especifique qué enfoque usar dentro de la función.
Date
- se puede suministrar una cadena y que se pueden analizar para determinar la fecha. Sin embargo, de esta manera, los parámetros de manejo también pueden ser muy delicados y pueden producir resultados poco confiables. Ver de Date
nuevo. No es imposible hacerlo bien: Moment lo maneja mucho mejor, pero es muy molesto de usar de todos modos.
monthlyPayment
se da pero total
no es un múltiplo entero. Y también cómo lidiar con posibles errores de redondeo de punto flotante si no se garantiza que los valores sean enteros (por ejemplo, pruébelo con total = 0.3
y monthlyPayment = 0.1
).