In JavaScript (ES6), I can have optional function parameter with default value. So to add a new behavior to the existing code base, I could either introduce new method(s) or extend the existing method with an optional parameter.
Consider the following example:
Existing method:
doSomething(param) {
// code to do something trivial
}
Desired new behavior: the ability to do something special after doing something trivial
Option 1: extend the existing method
doSomething(param, isSpecial = false) {
// code to do something trivial
if (isSpecial) {
// code to do some more thing special
}
}
Usage:
doSomething(param); // do something trivial
doSomething(param, true); // do something special
Option 2: add a new method
doSomethingSpecial(param) {
doSomething(param); // just call the existing method to do something trivial
// code to do some more thing special
Usage:
doSomething(param); // do something trivial
doSomethingSpecial(param); // do something special
Option 3: extend the existing method and add two new methods
doSomething(param, isSpecial) {
// code to do something trivial
if (isSpecial) {
// code to do some more thing special
}
}
doSomethingTrivial(param) {
doSomething(param, false);
}
doSomethingSpecial(param) {
doSomething(param, true);
}
Usage:
doSomethingTrivial(param); // do something trivial
doSomethingSpecial(param); // do something special
Currently I'm mostly using the first option, because it's less code to write. But thinking of the open closed principle, it doesn't sound right for me.
So which option should I choose? (in general, not special in JavaScript)
-
@Downvoter: please kindly explain :-|nhle– nhle2019年06月20日 09:22:11 +00:00Commented Jun 20, 2019 at 9:22
-
2How are you evaluating the merits of each choice to determine which one to use? What are your criteria? If there are two (or more) ways of approaching a task, how should one choose between them?Robert Harvey– Robert Harvey2019年06月20日 14:39:19 +00:00Commented Jun 20, 2019 at 14:39
-
Very nice question . Everyone was there once .Cap Barracudas– Cap Barracudas2020年10月14日 12:19:36 +00:00Commented Oct 14, 2020 at 12:19
3 Answers 3
I'd choose option 2 for the following reasons:
- A separately named method reveals the intention better than a boolean parameter that you need to look up to understand what it does.
- Since you're not modifying any existing behaviour but simply doing something extra at the end, there isn't a good reason to change the original method to take an additional parameter.
There is no right answer to this. In a general sense, you actually have three options:
- Add an optional parameter,
- Add a second function with a different name,
- Add a second function with the same name, ie overload the function.
I don't think JavaScript supports the third option, but I'm out of date with that language so may have that wrong. But many languages do, so it remains a generalised option.
I personally dislike optional parameters and actively avoid using them. I favour multiple functions with names that describe the reasons for the different parameters. And I'll use overloading when it makes sense to me to do so. But that "makes sense" is highly subjective, as are my other decisions. Other people will have different ideas on what they prefer.
The best advice for such things I've found is, be consistent. It's far more important that you define a set of rules for yourself for when to use each option and stick to them, than it is to worry about which option might be the better one.
-
I don't think the third option is relevant here. OP's example uses the boolean as a switch for the additional behavior, the value isn't used in any other way. So if OP adds a second function, it wouldn't need that parameter (since the second function always does the special thing), at which point you run into a conflict having two functions with the exact same signature, which means you need to give them different names (which is the second option)Flater– Flater2019年06月20日 08:42:55 +00:00Commented Jun 20, 2019 at 8:42
If you follow Bob Martin's ''clean code'', then you might prefer option 2 (as in @David Arno and @casablanca.) Indeed,
- One function argument is better than two
- Simple well-named functions are better than complicated, vaguely named
- Each function should do one and only one thing (ie, single responsibility principle at the basic level)
- Open-closed principle: open for extension, closed for modification. (Usually this is defined at a class level, but can also apply at a function level.)
It's also a good practice to avoid booleans, as they are not very meaningful for the business domain.
Some cases, however, may justify other options. For instance, if you have more than two types of "special", you could define a Specials enum
and a dispatcher function:
doSomething(param, special){
//or a switch statement
if (special == Specials.trivial) {
doSomethingTrivial(param); }
if (special == Specials.bogStandard) {
doSomethingBogStandard(param); }
if (special == Specials.special) {
doSomethingTrivial(param); }
}
// code to do trivial
doSomethingTrivial(param) { ...; }
// you get the idea
doSomethingSpecial(param) {...;}
doSomethingBogStandard(param) { ...; }
Compared to, say, hardcoding doSomethingTrivial()
in a module, this gives you a flexibility to configure the module by passing the specialEnum
. (In some languages you may pass the function instead.) If a particular module is always trivial, then you could hardcode this module and leave flexibility for other modules.
As usual "it depends", and there're trade-offs to consider. And of course, it's possible to refactor later.
Explore related questions
See similar questions with these tags.