14 ms·
Repeat yourself, do more than one thing, and rewrite everything (2018)
- foundart 4y agoLots of good ideas here, especially that duplication is better than the wrong abstraction.
- tpmoney 4y agoOne of the best pieces of advice I got really early in my career was write something 3 times before you decide to abstract it. Until you’ve done that, you just don’t know what parts you can really abstract and you’re likely wasting time. Pretty much every time I’ve ignored that advice I’ve regretted it.
- giraffe_lady 4y agoaka WET: Write Everything Twice.
- stametseater 4y agoSame. Writing something more than once gives you more than one perspective on the problem space. And with a better understanding of the problem space, you're more likely to find an optimal solution.
- avgDev 4y agoI found myself stuck in analysis paralysis and fear of not creating a perfect app. I became my worst enemy. My app was praised by VP, managers and staff using it, yet I saw it as a pile of garbage. Then I realized it doesn't have to be perfectly DRY, it could technically just be spaghetti. It isn't spaghetti but some things could be improved. While, better designed apps are easier to work with sometimes there are situation where it is impossible to create a formal design document, so you just need to 'send it'. The next iteration will improve many things, but if were to do those things initially the app would be in development for years, and now it is running a business.
- kitsunesoba 4y agoWith time I've progressively become less concerned with staying DRY, which perhaps counterintuitively has made it easier to avoid spaghetti problems. It's easier to keep things clean with a handful of near-duplicates that are tailored to the needs of their call sites than it is with a single trying to do everything. It's a bit more work to keep behavior consistent across duplicates but I'll take it if it means less untangling work for myself in the future.
- programmarchy 4y agoI’ve found the same, and have leaned more into patterns and proximity as guides. Find good patterns that can be repeated easily and predictably. Also, keep related code close together so it’s easy to find and copy somewhere else. Often times there are higher level abstractions that emerge which can then be “dry”ed out, but trying to do that too early creates more problems than it solves.
- toast0 4y agoGarbage that shipped and has customers and a purpose (and maybe makes money, if your company is interested in that) is called Legacy. Perfect code that never shipped doesn't have a name. Worst case, your garbage code gets you 6-12 months with customers and it has to be thrown away. No big deal, you said it was garbage and now you've got 6-12 months of actual knowledge of what your customers need and want, instead of what you thought they would need. You can make new legacy garbage that's much better than the first version now.
- mbrameld 4y agoI think of building software kind of like making pottery or sculpting in general. I just get something useful working to start with, it doesn't matter what the structure is. It's a lump of clay to be refined.
- Buttons840 4y agoWhen I have analysis paralysis and feel my app is a pile of garbage, I identify which part of the code I am most afraid of and then rewrite it and put tests around it, whatever it takes to become super confident that that one part I was afraid of is now working correctly.
- mmcclure 4y ago> If a replacement isn’t doing something useful after three months, odds are it will never do anything useful. This is painful to read, but unfortunately rings true. As an aside, when I saw the domain name/year I thought I'd find an update to one of my favorite programming rants of all time, "programming sucks."[1] [1] https://www.stilldrinking.org/programming-sucks https://www.stilldrinking.org/programming-sucks
- strict9 4y ago>“Don’t Repeat Yourself” often gets interpreted as “Don’t Copy Paste” or to avoid repeating code within the codebase When I think of the most difficult to understand code I've come across it was probably written by someone who lives and breathes that interpretation of DRY. But it doesn't end with code comprehension. Extreme abstraction and countless files and components also lead to buggy and difficult to maintain code. It's easy to lose understanding of branches and business flow when abstraction exists in the extreme.
- Spivak 4y agoI call these frankenframeworks. The constant drive to DRY and reach the supposed nirvana of code being a DSL of pure business logic leads to more and more implementation details being shoved under the rug to deeper and deeper layers. But for some reason there’s no foresight that any non-trivial change requires changing more than just the business logic and so you have to resort to bolting on config options, weird hooks, mixins, “concerns”, and global state for no reason other than it’s all you can do to reach down the layers.
- unethical_ban 4y agoBack when I took a Comp sci course 16 years ago (shit) I was taught that a single function should try to fit within a screen. The idea is that breaking a task up into digestible steps would both harbor more readable code, self-documentation and code reuse.
- MrPatan 4y agoGood idea, wrong metric. What should fit in a screen is the concept. If you take a big, hairy, complicated thing and just chop it into several functions that fit on a screen you have gained nothing.
- saulpw 4y agoIf you name the functions reasonably, and the functions don't interact except through arguments and return values, you have absolutely gained something.
- sundarurfriend 4y agoIf you're not a programmer and are just stumbling around trying to code, ideas like DRY and abstractions and modularity are super useful. I work with scientists/PhD students helping with their code from time to time, and it's easy to forget how much basics we take for granted. If you're a career programmer or want to be one, then yes, it's better to try things out and figure out from experience why these principles exist. Then, you can break the rules, because you understand their purpose and limitations now.
- smac__ 4y agoHere, only apply Don't Repeat Yourself to data not code. Making it mean each piece of knowledge should have a single authoritative reference. E.G. Avoid (if possible) places where state is synced.
- pphysch 4y agoThat's a great way to summarize it. With the corollary that "hard-coded data" is still data, not code.
- westernpopular 4y agoaka single source of truth
- agentultra 4y agoI think there needs to be a version of this for pure FP languages like Haskell or even OCaml or F#; almost none of these maxims and aphorisms seem to apply. Abstraction? It has a completely different meaning in this context. Our business is abstraction: creating precise definitions and semantic meaning where none existed before. It is much easier to create abstractions and sufficiently demonstrate their laws hold. So much so that we often design our programs and libraries with abstractions first. This forces our programs to deal with the side-effects of interacting with the world outside of our programs' memory-space at the very edges of our program. We can prove a great deal of our code is correct by construction which lets us focus our testing efforts on a much smaller portion of our programs. However even in non-FP languages I think a lot of these problems do go away if you use the above definition of abstraction and spend a bit more time thinking about the problem up front before writing code. Not too much, mind you, because the enemy of a good plan is a perfect one; however enough that you know what the essential properties and laws are at least tends to help and reduce the amount of code you need to consider and write.
- avgcorrection 4y agoFP has a better definition of abstraction where it is closer to the sense of “simplify”. In procedural programming it might just mean indirection. Or silly metaphors.
- jrochkind1 4y agoI don't disagree with a single thing in the OP.
- jimmaswell 4y ago> Never rewrite your code from scratch, ever! Is this really a common sentiment? When it comes to rewriting others' code, it's prudent to keep in mind that it's naturally harder to understand code written by someone else. Just because you're confused in the first five minutes of looking at something doesn't mean it's an unsalvagable spaghetti. It's too easy to underestimate the time and cost of a rewrite and confuse your lack of knowledge for a fault in the codebase. Of course sometimes a rewrite is still appropriate after that consideration. If it's your own code then you probably have a better judgement than anyone whether it's in need of a rewrite. Doesn't everybody tend to rewrite major components of something in its early states? Though I find as I gain experience over the years I have to rewrite/"draft" code less and less.
- kitsunesoba 4y agoSome of the most significant jumps in quality I've seen have been in total rewrites of my projects, at least when the project in question was at least moderately complex. There even used to be a project that I'd rewrite every so often (but never publish) just to see how much better each iteration was. That fell to the wayside because I got busy, but I should probably pick it back up at some point.
- rzzzt 4y agoDo you keep the project runnable at all times when you rewrite? My issue is twofold: 1) You can not do anything with the pieces until they are back together 2) If everything goes well, you get to see the exact same behavior as before. It can be faster, easier to modify or add stuff, perhaps even more elegant on the inside, but it will still be the same application.
- kitsunesoba 4y agoFor #1, yeah I do. If I'm working on more routine/boilerplatey parts I might go a little longer without running, but it's pretty important to me to verify that each bit is working as expected before moving on. It's easy to wind up in a mess if I'm operating on the assumption that what's been written so far all works. For #2, yeah that's true, but for me less visible improvements are gratifying, because not only is the thing being rewritten being improved, but I can also apply learnings to other projects that make rewriting them less necessary. Also, it just bugs me when there's reasonable obtainable improvements in optimization, flexibility, etc that I've left on the table… feels like I left the job half-done which isn't a great feeling.
- tabtab 4y ago"Always do X" and "Never do Y" are almost always bad advice. Live by rules of thumb but don't become a zealot or rigid purist. Some duplication is acceptable, but lots is probably a sign that something is factored poorly or the wrong tool for the job. Rules of thumb include but are not limited to: KISS, YAGNI, and DRY. Another good rule of thumb is make things easy to figure out for future maintainers who you have yet to meet and may never. Programming is communicating with a future human, not just a machine. It's about people. (Insert Soylent Green jokes here.) At least in ordinary CRUD, I find that simple, re-composable mini-components get me far more reuse than big swiss-army-knife-like components. Small components that can be copied, tweaked, remixed, or ignored with ease are more flexible. Also, communicating via strings and string maps (dictionaries) makes them easier to mix and match than complex data structures/classes. String maps are relatively simple yet flexible for structure passing. You lose a little compile-time-type-checking by going string-centric, but there are work-arounds, such as optional named parameters that switch on type scrubbing when needed. (I love optional named parameters. Every language should have them.)
- a_c 4y agoYour code is useless if no one is using it. If a tree falls in a forest and no one hears about it, it made absolutely no sound. Everything comes after that. Many programmers put cart before the horse by subscribing to tidbits of "best practice". Having people using it, you can think about making it right and fast, making the making of it right and fast. Then make the right people making it right and fast. And turtle all the way done from here.
- BeetleB 4y agoI've said it before and I'll say it again - I should encapsulate it as a law. BeetleB's Law of DRY: Every article that complains about DRY will be a strawman argument. The DRY acronym came from The Pragmatic Programmer, and almost every instance of DRY people complain about is not at all what is advocated in the book. There are different ways of interpreting what he wrote, but my version is: "If you have two separate requirements that are very similar, keep them separate in code. If your duplicated code is one requirement, then DRY it into one location in your code." So this: > Following “Don’t Repeat Yourself” might lead you to a function with four boolean flags, and a matrix of behaviours to carefully navigate when changing the code. Is not DRY. In fact, having boolean arguments is almost a guarantee that you've violated DRY. Another way to know you've violated DRY: If one requirement changes, do I need to add if conditions to the DRY'd function to ensure some other requirement doesn't break? If yes, you're in violation. Never tie in multiple requirements into one function. Or rather, do it but don't call it an application of DRY.
- klysm 4y agoDoesn’t matter what it originally meant, people take it to mean you shouldn’t have repeated code and that’s the DRY we all live with which results in bad abstractions. I don’t think it’s a straw man at all, unless you use your specific definition of DRY which isn’t very useful
- BeetleB 4y agoPeople are welcome to co-opt the acronym and give it another meaning. The issue is that the original DRY is a damn good principle, and it is more important to give it a name and propagate that knowledge. If all we do is rail against the "new" DRY and forget the original one, then we are at a net loss.
- rched 4y agoThe problem is with the entire concept of development "principles". They are a bad way to propagate knowledge. I suspect more people have an incorrect understanding of DRY than not. Seems like a net loss to me. We should ditch these principles altogether and focus on teaching a deeper understanding of these concepts that captures the nuances.
- Clent 4y agoIgnore advice on what not to do. Listen to advice on how to accomplish tasks. A carpenter does not study how not to hang a door. Likewise, don't listen to advice on how not to write code.
- deleted 4y ago[deleted]
- ParetoOptimal 4y agoI don't think it's quite the same though... or at least I can make an argument for learning about ways not to do programming tasks because it generalizes. There are patterns between ways not to do programming related things, e.g. use the single responsibility principle, use pure functions. There are also so many ways to accomplish programming tasks, it's useful to be able to filter down that multitude of ways or notice "this stack overflow post has 5 bad patterns, maybe I shouldn't use it".
- bokohut 4y agoI found the article to be sound in the fact of modularity and building upon what works as the old adage states "if it ain't broke don't fix it" holds true however there is always room for technology improvements when one monitors and measures the entire lifecycle of a transaction system. The world's systems exist in the way that they do today because someone took a risk on a design to work and the uptake of what “works” only spreads as the acceptance of said design is proven. I have wasted most of my adult life rewriting the same system in entirety five times and am now in the process of rewriting it again for the sixth however now I am applying it to a different industry. The design was proven over several decades in the critical uptime high transaction volume payments industry and now that same design is being generalized into other industries. The other industries applications may not have the same transaction volume requirements as the financial industries designs however refactoring what works ensures the critical availability portion as well as the scaling flexibility to meet potential high transaction volume should any other applied industries demand that same growth requirement.
- OliverJones 4y agoMy experience of this is interesting. When I'm writing code I care a lot about, I don't have to worry about DRY stuff, because I can't really write the code without figuring out the right abstractions. It starts DRY. But when I'm cranking out reporting code or boilerplate of some kind and I just want to finish the job, my work starts out dripping wet copypasta. I test it. I then do some squeezing -- refactoring -- to unify some of the abstractions and delete the almost-dup code. I try to DRY it up to a reasonable level. But, I confess, I don't subject the abstractions to as much scrutiny as the code I care about. My successors probably hate me for that. But...
- jacknews 4y agoThe problem with DRY and SRP is that you might be simply moving the complexity instead of reducing it. Eg with a bunch of one-line functions, you then need to call them, or they call each other, and then the complexity is in the call graph rather than laid out in a single function. Code needs to be as complex as the problem it is solving, the challenge is to avoid complexity beyond that, and ideally have the code be 'transparent' to the problem, ie it's easy to see the problem and how it's being solved from the code. As an aside, didn't 'fat controller' stop being a thing in the early 2010s, and the problem changed to 'god models'.
- user3939382 4y agoI don't know if there's a fancy programming acronym for this, but as much as DRY or SRP my rule is this: if I were to break this chunk of code off into a function, it would: * Give this chunk of code a name * Clearly document, in types and names, the inputs and outputs at its boundaries, without having to discover this through a breakpoint Does the clarity of adding that documentation outweigh the indirection? A great example is a set of 4-5 if-conditions. Looking at them might be unavoidable arcane-looking complexity with regex's or who knows. Now instead it's called: if ($this->orderIsValid($order)) Isn't that nicer in most cases for the person reading it, who's trying to understand what the larger function does? Yes, even if it's only used in that one spot. A lot of this is subjective so I'm not going to pretend to have written the programmer's stone tablet of rules but that's my strategy.
- revskill 4y agoDry is the difference between a good and a not good enough programmer. Good vode is easy to operate and extend later. Nondry code is a tech debt.
- vendiddy 4y agoNever trust an abstract principle by itself. Come up with your own concrete examples. Tinker with these examples to improve your understanding of underlying factors of the principle. Look for examples that might contradict the principle and understand why. Let us take DRY for example: If I make a change in one place, and I have to know about 4 other far away places to make the same change, will that cause problems? What if there two duplicate lines of code in the same file, right below each other? What if it's a 3000 line file that's duplicated? How about a 4 line function? What if changing it in one place doesn't mean you have to change the other place?
- babbledabbler 4y agoThis is something I wish was more widely discussed. Abstract principles are only templates for how to act, not prescriptive rules on what to do. Much like a craftsman uses various stencils and measures to guide their craft, it's not simply using the stencil that is necessary but applying that stencil with skill and judgment, and when working with others, sharing those stencils kindly.
- ladyattis 4y agoWhen you usually have flags in your function then you really have two functions in one which can be a problem. In practice, I usually break these kinds of functions down if it's looking like it's handling radically different cases, it does add some duplication but most times it's just the boilerplate of the language/platform than the actual work itself.
- bennysonething 4y agoAm I the only person who hates feature flags? We're doing it so we can do trunk based Dev. It's ridiculous, it makes every feature so much more complicated. All for the sake of not managing some branches.