6 ms·
Religiously splitting functions with boolean arguments doesn't always result in more maintainable code. Instead of trigonometry functions, how would you refact
by treve 5y ago
Religiously splitting functions with boolean arguments doesn't always result in more maintainable code.
Instead of trigonometry functions, how would you refactor JS's fetch() with many of its behaviour-altering flags?
- bjourne 5y agoGood rules of thumbs are given in the "Deciding which to use" section of the article. For the fetch() function, I'd keep most parameters as is since they don't change the essense of the function. But "cache" and "redirect" do (following redirects can cause N http requests rather than just one and using the cache perhaps 0) so I'd refactor them as new functions. Imagine adding retry functionality to the fetch() function using parameters. I think you can see how this leads to feature creep.
- peoplefromibiza 5y ago> how would you refactor JS's fetch() as @flavius29663 said (https://news.ycombinator.com/item?id=28593669 https://news.ycombinator.com/item?id=28593669) you can use the builder pattern FetchBuilder() .withUrl(ur) .withMode("cors") .withCache(true) .withHeader('Content-Type', 'application/json') .accept('*/*') .post() .then(response => response.json()) .then(data => console.log(data));
- kevincox 5y agoI see the builder pattern as a way to manage lack of keyword arguments. I see very little difference between your example and the actual fetch API that takes an object as JS's version of keyword arguments. Languages with good support for named/keyword arguments have more features such as required arguments and preventing duplicate arguments. With builder patterns your only real option is to make the builder constructor have required arguments (or throw a runtime error upon finalizing the builder).
- peoplefromibiza 5y ago> . I see very little difference between your example and the actual fetch API that takes an object as JS's version true the only difference is in the tooling code completion for methods names works much better than autocompletion for objects' fields. And you can't mistype a method name, it would not run and give you back a - hopefully - meaningful error, while the same is not true for objects' fields.
- kevincox 5y ago> code completion for methods names works much better than autocompletion for objects' fields. That is true for vanilla JS, unknown parameters will be ignored and unset will be set to undefined. However for languages that support keyword arguments (or even TypeScript[1]) the tooling should be even better than for the keyword argument case. [1] https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABMOcAUBvAhgGkQIwF8BKRDAKESsQgQGc4AbAUwDpG4BzNXA4gbnKFy5FOmwAuRAEY8EKQCYS-IA https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABMO...
- zamadatix 5y agoI'm not following how moving the options out of the function parameters and into the call chain makes the actual function more maintainable. It's still doing the exact same thing with the exact same options it's just pulling them from elsewhere. If anything you now have more functions to maintain on top of the function that does many different things based on the calling info. // The original "misses the point" trig(mode="cos", type="hyperbolic") // The style fetch() uses today trig({mode: "cos", type: "hyperbolic"}) // The builder refactor trigBuilder().withMode("Cos").withType("hyperbolic").calculate()
- peoplefromibiza 5y agoPersonally I don't like using with prefix in builders, I was simply presenting an example from another comment. the difference, IMO, is - in Javascript - that this // The style fetch() uses today trig({mode: "cos", typ: "hyperbolic"}) ^^^ would fail silently while // The builder refactor trig().mode("cos").typ("hyperbolic")(val) would trigger a compilation error but, IMO, passing objects is good enough most of the times, and I consider it a much better solution over passing boolean flags