15 ms·
Why do so many developers get DRY wrong?
- AdriaanvRossum 7y agoLike DRY is wrong? I don't really get the point of this article.
- aphextron 7y ago>Like DRY is wrong? I don't really get the point of this article. More that it's a guideline, not a law. We should always use best judgement to decide when the tradeoff of readability and declarative code is worth a small amount of repetition, rather than religiously refactoring something for the sake of it.
- pkaye 7y agoSometimes "A little copying is better than a little dependency."
- ubu7737 7y agoSometimes a little copying is better than 3 levels of complexity to create 3 different types of object. It's fine to hone your craft as you work by making use of abstractions that make sense at a larger scale of using that abstraction. I forgive you. But at 3+ levels in the class hierarchy to accomplish that unification of 3 different types, I have to object strenuously that you are straining purpose.
- Quekid5 7y agoI absolutely subscribe to that, but then again, I don't have a Rule of Three or similar... It's a bit difficult to get across in text, but the minimum number of repetitions of a piece of code to make it "worth" putting it in a function is... 1. (According to me, and Tony van Eerd of Postmodern C++ fame. I had come to this conclusion on my own, but his talk really articulated it well.) It's all about limiting the scope of side-effects, accidental reuse or variables, etc. etc. such that a human can do chunking to understand the whole. I generally find that this is not an easy thing to capture in "metrics" or "rules". Guidelines with reasonable rationales, etc. etc. and when-not-to's, definitely, but that's a really hard thing to do and it doesn't get many clicks. EDIT: ... and just to get back to DRY. The acronym is far too absolutist, but Try-Not-To-Repeat-Yourself-Too-Much-Unless-You-Have-Good-Reason-To isn't quite as catchy, is it?
- wrmsr 7y agoI've seen so many times people going all in on DRY not understanding that just as dangerous as duplication is _coupling_ - the inevitable result being some ungodly $COMPANY_NAME_common lib with a thousand dependencies, and usually only depped in a codebase for a config parser and a string helper. See also node_modules and left-pad.io.
- brentjanderson 7y agoDRY was introduced in the Pragmatic Programmer, and Dave Thomas pointed out in a recent Changelog episode that DRY doesn't mean "Don't repeat code", it means "Don't repeat knowledge." One concrete example: If your software has to create really complex objects, would you rather describe _how_ to create those objects in 10 places or one place? That's a scenario where you don't want to repeat yourself. Dan Abramov [wrote about](https://overreacted.io/goodbye-clean-code/ https://overreacted.io/goodbye-clean-code/) this (linked in the OP), but in his example he's removing repetitive code. He's not removing multiple copies of the _knowledge_ about what the program is supposed to do. It's a subtle difference that seems more difficult to describe than I'd like, but it's an important one.
- crispinb 7y agoNo, they're not saying it's wrong, but rather it's commonly misunderstood. From the motto alone you might think the point is to abjure all code duplication. But Hunt & Thomas' intent was instead to warn against duplicating sources of truth/knowledge - that is, all knowledge embedded in your code needs to have a canonical source, and all other references should derive from that source or you risk divergence (or in the best case must always remember to make necessary changes in multiple places). So for example, documentation (truths about the code) should derive from the code (eg by doc generation). Otherwise the docs & code will drift apart. Or if you're passing domain information across the wire between client & server, you should derive the data structures at both ends from a common source.
- iSnow 7y ago>all knowledge embedded in your code needs to have a canonical source I don't get it. Code /IS/ knowledge and whenever I copy-paste code around, I duplicate not only code but also knowledge.
- crispinb 7y agoWell (and I'm elucidating, not necessarily defending) they mean knowledge somewhat specific to the project, not in an absolute philosophical sense. So you have an API that belongs to this project. When you change it, do so in one place, and then run your doc generator rather than change it in both function/method signatures and docs. Or you have domain knowledge embedded in classes, and a wire protocol between peers or client & servers using different languages. Derive the data structures in the two different languages from common source (either one of the languages, or both from metadata). I think the distinction between this kind of project-specific 'knowledge' and more abstract 'everything is knowledge' issues is clear enough in practice. But it is just a rule of thumb rather than a deep philosophical principle, and like all such will break down in individual cases. whenever I copy-paste code around But that's just one source of code duplication. Another might be (for example) duplicated code deriving from code generation. DRY might advocate this (as there's a clear canonical source of knowledge), whereas a generic rule against all 'duplication' wouldn't.
- 7y ago
- mrkeen 7y agoThe comment that it's about knowledge, not code resonated with me. Like, if you saw Http.getClient(...).doGetRequest(...) a few times, it wouldn't be worth pulling them out into a myGetRequest(...) method. Your teammates already understand the existing, repeated statements, but they haven't seen myGetRequest(...) before, so you wouldn't be making the code any more readable to them. But if you had Http.getClient("auth.myservice.com:8443").doGetRequest(...) in a few places, then I would pull out the host and port (or maybe the whole line), since it contains knowledge of where/how to authenticate. Coming from the other direction: if I were reading the code, I can imagine myself looking for the one place where the auth happens, but I can't imagine myself needing to know the one place where Get requests happen (even if the 'Get' code is repeated much more than the 'auth' code)
- masswerk 7y agoI think, you are making a good point for what may be called mutable knowledge. I.e., when writing a shell script to iterate over a few files, nothing of this is of utter importance, since the script is meant to be run only once, thus we may consider any knowledge immutable. Also, maintenance and readability aren't much of a consideration here. In the case of a "real" application, when connecting to an endpoint, as in your example, we may consider address and credentials subject to change, so this is mutable knowledge, which ought to be represented once. However, the method of connecting is hard coded in several places, so it's pretty much immutable. If we expect the method of connecting (http) subject to change, we should consider to put this in a single spot, as well, even, if this may mean that the code may be harder to follow, since we introduced another layer of abstraction. And so on…
- keeganjw 7y agoI feel like this article ended before it should have. I'm still not exactly sure what the author means by Don't Repeat Knowledge. Should we not be refactoring or... just don't go overboard?
- crispinb 7y agoI'm still not exactly sure what the author means by Don't Repeat Knowledge I think they're assuming that everyone has read The Pragmatic Programmer. To quote the original DRY principle from there: Every piece of knowledge must have a single, unambiguous, authoritative representation within the system Note that this has only an accidental relationship with code duplication, and in some cases could increase the latter.
- rileymat2 7y agoMore often than not duplicate code is duplicate knowledge. It often is an implicit business rule that links several statements together or a system requirement like freeing db connections and locks in the right order after use.
- loopz 7y agoDRY skips the part about dependency management: Will tying these parts together make sense for future readability, changability, or not? Often it is wise to be clear what and how to separate and encapsulate. If there is only one right way, there is no reason for change or changing together, so is not shared knowledge.
- krisroadruck 7y agoHah I'm glad I'm not the only one. I finished reading it and thought that it felt like an intro and they entirely left out the meat of the article. Thought maybe it was just a lack of related knowledge as I just dabble in coding but yeah I figured at some point they would define what it was actually supposed to mean in depth. When that didn't happen I was left wondering what the point of the article was.
- beaker52 7y agoI find DRY fascinating. It's the source of a large portion of the accidental complexity I find in code. "If I just create this abstraction, all this duplicated code goes away" - we've all heard it and many of us have told it, but few of us realise that it's the prequel to the most popular story of all: "all this code is such a mess, there are all these extra layers that don't really make sense and unpicking it is such a pain, I can't believe someone wrote this". The story inbetween is about a young, inexperienced developer who has 3-days to deliver the one-feature-to-rule-them-all, to appease the almighty project manager, necessitating an adventure into the labyrinth carefully crafted by the developer in the first story.
- Frost1x 7y agoA lot of principles like DRY (as described out of correct context in this article) have cult like followings people follow mindlessly leading to unnecessary introduced complexity. I'm always amazed at how eager people are to over-engineer a solution that makes it a mess to deal with moving forward. Developers at large like to appear clever, tend to have (fragile) large egos, and don't seem to want to veer from established dogma--much of which based on little evidence or evidence that doesnt apply to a case they're dealing with.
- dec0dedab0de 7y agoIt's the source of a large portion of the accidental complexity I find in code. "If I just create this abstraction, all this duplicated code goes away" For me it's usually, "Oh crap that thing I changed I had to change here and here too, whoops its good now... Wait no I also had to change it here... and here... now that we're done with that we should be fine... DAMMIT!"
- marcosdumay 7y agoThe problem is that DRY is not the thing that solves this problem. It looks like it is, you'll see plenty of people claiming it is, it may even lead people into solving the problem after they gather some experience. But it's not what solves the problem.
- jfengel 7y agoI hadn't heard of the Rule of Three, but it parallels my own heuristic. The first time, I write the code to do the thing I need. The second time I encounter a similar thing, if I can't find the right abstraction to unify them, I go ahead and repeat myself, writing a second, similar round of code that does what it needs. If I encounter it a third time, then I've got enough data points to make a good guess about what the right abstraction will be. If I've done a good job so far, it shouldn't be too difficult to refactor it. (Strong, static typing helps.) This is, of course, just a heuristic, and it's not all-or-nothing. I'll take my best guess about what the right abstraction is going to be, and I'll try to get it right the first time. The second round also presents opportunities to take two points and extrapolate a line. It all comes down to experience: not just with the system, but with the domain that the system is about, and with the way systems change and grow. No one rule of thumb ever encapsulates all that.
- AnimalMuppet 7y agoI use the same approach to automate processes. The first time, I do it manually. The second time, I still do it manually, but I think "Hey, I did this once before. This is looking like something I maybe ought to automate." The third time I automate it. By then, I understand it well enough to have good odds on being able to do the automation successfully.
- amelius 7y agoHow often did you automate something yet? If it's more than three times, you ought to automate the automation!
- keithnoizu 7y agoskynet.gif
- AnimalMuppet 7y agoYou're kidding (I think), but I missed a piece. Part of the point of doing it the second time is to make sure that I really understand what I'm doing and how I'm doing it. Without that, I can't write the automation on the third time. Well, if the task is "automating things" (for very general values of "things"), I don't understand how I'm doing well enough to automate that.
- saber6 7y agoDRY like anything can be properly used or misused. For example, you can normalize a database so much that any basic query comes with a massive overhead (recursion). There is a middle ground between "religion" (pure DRY) and "chaos" (no DRY).
- goto11 7y agoHow does normalization lead to recursion? Normalization is one point where DRY really is critical, because redundant data in a database can lead to data corruption when it get out of sync. And if the data is corrupt, your whole business is screwed.
- saber6 7y agoI may be mis-communicating what I am trying to say. I once had the (mis)pleasure of dealing with some novice DBAs. There were instances in the data model where things were so recursively linked that one query would fan out to 200+ to actually return the set of meaningful data. As you might of imagined, this caused scaling issues when you started dealing with significant amount of data (hundreds of GB of data in the DB). Eventually we brought in some pros and one of the first things they did was eliminate a number of overly recursive queries and duplicated some (not all) fields of data to speed up performance. We went from 1->200+ fanout in a typical query to 1->25-ish. The performance gains were insane. Of course it violates the "don't repeat yourself" and to abstract linked (repetitive) data in a relational way. But sometimes this best practice can really be counter-productive in edge performance scenarios. But in general yeah, don't be repetitive, abstract your stuff, and keep it clean and easy to change globally if/when needed.
- ubu7737 7y agoDRY is just an admonition for beginners. Nobody who learns higher-level abstractions in a modern language needs to be reminded of DRY.
- 3pt14159 7y agoEh. Something I find pro devs do is just code the damn thing out quickly and wait for the right abstraction to emerge before stuffing it blindly into a function. If that means a bit of repetition, fine. If you push everything into tiny little methods or functions or abstract them into their own objects the first time you come across a couple of repeated lines of code then the clearer and better solution may not emerge as the requirements start to change. On the other hand, self documenting code is most easily done via method naming. This type of topic is hard to talk about. It's so nuanced that saying a statement about how to do it sounds like a a gutless generality. It also depends on the programming language and lifetime of the project. I've banged out some real ugly code when servers were on fire, but it was all stuff that was destined for an early death.
- networkimprov 7y agoDocumenting code via single-caller functions is usually a mistake, because to everyone else who looks, the set of functions is an API. Both internal and external APIs must be kept coherent. Also when readers are trying to understand exactly how some function changes the system state, having to refer to numerous other functions it calls is tedious.
- OJFord 7y ago> Documenting code via single-caller functions is usually a mistake, because to everyone else who looks, the set of functions is an API. That's a really good way of putting it. I try to avoid it by not writing new functions, but gladly using existing ones, in my implementation of whatever single new one. For example if I'm writing a find_and_update_foobar function, I'll use find_foobar if it exists, and with the right signature, but I won't write it just to implement the one I actually care about; ditto update_foobar. But, professionally I've mainly only used python; so I find it still deteriorates into a mess. (I type hint extensively, but still it only takes some missing hints, or something too loosely - or wrongly - typed.) I haven't used rust professionally/enough/on something large enough to be sure, but my feeling is that it just having a type checker prevents so much mis-refactoring.
- aazaa 7y agoThis article would benefit from some code examples. As it is, it left me with the same thought as those who claim to never need debuggers or object-oriented features: Fine let's say you're right - how do I implement your system?
- crispinb 7y agoThe comments here suggest two things: (1) most people misunderstand DRY (ie. they think it's about code rather than knowledge duplication), and (2)the article didn't do a great job of clearing the issue up. Though an alternative to (1) is that the meaning of DRY in common dev parlance has changed & has come to mean something different from Thomas & Hunt's intention.
- layer8 7y agoWhat they meant by DRY is otherwise known as SPOT — Single Point Of Truth — which is harder to misinterpret. The same “truth” — which can be data, values, behavior, policy, etc. — should not be defined multiple times in separate places, because a future change would have to be applied to all the places, or else cause different parts of a program or datastore to have inconsistent views on what the “truth” is. If you google for it, you will find the synonymous “Single Source Of Truth”, which however makes for a worse acronym.
- maest 7y agoIncidentally, this may explain why caching is hard - cache invalidation in particular. By definition, it must violate this SPOT/SSOT principle.
- layer8 7y agoWhile there is a thematic connection, SPOT is usually more of a design-time (or coding-time) principle. Caches still represent the same source, just time-delayed.
- regularfry 7y agoThat's not quite true; it's closer to say that it's very easy to design a cache mechanism which accidentally violates SPOT.
- rileymat2 7y agoI don’t disagree with this but it is more complicated because often the order statements are executed in is knowledge. Much duplicated code is duplicated knowledge. The question is whether it is a coincidence or the same concept.
- rojobuffalo 7y agoHaving a couple lines that are similar or copied in several places shouldn't be considered such a bad thing. Repetition reveals similarity, and having clear signals of similarity is really important. It's often more expressive / easier to understand than a single method name. Premature abstractions are way worse than repetition. A poor or insufficient abstraction leads to obfuscation which leads to misunderstanding which leads to novel constructs for the same responsibility. Because a poor abstraction can be really really difficult to back track, you end up with hacky work-arounds to get something done. I think encountering novelty in a codebase is the biggest thing that damages comprehension; and repetition actually enhances comprehensibility.
- lr4444lr 7y agoI feel like this article is being critical about something without justly staking a clear claim about what the right approach is. In my experience, the benefit of DRY code is bug reduction and overall increased new development velocity. There is a whole class of bugs around similar behaviors that devs and product managers expect to move in sync which don't, because features develop over time and it was just easier to code separate small bits than refactor into a common code path. Yes, it can make readability harder to unify into abstractions and create the right configs or import steps. But the time hunting down and fixing the bugs, plus the drag on overall feature development due to having to write updates in multiple places and test for them is far worse to deal with for not taking that preventative measure.
- proc0 7y agoSo what's the problem with what people do? The article doesn't go into detail. Keeping things 100% DRY is never a bad thing, with the only exception that code becomes too obscure and hard for new contributors to start on, which granted it's pretty important, however it's not like people are getting DRY wrong.
- deleted 7y ago[deleted]
- makecheck 7y agoI don’t mind repeating something as long as I write it in a style that could become a function in a straightforward way. Seems like the first time you have to change something, you realize it applies to one case and not the other. The more important thing is that the repeated/common parts are obvious. For example, if you reuse the same logic in a couple places, where the only difference is some specific variable, it should be written as a block with alias variables at the top. That way, two different cases look literally the same (except for a couple assignments at the top).
- sethammons 7y agoA friend at work (years ago) introduced me to WET: Write Everything Twice, a cheeky response to DRY enthusiasts. It falls just short of the Rule of Threes (as soon as you write it a third time, refactor it out). I think this article does have something going for it. DRY should be about knowledge. Don't repeat yourself by handling tax rates all over, get that into a central place. This is not about turning similar looking blocks of code into a clean single block that handles everything as these tend to actually hurt maintainability (ever see the littering of conditionals in "DRY" code because multiple call sites use the similar code slightly different? Yeah, you did it wrong). Another comment wrote it well by mentioning SPOT: Single Point of Truth. DRY and WET SPOTs. I feel like an analogy is forming that someone more quippy than myself can ferret out.
- hinkley 7y agoDRY tests are. the. worst. Way to lock us into last years’ requirements, bud. This is where DAMP comes in. Descriptive And Meaningful Prose. I should be able to read the test failure message and know what I broke. Barring that, I should be able to read the test (not the whole fucking test file) and tell what I screwed up. Anything else kills momentum, and I just want to get away from your code as fast as possible. Which means more tech debt.
- deleted 7y ago[deleted]
- stinos 7y agoOn the other hand, articles like this or principles like WET don't suddenly make it ok to just go ahead and duplicate code all over the place. It's not like code cannot be knowledge. Depending on the type of code SPOT and (what gets misunderstood as) DRY are totally about the same thing and mean the proper solution is to take those bits of similar code and make them into a function. Anyway, you likely know that already but I just felt information like this needs to be on this page as well to avoid possible beginners reading it might think all duplication is fine :] Because I've seen what happens when code containing the knowlegde gets duplicated and the result was never good and most of the time horrible on all fronts.
- 7y ago
- _bxg1 7y agoThe article is weirdly void of a counter-proposal, or a definition of what it means to not repeat yourself in terms of "knowledge"
- reggieband 7y agoI have so much to say on this topic that I feel like I can't say anything. I'll just leave it at: beginners tend to do too little, intermediates tend to do too much and experts try to do no more than enough.
- WalterBright 7y agoAny programming guideline regarded as Dicta Bölke is going to lead to garbage. They always must be leavened with Good Judgement.
- drewcoo 7y agoDoes anyone else see a certain irony in the raw number of Dry articles in existence? Or the fact that people keep writing them? I think the deeper problem in the software industry is that we have no collective memory and need to DRY up as a whole.
- fsajkdnjk 7y agonowadays, as golang dev, i don't even know how DRY looks like :D what I've learnt throughout many years of coding is that purest mantra one should follow is YAGNI. devs think like devs and strive for perfect code. but that goes directly against the business. the majority of the entire world is being run on really bad code. but that bad code works. and that is what is important. in a way, you should treat things like blackboxes with strict interfaces. no one should care how the box works, as long as its interface works like it is supposed to. PS: the dangers of DRY are introduction of deep dependencies that might, and probably will, bite you in the ass along the way. DRY should be used only for libraries, not for business logic - ever.
- epicgiga 7y agoDRYing the code is just an entry level form of simplifying the code. It's a good starting point, but its value quickly taps out once junior devs start writing incrementByOneFromZeroToNLoop(n) functions. Code is closer to a craft like carpentry than a pure knowledge job. There aren't any rules, only heuristics, and it takes time to hone your skills (not "learn" them). The biggest limiter in this is the excessive tendency for flat hierarchies in dev. It flies in the face of the apprentice - journeyman - master system that has always naturally structured the delivery and learning of craftsmanship.
- drbojingle 7y agoImo, Dont Repeat Yourself makes most sense when you forget about code and take it to mean that you shouldnt repeat your work. IE, if you wrote some code in one place that you needed elsewhere, copy pasting the code is fine under my interpretation because it allows you to spent the least amount of time working on a problem you've already solved.
- anonymouswacker 7y agoWhy do developers not see the forest for the trees?
- namuol 7y ago> [...] the original “Don’t repeat yourself” was nothing to do with code, it was to do with knowledge > The trouble with DRY is it has no reference to the knowledge bit, which is arguably the most important part! Okay. Now what does this mean? Is this article effectively a tantalizing recommendation to read The Pragmatic Programmer?
- deleted 7y ago[deleted]
- hyperpallium 7y agoYou can have specious repetition, code that is identical only by coincidence, not in a deep semantic sense. To determine what it is, you need to understand the domain. Part of that is knowing not just what it is, but how it generalizes and predicting how it is likely to change. Of course, this is approaching perfection. One could also cut and paste monkey-like, e.g. instead of looping (without a performance need to unroll loops).
- wruza 7y agoThe opposite of the rule of three and pattern detection is an instant detection stupid code (no funny acronym for that). An example of stupid code: let setX = (e) => {this.x = +e.target.value} ... other setup ... input({onchange:setX, value:this.x}) This code is not a subject of undry or rule of three, as it’s ratio of meaning to character count is too low. And yet some frameworks make a decision to abstract it out at a wrong point: let [x, setX] = ... ... other setup ... input({ onchange:(e) => setX(+e.target.value), value:x}) instead of clean and readable input_num(this, 'x', {}) // or this.input_num('x', {})
- seanwilson 7y agoThe comments should make it painfully obvious there isn't a general rule that applies to all projects in all situation. DRY, WET, DAMP, SPOT, KISS, YAGNI... Software engineering is too nuanced to be summed up in an acronym and surely the inventor of each acronym only intended it to be a basic rule of thumb.
- goto11 7y ago"It feels good" - I think that is a really important point! Overzealous DRY'ing is like a game. Every few tokens you save by clever reuse is a small victory. So it is easy to lose sense of the big picture. Programmers often like logical games and challenges, but it is dangerous to treat development like that. We should be weary of micro-optimizations for "elegance" which actually hurt the larger-scale maintainability of the system.
- skywhopper 7y agoI wish the author here or Dave Thomas would explain what they mean by DRY meaning “knowledge”. They both say that and leave it as obvious...
- dllthomas 7y agoHappy to do as asked, though I am a different Dave Thomas. Per my understanding, it's anything you might say about your system, especially as it relates to your domain. "There is a button here", "this is what we store about users", "broken widgets are red", "this is how we calculate interest", ...
- dllthomas 7y agoIt's memetics. "DRY" is catchy, easy to talk about, easily verbed as a recommendation, seems like a good idea, and seems to be recommended by people who know what they're doing. The problem is that it seems self explanatory, so no one discusses the definition. At the same time, the more obvious definition isn't the right one. As a counter-meme, I have been proposing we refer to overaggressive syntactic deduplication as "Huffman coding".
- luord 7y agoUnlike Abramov's original post, I actually agree with this one, being more nuanced. The author acknowledges that DRY (and ultimately, clean code et al) itself is not evil; it's just misunderstood.