Is there a pattern for handling conflicting function parameters?How do you deal with errors in enumeration / list processing (lowish-level API)As an API-user, would you tolerate BestPractice Exceptions?When writing a library or an API, when should and when shouldn't I validate or automatically correct errors in data provided by another developer?Idiomatic wrapping of C++ template type API in CCollection properties and initializer lists in .Net API designWhat HTTP action and return value should be used on resource's actionHandling Different Parameters for Derived Classes

Did Tolkien ever write about a Heaven or Hell for Men?

How does Monks' Improved Unarmored Movement work out of combat?

Incomplete iffalse: How to shift a scope in polar coordinate?

How to study endgames?

Can you cure a Gorgon's Petrifying Breath before it finishes turning a target to stone?

Calculate the Ultraradical

Delete n lines skip 1 line script

grounded outlets and code compliance

What are one's options when facing religious discrimination at the airport?

Beyond Futuristic Technology for an Alien Warship?

Why does `FindFit` fail so badly in this simple case?

Replacing cord for IBM model M keyboard

How do I introduce dark themes?

Is there an in-universe explanation of how Frodo's arrival in Valinor was recorded in the Red Book?

Windows 10 deletes lots of tiny files super slowly. Anything that can be done to speed it up?

Verb ending in -ん with positive meaning?

Why has Speaker Pelosi been so hesitant to impeach President Trump?

How can I visualize an ordinal variable predicting a continuous outcome?

If a spaceship ran out of fuel somewhere in space between Earth and Mars, does it slowly drift off to the Sun?

If someone asks a question using “quién”, how can one shortly respond?

Accessing JSON fields in html of LWC

Create the same subfolders in another folder

Would an object shot from earth fall into the sun?

Do my potential customers need to understand the "meaning" of a logo, or just recognize it?



Is there a pattern for handling conflicting function parameters?


How do you deal with errors in enumeration / list processing (lowish-level API)As an API-user, would you tolerate BestPractice Exceptions?When writing a library or an API, when should and when shouldn't I validate or automatically correct errors in data provided by another developer?Idiomatic wrapping of C++ template type API in CCollection properties and initializer lists in .Net API designWhat HTTP action and return value should be used on resource's actionHandling Different Parameters for Derived Classes






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








4















We have an API function that breaks down a total amount into monthly amounts based on given start and end dates.



// 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,
;



Recently, a consumer for this API wanted to specify the date range in other ways: 1) by providing the number of months instead of the end date, or 2) by providing the monthly payment and calculating the end date. In response to this, the API team changed the function to the following:



// 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),
;



I feel this change complicates the API. Now the caller needs to worry about the heuristics hidden with the function's implementation in determining which parameters take preference in being used to calculate the date range (i.e. by order of priority monthlyPayment, numMonths, endDate). If a caller doesn't pay attention to the function signature, they might send multiple of the optional parameters and get confused as to why endDate is being ignored. We do specify this behavior in the function documentation.



Additionally I feel it sets a bad precedent and adds responsibilities to the API that it should not concern itself with (i.e. violating SRP). Suppose additional consumers want the function to support more use cases, such as calculating total from the numMonths and monthlyPayment parameters. This function will become more and more complicated over time.



My preference is to keep the function as it was and instead require the caller to calculate endDate themselves. However, I may be wrong and was wondering if the changes they made were an acceptable way to design an API function.



Alternatively, is there a common pattern for handling scenarios like this? We could provide additional higher-order functions in our API that wrap the original function, but this bloats the API. Maybe we could add an additional flag parameter specifying which approach to use inside of the function.










share|improve this question





















  • 4





    "Recently, a consumer for this API wanted to [provide] the number of months instead of the end date" - This is a frivolous request. They can transform the # of months into a proper end date in a line or two of code on their end.

    – Graham
    9 hours ago

















4















We have an API function that breaks down a total amount into monthly amounts based on given start and end dates.



// 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,
;



Recently, a consumer for this API wanted to specify the date range in other ways: 1) by providing the number of months instead of the end date, or 2) by providing the monthly payment and calculating the end date. In response to this, the API team changed the function to the following:



// 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),
;



I feel this change complicates the API. Now the caller needs to worry about the heuristics hidden with the function's implementation in determining which parameters take preference in being used to calculate the date range (i.e. by order of priority monthlyPayment, numMonths, endDate). If a caller doesn't pay attention to the function signature, they might send multiple of the optional parameters and get confused as to why endDate is being ignored. We do specify this behavior in the function documentation.



