3 ms·
How about the JUCS principle - Just Use Common Sense. What do you want to see when you come back in half a year to make a change? Write that. What does YAGNI e
by mike_hock 3y ago
How about the JUCS principle - Just Use Common Sense. What do you want to see when you come back in half a year to make a change? Write that.
What does YAGNI even mean if it can stand in opposition of DRY? If it just means "you don't need to do that," and "that" can mean whatever you want, then it's not a useful guiding principle.
Example of a YAGNI violation: You're writing a piece of code whose purpose is to download some kind of asset for whatever thingamajigga you're working on. It just needs to HTTP GET the resource from your official server. To future-proof it, you also add support for using any of the HTTP verbs as well as adding custom request headers. Not only have you written useless code that will likely never be needed, you've leaked implementation details (all these HTTP details don't make sense if a future version wants to use a different protocol).
Example of what is not a YAGNI violation: Your asset downloader also needs to parse some sidechannel information that the server returns as custom response headers. You just assume that header names are capitalized the way your server sends them and don't bother with case-insensitivity. That isn't following "YAGNI," that's leaving a ticking time bomb behind.
YAGNI is about functionality, DRY is about structure.
- lstamour 3y ago> What does YAGNI even mean if it can stand in opposition of DRY? If it just means "you don't need to do that," and "that" can mean whatever you want, then it's not a useful guiding principle. > YAGNI is about functionality, DRY is about structure. I absolutely see where you’re coming from and I agree, the reason DRY caught on and YAGNI hasn’t is indeed the vagueness of YAGNI. But I would equally argue that the simplicity of DRY is what gets you in trouble if you over-optimize for DRY regardless of context. DRY can be about functionality: if you’ve already implemented a feature, even if it’s a library maintained by another team, as long as the tests encourage your use case, you should re-use existing functionality over creating yet another abandoned half-baked attempt at something. YAGNI, by opposition, might suggest that the effort spent learning the other team’s library and maintaining a connection to what might be brittle code is itself overhead. A similar debate can be found in using an npm library. DRY would argue if you already use the library, keep using it. YAGNI would argue if the library is only used in one place, rip it out for simplicity and replace it, especially if the code is old. Taken to extremes, DRY is how we end up with a left-pad module on npm while YAGNI is using padStart built-in to modern JS. Likewise taken to extremes, YAGNI may result in missing functionality and unmaintainable spaghetti code, while DRY is one possible approach to taming complexity in codebases. Both are essential principles, neither actually more important than the other. I agree with JUCS, but it’s even less defined than YAGNI ;-)
- mike_hock 3y agoThis over-generalization of vague concepts isn't helpful. An example of DRY would be: You're using libraries "foo" and "baz," and whenever foo::get_bar() returns 1, 2, or 3, you need to call (for your use-case) baz::qux(9), baz::qux(31), or baz::qux(-5), respectively. So you create one function that either handles both calls completely, or at least maps the return value from get_bar to the argument required by qux. The violation of DRY would have switch statements littered throughout the code that all do the same mapping manually. A build-or-"buy" decision isn't about being DRY or not.
- vidarh 3y agoIn this case, the issue is that they've tried to "DRY" up things that don't actually reduce any repetition. Yet. Maybe it will in the future, then DRY it up then. Secondly, DRY is meaningless if applied at units so small that you replace one invocation of a method with another invocation of a method when the arguments to the first one are obvious. E.g. consider this from the example: def find_admin_role Roles.find_by(name: 'admin') end Assuming your application consistently uses `name`, and is consistent about class names, `find_admin_role` is not saving you complexity over Roles.find_by(name: 'admin'). People familiar with Ruby ORMs and tasked with finding an admin role will go looking for finders in the Role class. They're not likely to find your method, and so are likely to write their own. The former introduces complexity that is only warranted to me if 1) the method of finding the admin role grows more complex so it's non-obvious, 2) the method you DRY it up into is actually being used at least twice, 3) it's placed in the most appropriate class. And it's that second where YAGNI comes in. By all means, DRY up logic. But don't do it before it actually stops you repeating yourself in a way that is actually significant. To #3, that "find_admin_role" method really should be `Roles.find_admin` if it's allowed to exist at all - there it's at least somewhat defensible even if it is only a single line method, because others are likely to find it there, and even if it seems relatively redundant, at least there it serves to document that this is indeed the canonical name for an admin role.