3 ms·
The “YAGNI” principle is something I’ve had to learn the hard way - and continue to learn it, just earlier this week, in fact. YAGNI and DRY are sometimes in vi
by lstamour 3y ago
The “YAGNI” principle is something I’ve had to learn the hard way - and continue to learn it, just earlier this week, in fact. YAGNI and DRY are sometimes in vicious opposition. A pro tip I picked up from Gary Bernhardt’s Destroy All Software screencasts is to leave some DRYing (or other refactoring for readability/maintenance purposes) until after you write tests and are in a red-green-refactor cycle. You can always DRY your code later, especially now that IDEs make it so easy to extract methods for you with automatic population of required variables/parameters.
- vidarh 3y agoPersonally I think DRY only makes sense as long as either the code is shorter (here it's longer...), or you encapsulate logic, especially when that logic will be called from multiple places in the code base. Here it won't... I think some of these methods might be ok in a public helper class ("go here if you want to know the correct way of finding these kinds of objects so we have a single extension point"), but not as private methods... The irony here is they try to let you read the main codepath top down, but because they unnecessarily obscure details they force you to jump back and forth between a ton of methods instead, completely ruining any benefit. I love code that lets you actually read it sequentially, but then it needs to actually let you do that.
- mike_hock 3y agoHow 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.