Additionally I feel it sets a bad precedent and adds responsibilities to the API that it should not concern itself with (i.e. violating SRP). Suppose additional consumers want the function to support more use cases, such as calculating total from the numMonths and monthlyPayment parameters. This function will become more and more complicated over time.



My preference is to keep the function as it was and instead require the caller to calculate endDate themselves. However, I may be wrong and was wondering if the changes they made were an acceptable way to design an API function.



Alternatively, is there a common pattern for handling scenarios like this? We could provide additional higher-order functions in our API that wrap the original function, but this bloats the API. Maybe we could add an additional flag parameter specifying which approach to use inside of the function.










share|improve this question





















  • 4





    "Recently, a consumer for this API wanted to [provide] the number of months instead of the end date" - This is a frivolous request. They can transform the # of months into a proper end date in a line or two of code on their end.

    – Graham
    9 hours ago













4












4








4








We have an API function that breaks down a total amount into monthly amounts based on given start and end dates.



// 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,
;



Recently, a consumer for this API wanted to specify the date range in other ways: 1) by providing the number of months instead of the end date, or 2) by providing the monthly payment and calculating the end date. In response to this, the API team changed the function to the following:



// 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),
;



I feel this change complicates the API. Now the caller needs to worry about the heuristics hidden with the function's implementation in determining which parameters take preference in being used to calculate the date range (i.e. by order of priority monthlyPayment, numMonths, endDate). If a caller doesn't pay attention to the function signature, they might send multiple of the optional parameters and get confused as to why endDate is being ignored. We do specify this behavior in the function documentation.



Additionally I feel it sets a bad precedent and adds responsibilities to the API that it should not concern itself with (i.e. violating SRP). Suppose additional consumers want the function to support more use cases, such as calculating total from the numMonths and monthlyPayment parameters. This function will become more and more complicated over time.



My preference is to keep the function as it was and instead require the caller to calculate endDate themselves. However, I may be wrong and was wondering if the changes they made were an acceptable way to design an API function.



Alternatively, is there a common pattern for handling scenarios like this? We could provide additional higher-order functions in our API that wrap the original function, but this bloats the API. Maybe we could add an additional flag parameter specifying which approach to use inside of the function.










share|improve this question
















We have an API function that breaks down a total amount into monthly amounts based on given start and end dates.



// 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,
;



Recently, a consumer for this API wanted to specify the date range in other ways: 1) by providing the number of months instead of the end date, or 2) by providing the monthly payment and calculating the end date. In response to this, the API team changed the function to the following:



// 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),
;



I feel this change complicates the API. Now the caller needs to worry about the heuristics hidden with the function's implementation in determining which parameters take preference in being used to calculate the date range (i.e. by order of priority monthlyPayment, numMonths, endDate). If a caller doesn't pay attention to the function signature, they might send multiple of the optional parameters and get confused as to why endDate is being ignored. We do specify this behavior in the function documentation.



Additionally I feel it sets a bad precedent and adds responsibilities to the API that it should not concern itself with (i.e. violating SRP). Suppose additional consumers want the function to support more use cases, such as calculating total from the numMonths and monthlyPayment parameters. This function will become more and more complicated over time.



My preference is to keep the function as it was and instead require the caller to calculate endDate themselves. However, I may be wrong and was wondering if the changes they made were an acceptable way to design an API function.



Alternatively, is there a common pattern for handling scenarios like this? We could provide additional higher-order functions in our API that wrap the original function, but this bloats the API. Maybe we could add an additional flag parameter specifying which approach to use inside of the function.







api-design






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 9 hours ago







CalMlynarczyk

















asked 10 hours ago









CalMlynarczykCalMlynarczyk

1244 bronze badges




1244 bronze badges










  • 4





    "Recently, a consumer for this API wanted to [provide] the number of months instead of the end date" - This is a frivolous request. They can transform the # of months into a proper end date in a line or two of code on their end.

    – Graham
    9 hours ago












  • 4





    "Recently, a consumer for this API wanted to [provide] the number of months instead of the end date" - This is a frivolous request. They can transform the # of months into a proper end date in a line or two of code on their end.

    – Graham
    9 hours ago







