Most active commenters

    ←back to thread

    1455 points nromiun | 15 comments | | HN request time: 0s | source | bottom
    Show context
    exclipy ◴[] No.45077894[source]
    This was my main takeaway from A Philosophy Of Software Design by John Ousterhout. It is the best book on this subject and I recommend it to every software developer.

    Basically, you should aim to minimise complexity in software design, but importantly, complexity is defined as "how difficult is it to make changes to it". "How difficult" is largely determined by the amount of cognitive load necessary to understand it.

    replies(11): >>45077906 #>>45077954 #>>45078135 #>>45078497 #>>45078728 #>>45078760 #>>45078826 #>>45078970 #>>45079961 #>>45080019 #>>45082718 #
    bsenftner ◴[] No.45077954[source]
    Which is why I consider DRY (Don't Repeat Yourself) to be an anti-rule until an application is fairly well understood and multiple versions exist. DO repeat yourself, and do not create some smart version of what you think the problem is before you're attempting the 3rd version. Version 1 is how you figure out the problem space, version 2 is how you figure out your solution as a maintainable dynamic thing within a changing tech landscape, and version 3 is when DRY is look at for the first time for that application.
    replies(5): >>45078178 #>>45078299 #>>45078606 #>>45078696 #>>45079410 #
    zahlman ◴[] No.45078299[source]
    DRY isn't about not reimplementing things; it's about not literally copying and pasting code. Which I have seen all the time, and which some might find easier now but will definitely make the system harder to change (correctly) at some point later on.
    replies(10): >>45078465 #>>45078493 #>>45078525 #>>45078789 #>>45078797 #>>45078961 #>>45079164 #>>45079325 #>>45079628 #>>45079966 #
    1. ryeats ◴[] No.45078493[source]
    This is a trap junior devs fall into DRY isn't free it can be premature optimization since in order to avoid copying code you often add both an abstraction AND couple components together that are logically separate. The issues are at some point they may have slightly different requirements and if done repeatedly you can get to a point that you have all these small layers of abstraction that are cross cutting concerns and making changes have a bigger blast radius than you can intuit easily.
    replies(5): >>45078671 #>>45078700 #>>45079551 #>>45080482 #>>45081244 #
    2. rkomorn ◴[] No.45078671[source]
    The reverse of that is people introducing bugs because code that wasn't DRY enough was only changed in some of the places that needed to be changed instead of all the places.

    To me, it's the things that are specifically intended to behave the same should be kept DRY.

    replies(2): >>45079743 #>>45081298 #
    3. zahlman ◴[] No.45078700[source]
    If you notice that two parts of the code look similar, but have a good reason not to merge or refactor, that deserves a signpost comment.

    If you're copying and pasting something, there probably isn't a good reason for that. (The best common reason I can think of is "the language / framework demands so much boilerplate to reuse this little bit of code that it's a net loss" — which is still a bad feeling.)

    If you rewrite something without noticing that you're doing so, something has definitely gone wrong.

    If a client's requirements change to the point where you can't accommodate them in the nicely refactored function (or to the point where doing so would create an abomination) — then you can make the separate, similar looking version.

    replies(2): >>45078878 #>>45079785 #
    4. smallnamespace ◴[] No.45078878[source]
    > If you're copying and pasting something, there probably isn't a good reason for that.

    I would embrace copying and pasting for functionality that I want to be identical in two places right now, but I’m not sure ought to be identical in the future.

    replies(1): >>45082725 #
    5. fenomas ◴[] No.45079551[source]
    All my younger colleagues have heard my catchphrase:

    Copy-paste is free; abstractions are expensive.

    replies(1): >>45079892 #
    6. sroerick ◴[] No.45079743[source]
    This is the correct take - if you're getting this type of bug, it's now past time for DRY
    7. chipsrafferty ◴[] No.45079785[source]
    I don't think it's as cut and dry as that. In my team we require 100% test coverage. Every file requires an accompanying test file, and every test file is set up with a bunch of mocks.

    Sure, we could take the Foo, Bar, and Baz tables that share 80-90% of common logic and have them inherit from a common, shared, abstract component. We've discussed it in the past. Maybe it's the better solution, maybe not. But it would mean that instead of maintaining 3 component files and 3 test file, which are very similar, and when we need to change something it is often a copy-paste job, instead we'd have to maintain 2 additional files for the shared component, and when that has to change, it would require more work as we then have to add more to the other 3 files.

    Such setups can often cause a cascade of tests that need updated and PRs with dozens of files changed.

    Also, there are many parts of our project where things could be done much better if we were making them from scratch. But, 6 years of changing requirements and new features and this is what we have - and at this point, I'm not sure that having a shared component would actually make things easier unless we rewrite a huge amount of the codebase, for which there is no business reason.

    replies(1): >>45080638 #
    8. wilkystyle ◴[] No.45079892[source]
    One of the many great takeaways from Sandi Metz's talk at Railsconf 2014: "Duplication is far cheaper than the wrong abstraction."

    https://www.youtube.com/watch?v=8bZh5LMaSmE

    Worth watching in its entirety, but the quote is from ~13:59 in that video.

    replies(1): >>45080260 #
    9. drivers99 ◴[] No.45080260{3}[source]
    The related blog post (I just found thanks to watching that and then searching for her site) is great too: https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction

    It explains so much of what has been bothering me about what I work on at work, and now I understand why and some of what to do about it.

    10. kragen ◴[] No.45080482[source]
    DRY isn't an optimization of any kind, so it can't be a premature optimization. "Premature optimization" is a specific failure mode of programmers, not just a meaningless term you can use to attack anything you don't like. "Optimization" is refactoring to reduce the use of resources (which are specifically cycles and bytes) and it's "premature" when you don't yet know that you're doing it where it matters.

    Otherwise I mostly agree.

    11. matijsvzuijlen ◴[] No.45080638{3}[source]
    I can understand requiring 100% test coverage, but it seems to me that requiring a test file for every file is preventing your team from doing useful refactoring.

    What made your team decide on that rule? Could your team decide to drop it since it hinders improving the design of your code?

    12. seadan83 ◴[] No.45081244[source]
    Indeed a trap. I'd say DRY is all about not duplicating logical components. Just because two pieces of code look similar, does not mean they need to be combined.

    As an analogy, when writing a book, it's the difference of not repeating the opening plot of the story multiple times vs replacing every instance of the with a new symbol.

    13. pkolaczk ◴[] No.45081298[source]
    An obvious example of that is defining named constants and referring them by name instead of repeating the same value in N places. This is also DRY and good kind of DRY.
    replies(1): >>45082660 #
    14. ryeats ◴[] No.45082660{3}[source]
    This is actually a particular pet pieve of mine because I worked with the Camel framework which has a lot of boilerplate in strings but if you start using constants for the common parts you now have an unreadable mess of constants concatenated together that buys you nothing.
    15. fauigerzigerk ◴[] No.45082725{3}[source]
    I agree completely. DRY shouldn't be a compression algorithm.

    If two countries happen to calculate some tax in the same way at a particular time, I'm still going to keep those functions separate, because the rules are made by two different parliaments idependently of each other.

    Referring to the same function would simply be an incorrect abstraction. It would suggest that one tax calculation should change whenever the other changes.

    If, on the other hand, both countries were referring to a common international standard then I would use a shared function to mirror the reference/dependency that they decided to put into their respective laws.