4




4





"Recently, a consumer for this API wanted to [provide] the number of months instead of the end date" - This is a frivolous request. They can transform the # of months into a proper end date in a line or two of code on their end.

– Graham
9 hours ago





"Recently, a consumer for this API wanted to [provide] the number of months instead of the end date" - This is a frivolous request. They can transform the # of months into a proper end date in a line or two of code on their end.

– Graham
9 hours ago










3 Answers
3






active

oldest

votes


















9
















Seeing the implementation, it appears to me what you really require here is 3 different functions instead of one:



The original one:



function getPaymentBreakdown(total, startDate, endDate) 


The one providing the number of months instead of the end date:



function getPaymentBreakdownByNoOfMonths(total, startDate, noOfMonths) 


and the one providing the monthly payment and calculating the end date:



function getPaymentBreakdownByMonthlyPayment(total, startDate, monthlyPayment) 


Now, there are no optional parameters any more, and it should be pretty clear which function is called how and for which purpose. Note the different function names don't mean you have to repeat any logic - internally, if these 3 functions share some common logic, it should be refactored to a "private" function.




is there a common pattern for handling scenarios like this




I don't think there is a "pattern" (in the sense of the GoF design patterns) which describes good API design. Using self-describing names, functions with fewer parameters, functions with orthogonal (=independent) parameters, are just basic principles of creating readable, maintainable and evolvable code. Not every good idea in programming is necessarily a "design pattern".






share|improve this answer


































    6

















    Additionally I feel it sets a bad precedent and adds responsibilities to the API that it should not concern itself with (i.e. violating SRP). Suppose additional consumers want the function to support more use cases, such as calculating total from the numMonths and monthlyPayment parameters. This function will become more and more complicated over time.




    You're exactly correct.




    My preference is to keep the function as it was and instead require the caller to calculate endDate themselves. However, I may be wrong and was wondering if the changes they made were an acceptable way to design an API function.




    This isn't ideal either, because the caller code will be polluted with unrelated boiler plate.




    Alternatively, is there a common pattern for handling scenarios like this?




    Introduce a new type, like DateInterval. Add whatever constructors make sense (start date + end date, start date + num months, whatever.). Adopt this as the common-currency types for expressing intervals of dates/times throughout your system.






    share|improve this answer

























    • Are you aware that in a weakly typed language like JavaScript a constructor DateTime(startDate,endDate) cannot be distinguished from a constructor DateTime(startDate,numOfMonths)?

      – Doc Brown
      9 hours ago







    • 2





      @DocBrown Yep. In such cases (Ruby, Python, JS), it's customary to just use static/class methods. But that's an implementation detail, that I don't think is particularly relevant to my answer's point ("use a type").

      – Alexander
      8 hours ago






    • 1





      Using a type is not wrong, but it actually does not really solve the OPs problem. In the current case it does only shift the problem from the existing function to the constructor of the type (or a factory method). In JavaScript, you need different function names to distinguish between semantically different functions with similar number of arguments, that would be necessary for the factory methods for the new type as well. So no, this is not just an implementation detail - introducing a type is here just a red herring (but my congratulations, at least 5 upvoters took the bait).

      – Doc Brown
      1 hour ago



















    0
















    Sometimes fluent-expressions help on this:



    let payment1 = forTotalAmount(1234)
    .breakIntoPayments()
    .byPeriod(months(2));

    let payment2 = forTotalAmount(1234)
    .breakIntoPayments()
    .byDateRange(saleStart, saleEnd);

    let monthsDue = forTotalAmount(1234)
    .calculatePeriod()
    .withPaymentsOf(12.34)
    .monthly();


    Given enough time to design, you can come up with a solid API that acts similar to a domain-specific-language.



    The other big advantage is that IDEs with autocomplete make almost irrevelant to read the API documentation, as is intuitive due its self-discoverable capabilities.






    share|improve this answer





























      Your Answer








      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "131"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );














      draft saved

      draft discarded
















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f398828%2fis-there-a-pattern-for-handling-conflicting-function-parameters%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      9
















      Seeing the implementation, it appears to me what you really require here is 3 different functions instead of one:



      The original one:



      function getPaymentBreakdown(total, startDate, endDate) 


      The one providing the number of months instead of the end date:



      function getPaymentBreakdownByNoOfMonths(total, startDate, noOfMonths) 


      and the one providing the monthly payment and calculating the end date:



      function getPaymentBreakdownByMonthlyPayment(total, startDate, monthlyPayment) 


      Now, there are no optional parameters any more, and it should be pretty clear which function is called how and for which purpose. Note the different function names don't mean you have to repeat any logic - internally, if these 3 functions share some common logic, it should be refactored to a "private" function.




      is there a common pattern for handling scenarios like this




      I don't think there is a "pattern" (in the sense of the GoF design patterns) which describes good API design. Using self-describing names, functions with fewer parameters, functions with orthogonal (=independent) parameters, are just basic principles of creating readable, maintainable and evolvable code. Not every good idea in programming is necessarily a "design pattern".






      share|improve this answer































        9
















        Seeing the implementation, it appears to me what you really require here is 3 different functions instead of one:



        The original one:



        function getPaymentBreakdown(total, startDate, endDate) 


        The one providing the number of months instead of the end date:



        function getPaymentBreakdownByNoOfMonths(total, startDate, noOfMonths) 


        and the one providing the monthly payment and calculating the end date:



        function getPaymentBreakdownByMonthlyPayment(total, startDate, monthlyPayment) 


        Now, there are no optional parameters any more, and it should be pretty clear which function is called how and for which purpose. Note the different function names don't mean you have to repeat any logic - internally, if these 3 functions share some common logic, it should be refactored to a "private" function.




        is there a common pattern for handling scenarios like this




        I don't think there is a "pattern" (in the sense of the GoF design patterns) which describes good API design. Using self-describing names, functions with fewer parameters, functions with orthogonal (=independent) parameters, are just basic principles of creating readable, maintainable and evolvable code. Not every good idea in programming is necessarily a "design pattern".






        share|improve this answer





























          9














          9










          9









          Seeing the implementation, it appears to me what you really require here is 3 different functions instead of one:



          The original one:



          function getPaymentBreakdown(total, startDate, endDate) 


          The one providing the number of months instead of the end date:



          function getPaymentBreakdownByNoOfMonths(total, startDate, noOfMonths) 


          and the one providing the monthly payment and calculating the end date:



          function getPaymentBreakdownByMonthlyPayment(total, startDate, monthlyPayment) 


          Now, there are no optional parameters any more, and it should be pretty clear which function is called how and for which purpose. Note the different function names don't mean you have to repeat any logic - internally, if these 3 functions share some common logic, it should be refactored to a "private" function.




          is there a common pattern for handling scenarios like this




          I don't think there is a "pattern" (in the sense of the GoF design patterns) which describes good API design. Using self-describing names, functions with fewer parameters, functions with orthogonal (=independent) parameters, are just basic principles of creating readable, maintainable and evolvable code. Not every good idea in programming is necessarily a "design pattern".






          share|improve this answer















          Seeing the implementation, it appears to me what you really require here is 3 different functions instead of one:



          The original one:



          function getPaymentBreakdown(total, startDate, endDate) 


          The one providing the number of months instead of the end date:



          function getPaymentBreakdownByNoOfMonths(total, startDate, noOfMonths) 


          and the one providing the monthly payment and calculating the end date:



          function getPaymentBreakdownByMonthlyPayment(total, startDate, monthlyPayment) 


          Now, there are no optional parameters any more, and it should be pretty clear which function is called how and for which purpose. Note the different function names don't mean you have to repeat any logic - internally, if these 3 functions share some common logic, it should be refactored to a "private" function.




          is there a common pattern for handling scenarios like this




          I don't think there is a "pattern" (in the sense of the GoF design patterns) which describes good API design. Using self-describing names, functions with fewer parameters, functions with orthogonal (=independent) parameters, are just basic principles of creating readable, maintainable and evolvable code. Not every good idea in programming is necessarily a "design pattern".







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 10 mins ago

























          answered 9 hours ago









          Doc BrownDoc Brown

          143k25 gold badges267 silver badges423 bronze badges




          143k25 gold badges267 silver badges423 bronze badges


























              6

















              Additionally I feel it sets a bad precedent and adds responsibilities to the API that it should not concern itself with (i.e. violating SRP). Suppose additional consumers want the function to support more use cases, such as calculating total from the numMonths and monthlyPayment parameters. This function will become more and more complicated over time.




              You're exactly correct.




              My preference is to keep the function as it was and instead require the caller to calculate endDate themselves. However, I may be wrong and was wondering if the changes they made were an acceptable way to design an API function.




              This isn't ideal either, because the caller code will be polluted with unrelated boiler plate.




              Alternatively, is there a common pattern for handling scenarios like this?




              Introduce a new type, like DateInterval. Add whatever constructors make sense (start date + end date, start date + num months, whatever.). Adopt this as the common-currency types for expressing intervals of dates/times throughout your system.






              share|improve this answer

























              • Are you aware that in a weakly typed language like JavaScript a constructor DateTime(startDate,endDate) cannot be distinguished from a constructor DateTime(startDate,numOfMonths)?

                – Doc Brown
                9 hours ago







              • 2





                @DocBrown Yep. In such cases (Ruby, Python, JS), it's customary to just use static/class methods. But that's an implementation detail, that I don't think is particularly relevant to my answer's point ("use a type").

                – Alexander
                8 hours ago






              • 1





                Using a type is not wrong, but it actually does not really solve the OPs problem. In the current case it does only shift the problem from the existing function to the constructor of the type (or a factory method). In JavaScript, you need different function names to distinguish between semantically different functions with similar number of arguments, that would be necessary for the factory methods for the new type as well. So no, this is not just an implementation detail - introducing a type is here just a red herring (but my congratulations, at least 5 upvoters took the bait).

                – Doc Brown
                1 hour ago
















              6

















              Additionally I feel it sets a bad precedent and adds responsibilities to the API that it should not concern itself with (i.e. violating SRP). Suppose additional consumers want the function to support more use cases, such as calculating total from the numMonths and monthlyPayment parameters. This function will become more and more complicated over time.




              You're exactly correct.




              My preference is to keep the function as it was and instead require the caller to calculate endDate themselves. However, I may be wrong and was wondering if the changes they made were an acceptable way to design an API function.




              This isn't ideal either, because the caller code will be polluted with unrelated boiler plate.




              Alternatively, is there a common pattern for handling scenarios like this?




              Introduce a new type, like DateInterval. Add whatever constructors make sense (start date + end date, start date + num months, whatever.). Adopt this as the common-currency types for expressing intervals of dates/times throughout your system.






              share|improve this answer

























              • Are you aware that in a weakly typed language like JavaScript a constructor DateTime(startDate,endDate) cannot be distinguished from a constructor DateTime(startDate,numOfMonths)?

                – Doc Brown
                9 hours ago







              • 2





                @DocBrown Yep. In such cases (Ruby, Python, JS), it's customary to just use static/class methods. But that's an implementation detail, that I don't think is particularly relevant to my answer's point ("use a type").

                – Alexander
                8 hours ago






              • 1





                Using a type is not wrong, but it actually does not really solve the OPs problem. In the current case it does only shift the problem from the existing function to the constructor of the type (or a factory method). In JavaScript, you need different function names to distinguish between semantically different functions with similar number of arguments, that would be necessary for the factory methods for the new type as well. So no, this is not just an implementation detail - introducing a type is here just a red herring (but my congratulations, at least 5 upvoters took the bait).

                – Doc Brown
                1 hour ago














              6














              6










              6










              Additionally I feel it sets a bad precedent and adds responsibilities to the API that it should not concern itself with (i.e. violating SRP). Suppose additional consumers want the function to support more use cases, such as calculating total from the numMonths and monthlyPayment parameters. This function will become more and more complicated over time.




              You're exactly correct.




              My preference is to keep the function as it was and instead require the caller to calculate endDate themselves. However, I may be wrong and was wondering if the changes they made were an acceptable way to design an API function.




              This isn't ideal either, because the caller code will be polluted with unrelated boiler plate.




              Alternatively, is there a common pattern for handling scenarios like this?




              Introduce a new type, like DateInterval. Add whatever constructors make sense (start date + end date, start date + num months, whatever.). Adopt this as the common-currency types for expressing intervals of dates/times throughout your system.






              share|improve this answer














              Additionally I feel it sets a bad precedent and adds responsibilities to the API that it should not concern itself with (i.e. violating SRP). Suppose additional consumers want the function to support more use cases, such as calculating total from the numMonths and monthlyPayment parameters. This function will become more and more complicated over time.




              You're exactly correct.




              My preference is to keep the function as it was and instead require the caller to calculate endDate themselves. However, I may be wrong and was wondering if the changes they made were an acceptable way to design an API function.




              This isn't ideal either, because the caller code will be polluted with unrelated boiler plate.




              Alternatively, is there a common pattern for handling scenarios like this?




              Introduce a new type, like DateInterval. Add whatever constructors make sense (start date + end date, start date + num months, whatever.). Adopt this as the common-currency types for expressing intervals of dates/times throughout your system.







              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered 9 hours ago









              AlexanderAlexander

              1,3378 silver badges16 bronze badges




              1,3378 silver badges16 bronze badges















              • Are you aware that in a weakly typed language like JavaScript a constructor DateTime(startDate,endDate) cannot be distinguished from a constructor DateTime(startDate,numOfMonths)?

                – Doc Brown
                9 hours ago







              • 2





                @DocBrown Yep. In such cases (Ruby, Python, JS), it's customary to just use static/class methods. But that's an implementation detail, that I don't think is particularly relevant to my answer's point ("use a type").

                – Alexander
                8 hours ago






              • 1





                Using a type is not wrong, but it actually does not really solve the OPs problem. In the current case it does only shift the problem from the existing function to the constructor of the type (or a factory method). In JavaScript, you need different function names to distinguish between semantically different functions with similar number of arguments, that would be necessary for the factory methods for the new type as well. So no, this is not just an implementation detail - introducing a type is here just a red herring (but my congratulations, at least 5 upvoters took the bait).

                – Doc Brown
                1 hour ago


















              • Are you aware that in a weakly typed language like JavaScript a constructor DateTime(startDate,endDate) cannot be distinguished from a constructor DateTime(startDate,numOfMonths)?

                – Doc Brown
                9 hours ago







              • 2





                @DocBrown Yep. In such cases (Ruby, Python, JS), it's customary to just use static/class methods. But that's an implementation detail, that I don't think is particularly relevant to my answer's point ("use a type").

                – Alexander
                8 hours ago






              • 1





                Using a type is not wrong, but it actually does not really solve the OPs problem. In the current case it does only shift the problem from the existing function to the constructor of the type (or a factory method). In JavaScript, you need different function names to distinguish between semantically different functions with similar number of arguments, that would be necessary for the factory methods for the new type as well. So no, this is not just an implementation detail - introducing a type is here just a red herring (but my congratulations, at least 5 upvoters took the bait).

                – Doc Brown
                1 hour ago

















              Are you aware that in a weakly typed language like JavaScript a constructor DateTime(startDate,endDate) cannot be distinguished from a constructor DateTime(startDate,numOfMonths)?

              – Doc Brown
              9 hours ago






              Are you aware that in a weakly typed language like JavaScript a constructor DateTime(startDate,endDate) cannot be distinguished from a constructor DateTime(startDate,numOfMonths)?

              – Doc Brown
              9 hours ago





              2




              2





              @DocBrown Yep. In such cases (Ruby, Python, JS), it's customary to just use static/class methods. But that's an implementation detail, that I don't think is particularly relevant to my answer's point ("use a type").

              – Alexander
              8 hours ago





              @DocBrown Yep. In such cases (Ruby, Python, JS), it's customary to just use static/class methods. But that's an implementation detail, that I don't think is particularly relevant to my answer's point ("use a type").

              – Alexander
              8 hours ago




              1




              1





              Using a type is not wrong, but it actually does not really solve the OPs problem. In the current case it does only shift the problem from the existing function to the constructor of the type (or a factory method). In JavaScript, you need different function names to distinguish between semantically different functions with similar number of arguments, that would be necessary for the factory methods for the new type as well. So no, this is not just an implementation detail - introducing a type is here just a red herring (but my congratulations, at least 5 upvoters took the bait).

              – Doc Brown
              1 hour ago






              Using a type is not wrong, but it actually does not really solve the OPs problem. In the current case it does only shift the problem from the existing function to the constructor of the type (or a factory method). In JavaScript, you need different function names to distinguish between semantically different functions with similar number of arguments, that would be necessary for the factory methods for the new type as well. So no, this is not just an implementation detail - introducing a type is here just a red herring (but my congratulations, at least 5 upvoters took the bait).

              – Doc Brown
              1 hour ago












              0
















              Sometimes fluent-expressions help on this:



              let payment1 = forTotalAmount(1234)
              .breakIntoPayments()
              .byPeriod(months(2));

              let payment2 = forTotalAmount(1234)
              .breakIntoPayments()
              .byDateRange(saleStart, saleEnd);

              let monthsDue = forTotalAmount(1234)
              .calculatePeriod()
              .withPaymentsOf(12.34)
              .monthly();


              Given enough time to design, you can come up with a solid API that acts similar to a domain-specific-language.



              The other big advantage is that IDEs with autocomplete make almost irrevelant to read the API documentation, as is intuitive due its self-discoverable capabilities.






              share|improve this answer































                0
















                Sometimes fluent-expressions help on this:



                let payment1 = forTotalAmount(1234)
                .breakIntoPayments()
                .byPeriod(months(2));

                let payment2 = forTotalAmount(1234)
                .breakIntoPayments()
                .byDateRange(saleStart, saleEnd);

                let monthsDue = forTotalAmount(1234)
                .calculatePeriod()
                .withPaymentsOf(12.34)
                .monthly();


                Given enough time to design, you can come up with a solid API that acts similar to a domain-specific-language.



                The other big advantage is that IDEs with autocomplete make almost irrevelant to read the API documentation, as is intuitive due its self-discoverable capabilities.






                share|improve this answer





























                  0














                  0










                  0









                  Sometimes fluent-expressions help on this:



                  let payment1 = forTotalAmount(1234)
                  .breakIntoPayments()
                  .byPeriod(months(2));

                  let payment2 = forTotalAmount(1234)
                  .breakIntoPayments()
                  .byDateRange(saleStart, saleEnd);

                  let monthsDue = forTotalAmount(1234)
                  .calculatePeriod()
                  .withPaymentsOf(12.34)
                  .monthly();


                  Given enough time to design, you can come up with a solid API that acts similar to a domain-specific-language.



                  The other big advantage is that IDEs with autocomplete make almost irrevelant to read the API documentation, as is intuitive due its self-discoverable capabilities.






                  share|improve this answer















                  Sometimes fluent-expressions help on this:



                  let payment1 = forTotalAmount(1234)
                  .breakIntoPayments()
                  .byPeriod(months(2));

                  let payment2 = forTotalAmount(1234)
                  .breakIntoPayments()
                  .byDateRange(saleStart, saleEnd);

                  let monthsDue = forTotalAmount(1234)
                  .calculatePeriod()
                  .withPaymentsOf(12.34)
                  .monthly();


                  Given enough time to design, you can come up with a solid API that acts similar to a domain-specific-language.



                  The other big advantage is that IDEs with autocomplete make almost irrevelant to read the API documentation, as is intuitive due its self-discoverable capabilities.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited 2 hours ago

























                  answered 2 hours ago









                  DanielCuadraDanielCuadra

                  1914 bronze badges




                  1914 bronze badges































                      draft saved

                      draft discarded















































                      Thanks for contributing an answer to Software Engineering Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f398828%2fis-there-a-pattern-for-handling-conflicting-function-parameters%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Canceling a color specificationRandomly assigning color to Graphics3D objects?Default color for Filling in Mathematica 9Coloring specific elements of sets with a prime modified order in an array plotHow to pick a color differing significantly from the colors already in a given color list?Detection of the text colorColor numbers based on their valueCan color schemes for use with ColorData include opacity specification?My dynamic color schemes

                      Invision Community Contents History See also References External links Navigation menuProprietaryinvisioncommunity.comIPS Community ForumsIPS Community Forumsthis blog entry"License Changes, IP.Board 3.4, and the Future""Interview -- Matt Mecham of Ibforums""CEO Invision Power Board, Matt Mecham Is a Liar, Thief!"IPB License Explanation 1.3, 1.3.1, 2.0, and 2.1ArchivedSecurity Fixes, Updates And Enhancements For IPB 1.3.1Archived"New Demo Accounts - Invision Power Services"the original"New Default Skin"the original"Invision Power Board 3.0.0 and Applications Released"the original"Archived copy"the original"Perpetual licenses being done away with""Release Notes - Invision Power Services""Introducing: IPS Community Suite 4!"Invision Community Release Notes

                      199年 目錄 大件事 到箇年出世嗰人 到箇年死嗰人 節慶、風俗習慣 導覽選單