[HN Gopher] Goodbye, Clean Code
       ___________________________________________________________________
        
       Goodbye, Clean Code
        
       Author : danabramov
       Score  : 191 points
       Date   : 2020-01-11 21:32 UTC (1 hours ago)
        
 (HTM) web link (overreacted.io)
 (TXT) w3m dump (overreacted.io)
        
       | 29athrowaway wrote:
       | > Firstly, I didn't talk to the person who wrote it. I rewrote
       | the code and checked it in without their input.
       | 
       | If you want to modify a method that has 10 unique contributors.
       | Do you really need to talk to different 10 people to maintain to
       | make a change? That does not sound very effective.
       | 
       | And, most importantly: when you code as a job, all your
       | deliverables are company's property. They are not yours. The
       | company can do whatever they want with them, they don't need your
       | opinion or approval. If they want to replace every piece of code
       | that you ever submitted with an ASCII clown, then print the
       | source code make a pinata from it, they can do that too if they
       | want.
       | 
       | Secondly: version control. If you want the old version of some
       | code, you can retrieve from version control right? You can leave
       | a comment such as: "for a verbose version of this method, see
       | revision <sha1>".
        
         | yoz-y wrote:
         | > If you want to modify a method that has 10 unique
         | contributors. Do you really need to talk to different 10 people
         | to maintain to make a change?
         | 
         | I think the more apt example in this case would be if somebody
         | made a modification in that file and you rewrote just their
         | modification immediately after they done it without discussion.
         | If the modification is necessary so soon it means that the
         | feature/implementation were not discussed properly before and
         | the process probably needs revisiting.
         | 
         | Of course if you are modifying part of the file, or doing some
         | previously agreed refactoring effort then explicit author
         | consent is not necessary.
         | 
         | > Secondly: version control. If you want the old version of
         | some code
         | 
         | I think here we talk mostly about production code. The problem
         | with relying on the source control for "I will revert this to
         | the old version when it will become required" is that the code
         | will evolve in subtle manners and it will be hard to roll back
         | and apply all patches on top of it.
        
         | flurdy wrote:
         | > > Firstly, I didn't talk to the person who wrote it. I
         | rewrote the code and checked it in without their input.
         | 
         | > Do you really need to talk to different 10 people to maintain
         | to make a change?
         | 
         | No, you don't talk to all of the 10 contributors. But if you
         | want to still work as a team you should talk to a few.
         | Depending on the size of the change.
         | 
         | Some or even all of the previous contributors may no longer be
         | at the company or are inaccessible. But a super quick
         | discussion with 1-3 other team members should float if this is
         | a good idea or not.
         | 
         | Obviously, if you practise pair programming, most smaller
         | rewrites just need a consensus within the pair, and a more
         | extensive change may be a good idea to get the approval of
         | another pair, especially if some other team members were the
         | original contributors.
         | 
         | There is no need to be precious about any existing code. Nor
         | any need to be a bull-in-china-shop either.
        
           | 29athrowaway wrote:
           | For quick changes, you can simply submit your changes in a
           | pull request and assign them as reviewers.
           | 
           | For non-quick changes (that are worth the cost), you can have
           | a discussion about it and evaluate pros and cons.
        
       | awinter-py wrote:
       | IMO line count is an important metric
       | 
       | if two companies are broadly similar but one gets the job done
       | with 10x less code, they're probably in a better survival
       | position
       | 
       | not all logic _should_ be reusable or super generic, but there 's
       | a size level at which avoiding abstractions becomes toxic to
       | further growth
       | 
       | there's a good article floating around somewhere about things you
       | learn at 1k, 10k, 100k-line codebases and how your philosophy
       | changes
       | 
       | with a million caveats, of course, size and maintainability are
       | going to be correlated
        
       | bfung wrote:
       | Did the colleagues code go through code review before it was
       | accepted?
       | 
       | And obviously, there wasn't a review for the refactored code
       | before check-in.
       | 
       | Use a code review system, would e avoided a lot of this in the
       | first place.
        
       | Dirak wrote:
       | I would even take your learnings from your experience a step
       | further and say that one should be proactive in talking to
       | teammates and exploring ideas on how to improve the codebase if
       | you think there is room for improvement. For instance, it may
       | well be that inheritance is the wrong pattern for that given
       | codebase, but there are indications that the current architecture
       | isn't scalable.
       | 
       | With more investment, more research could have been put into
       | looking at better suited architectures such as the Entity
       | Component System architecture, where Entities such as Rects and
       | Ellipsis are composed of units of functionality (position,
       | resizability, etc), which is a proven architecture for this sort
       | of application. Then, implementation would be a matter of getting
       | team buy-in / weighing the refactor pros and cons with your team.
       | 
       | Tangential, but Entity Component Systems are a great way to
       | structure systems with many types of entities that share subsets
       | of functionalities. https://kyren.github.io/2018/09/14/rustconf-
       | talk.html.
        
       | Havoc wrote:
       | I feel the code aspect could have gone either way.
       | 
       | It's the human part that went sideways. Egos are fragile & this
       | is essentially "your code is bad and I can do it better".
       | 
       | I've been on the receiving side of this exact thing - also
       | duplication. Fortunately the dup was bad enough that I could see
       | I was wrong.
        
       | kevin1024 wrote:
       | Duplication is far cheaper than the wrong abstraction.
       | 
       | https://www.sandimetz.com/blog/2016/1/20/the-wrong-abstracti...
        
       | jrs95 wrote:
       | To me the #1 thing that fixes the social issues described in this
       | post (changing code someone checking in code a few hours after
       | they pushed it) is a code review process. The most valuable thing
       | about always doing pull requests and code review is sharing
       | information and having discussion about changes, not necessarily
       | the immediate improvement of the code. A team will gain more
       | knowledge about what everyone is doing by reviewing each others
       | pull requests than they do from a daily standup by a pretty large
       | margin in my opinion.
       | 
       | In this particular example, reviewing a PR would have meant that
       | a discussion about whether or not that abstraction was a good
       | change _before_ the code was ever merged.
        
       | BeetleB wrote:
       | The first thing I did when I read this was come to the HN
       | comments and search for people complaining about DRY:
       | 
       | https://news.ycombinator.com/item?id=22022599
       | 
       | https://news.ycombinator.com/item?id=22022842
       | 
       | https://news.ycombinator.com/item?id=22022896
       | 
       | https://news.ycombinator.com/item?id=22022836
       | 
       | The author of this piece was not engaging in a DRY activity even
       | if he thought he was. He (perhaps unwittingly) admits to it
       | himself:
       | 
       | > My code traded the ability to change requirements for reduced
       | duplication, and it was not a good trade.
       | 
       | The acronym DRY was coined in _The Pragmatic Programmer_ , and
       | the author of that book makes it clear that DRY is about not
       | repeating _requirements_ in code. You definitely don 't want to
       | deduplicate similar code if it involves _multiple_ requirements
       | because then you entangle yourself, which is what the author of
       | this piece did.
        
         | monksy wrote:
         | Are you saying that they're repeating themselves?
        
       | monksy wrote:
       | To me this sounds like he gave up on producing something with
       | craftsmanship. It sounds like he's getting bullied by someone of
       | lessor experience.
       | 
       | If the code was blainently duplicated, that's going to create
       | problems later.
        
       | jcims wrote:
       | Isn't the only reason we care about duplicate code that we don't
       | want to miss an instance of it for enhancements or bug fixes down
       | the line? Don't we have technology that helps us reduce that
       | concern?
        
         | Rapzid wrote:
         | Yeah, it's not about text/code duplication as much as it's
         | about behavior duplication. In theory both, hopefully three or
         | more!, code paths share the exact same behavior and if that
         | behavior ever changes it will need to change EVERYWHERE you
         | introduced a method to abstract it away.
         | 
         | Depending though, the indirection trade off may not be worth
         | the abstraction to DRY it up. Then you end up with code like
         | what was popular in the bad old days of Ruby. Essentially, you
         | can get carried away.
        
       | sirtoffski wrote:
       | Off topic: Docusaurus V2 makes a really clean looking blog via
       | GitHub pages. Cheers
        
       | misterCrowley wrote:
       | Clean code and Agile is excellent and is important to use in
       | enterprise applications. The author needs to educate himself
        
       | smacktoward wrote:
       | My rule is: if I find myself sorting things into two buckets, one
       | of which I've given a name that obviously means "good" and the
       | other "bad," that's a sign I'm deciding emotionally rather than
       | rationally. It's time to take a step back and think about the
       | distinctions between the things in the buckets harder.
       | 
       | Sorting code into "clean" and "dirty" buckets is a good example
       | of this. Both bucket names are completely subjective, with
       | "clean" obviously meaning good and "dirty" bad. As the article
       | indicates, dig in a little deeper and it's not hard to find
       | objective ways the "dirty" code would actually be preferable.
        
       | quaquaqua1 wrote:
       | what the fuck did i just read
        
         | rckclmbr wrote:
         | A good post about someone learning that writing code is more
         | than just about how pretty it looks. How you work with others
         | is incredibly important in this industry
        
           | BelleOfTheBall wrote:
           | Is that not common knowledge? I feel like this is a well-
           | written post with a good point but it's a familiar point. You
           | could boil part of it down to 'all's good in moderation', so
           | don't just keep your code clean, keep it clean and easy to
           | read, etc.
        
             | dictum wrote:
             | Leaving common knowledge undocumented is, in itself, a
             | misguided attempt at DRY.
             | 
             | Your common knowledge isn't necessarily everyone's common
             | knowledge; what you perceive isn't necessarily _what it
             | is_.
             | 
             | Every day there are many people just starting to code.
             | There are cultural and regional differences. They might not
             | have hit the exact spot in which this information appears.
             | 
             | Knowledge also disappears, fades, gets censored or
             | destroyed, gets mixed up and remembered incorrectly. You
             | might take something as a given and misremember it 20 years
             | from now. You might read your own code 5 years from now and
             | not know _why_ something 's there -- something that was
             | taken to be obvious.
        
             | mannykannot wrote:
             | It definitely is something that needs to be said, as it is
             | not uncommon to find people doing the opposite: taking a
             | rule-of-thumb and asserting that it is the one true way.
             | The people who are most likely to make this mistake are
             | smart and well-motivated, enthusiastic about the power of
             | abstraction to simplify things, and have some experience
             | but not a lot.
        
             | danabramov wrote:
             | I didn't mean to imply there's anything novel in my post
             | :-) someone's gotta beat that drum once in a while.
        
               | vga805 wrote:
               | Thank you Dan, your posts have been a great source for a
               | lot of us out here.
        
         | adamisom wrote:
         | Would it help to point out the the author of that post invented
         | React?
        
           | azangru wrote:
           | Would it help to point out that he didn't? :-)
        
           | danabramov wrote:
           | Thanks but I'm only helping maintain it. :-) I did co-author
           | a few other projects though.
        
           | tudorpavel wrote:
           | Not really and Dan didn't invent React, he is currently on
           | the core team. Just ignore trolls such as GP, it ain't worth
           | it.
        
       | [deleted]
        
       | Insanity wrote:
       | I agree that not every "smart approach" is worth it if you
       | sacrifice legibility.
       | 
       | But I don't think you necessarily need to ask permission to
       | refactor code. On the projects I had the past couple of years
       | everyone understood that code was open to be changed by anyone.
       | 
       | In practice we'd often ask "why did you do X" instead of just
       | rewriting it.
       | 
       | I trusted the people I worked with on those projects though and
       | if they thought they had to rewrite part of my code for whatever
       | reason, that was fine by me. And vice versa, I changed their code
       | and that was fine.
        
         | monksy wrote:
         | That and follow it up on a code review pointing out that it's
         | duplication that could lead to bugs later.
        
         | scarface74 wrote:
         | Well in his case, did refactoring the code to clean it up add
         | business value?
         | 
         | There has to be a very good reason for me to refactor
         | existing/working code for instance for performance.
         | 
         | I won't refactor code to reduce existing duplication but I will
         | refactor code if I see there is some functionality that I need
         | elsewhere so I won't just copy and paste.
        
           | Nullabillity wrote:
           | > Well in his case, did refactoring the code to clean it up
           | add business value?
           | 
           | Yes, it made future modifications easier and discouraged
           | adding special-case behaviour.
           | 
           | And after reverting the change they did apparently fall into
           | that trap.
        
       | franciscop wrote:
       | This should rightfully be on the front-page of HN. I've gone
       | through something almost the same as Dan Abramov here, and I feel
       | it's difficult to impossible to explain this and you have to
       | experience it yourself.
       | 
       | The tricky bit is where to draw the line, which I've learned only
       | after pouring thousands of lines of code and I understand is a
       | bit different for everybody. The rule of three[1] was a very
       | useful rule of thumb in the beginning, but there are many
       | secondary variables that I unconsciously use to decide when to
       | remove repetition. e.g.:
       | 
       | - Single file tends to be split _less often_ , since refactoring
       | it is easier. Example: the single file routing in React being
       | repetitive is okay, but if there's multiple files with routers
       | and custom logic I'd consider a helper a lot stronger.
       | 
       | - Conceptually straightforward APIs tend to be split _more often_
       | , since it's easy to package and reason about, as well as design.
       | Examples: cookies, warnings, kv stores, etc.
       | 
       | - Early stage projects tend to be split _less often_ , since few
       | things are not yet clear and being able to put everything in your
       | head is a lot more important.
       | 
       | It's also one of the lessons that you should learn going to
       | senior. To the extreme, someone insisting in removing this kind
       | of duplication for the sake of it is often a sign of a junior dev
       | (as in, because it's _wrong_ and not trying to understand the
       | codebase /tradeoffs first).
       | 
       | [1] https://blog.codinghorror.com/rule-of-three/
        
       | acjohnson55 wrote:
       | I find myself wishing the question of whether to factor code out
       | wasn't binary. Like if you could transclude parameterized code.
       | You'd get the benefits of not having to keep a stack trace in
       | your head, while still having a canonical version of an
       | abstraction. Like a macro, but always expanded in-place.
        
       | paulnechifor wrote:
       | Sorry for the off topic grammar question, but am I the only one
       | who finds it confusing how people have started to use plural
       | pronouns to refer to individual people?
        
         | jdashg wrote:
         | It started in the 14th century. Wikipedia has a good article on
         | it: https://en.m.wikipedia.org/wiki/Singular_they
        
       | ChrisMarshallNY wrote:
       | I'm finding this kind of issue coming up a lot with the current
       | abhorrence with polymorphism and inheritance.
       | 
       | I like using interfaces and protocols, but I also still very much
       | use inheritance. It's a fundamental tool that was invented for a
       | reason, and, sometimes, it is the best tool for the task.
       | 
       | I've probably weathered just about every "paradigm shift" that
       | has happened in software development. At one time, using
       | variables with names longer than four characters was considered
       | bad programming.
       | 
       | Anyone remember GOTO?
       | 
       | Some older constructs (like the two above): good riddance.
       | Others...not so much. Structured Programming, which was declared
       | The Mark of Satan, at one time, is still very much the basis for
       | all our work.
       | 
       | I love a lot of the new tools and techniques, but I still mix in
       | a lot of the older stuff when I write software. To some, this is
       | "unclean," because it doesn't tick some arbitrary "buzzwurd _du
       | jour_. "
       | 
       | Simple, solid code is always a great starting place.
       | 
       | The author talks about removing repetitiveness (DRY). I think
       | that's excellent, but, in my experience, I need to be very, very
       | careful when I do that, as the original author may have tweaked
       | just one little line, in one of the clones, and my refactoring
       | may break things; sometimes, not until it's been out to the
       | customers for six months.
       | 
       | That's pretty much _de rigueur_ for any refactoring; not just
       | DRYdock. In my experience, having some robust unit tests and test
       | harnesses in place is absolutely required.
       | 
       | I tend to write code iteratively. I'll start with some naive,
       | sloppy code that works; maybe not well, then refactor it in
       | stages, testing the heck out of it; each time.
       | 
       | I used to work for a Japanese company. I had many differences
       | with my Japanese peers, but they were the most disciplined
       | programmers I've ever encountered. Whenever they would modify
       | code, they would leave the old code in there, but commented out,
       | and add some comments, explaining what their new code does.
       | 
       | Made for some pretty verbose source files, but it was immediately
       | apparent what was done, and why (I think the practice began
       | before most good VCSes were invented). It also gave you the
       | original code to copy and paste, if necessary. Very old-
       | fashioned, but it made their changes (and bugs, therein), easy to
       | understand. It also helped because the code was often stepped on
       | by _many_ programmers.
       | 
       | I'm thinking that a lot of folks are relying on commit comments
       | to explain changes; which is good, but adds extra time to
       | figuring something out.
        
       | solidist wrote:
       | AHA
       | 
       | https://kentcdodds.com/blog/aha-programming
        
       | Traster wrote:
       | I think this is a great post, it covers a topic succinctly and
       | agree with its conclusion.
       | 
       | On the topic of actually refactoring code I think we should
       | consider the code as a variable - that is to say, sometimes these
       | variables just happen to equal each other in which case they are
       | two separate things. Sometimes two variables aren't just equal,
       | but they're the same. That's when to factor out the code.
       | Otherwise the second these two variables are no longer equal you
       | end up in trouble. The secret is divining when something is _for
       | all intents and purposes_ the same as something else in this
       | specific situation.
        
       | boffinism wrote:
       | I think this highlights an important nuance to the Don't Repeat
       | Yourself maxim. It's not just about whether two bits of code are
       | similar now. It's about whether, when they change in future, they
       | are likely to change in the same ways. If not, then DRYing up the
       | code now is only making more work for yourself down the line.
        
         | tudorpavel wrote:
         | DRY is good but like any abstraction it has tradeoffs. It might
         | give you a warm feeling to do the refactor, but you might end
         | up with code that's harder to understand and harder to replace.
        
         | erik_seaberg wrote:
         | I've always found the
         | https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle,
         | where you derive from classes instead of editing them in-place,
         | sort of appealing for this reason.
        
           | terandle wrote:
           | What is this implying? That instead of adding a
           | property/method to a class you should instead create a child
           | class that inherits from the original with the new
           | properties? Sounds like a great way to have a very
           | complicated class hierarchy IMO
        
             | erik_seaberg wrote:
             | Exactly that. Just because _you_ want new behavior doesn 't
             | mean all the _other_ consumers of that class also want it.
             | The old behavior should still exist, and have a name. I 'm
             | not sure whether the idea was ever fully developed into
             | patterns for replacing deep hierarchies with simplified
             | classes that factor out some inheritance from otherwise-
             | unused base classes.
        
       | burlesona wrote:
       | I've usually heard this phenomenon called "incidental
       | duplication," and it's something I find myself teaching junior
       | engineers about quite often.
       | 
       | There are a lot of situations where 3-5 lines of many methods
       | follow basically the same pattern, and it can be aggravating to
       | look at. "Don't repeat yourself!" Right?
       | 
       | So you try to extract that boilerplate into a method, and it's
       | fine until the very next change. Then you need to start passing
       | options and configuration into your helper method... and before
       | long your helper method is extremely difficult to reason about,
       | because it's actually handling a dozen cases that are
       | superficially similar but full of important differences in the
       | details.
       | 
       | I encourage my devs to follow a rule of thumb: don't extract
       | repetitive code right away, try and build the feature you're
       | working on with the duplication in place first. Let the code go
       | through a few evolutions and waves of change. Then one of two
       | things are likely to happen:
       | 
       | (1) you find that the code doesn't look so repetitive anymore,
       | 
       | or, (2) you hit a bug where you needed to make the same change to
       | the boilerplate in six places and you missed one.
       | 
       | In scenario 1, you can sigh and say "yeah it turned out to be
       | incidental duplication, it's not bothering me anymore." In
       | scenario 2, it's probably time for a careful refactoring to pull
       | out the bits that have proven to be identical (and, importantly,
       | _must be_ identical across all of the instances of the code).
        
         | lilyball wrote:
         | I have 2 rules I use when determining whether to duplicate code
         | or to refactor:
         | 
         | 1. How many duplications are there? If the code is duplicated
         | once, that's fine. If it's duplicated twice (so 3 instances of
         | it), then it's time to consider refactoring, subject to the
         | next rule.
         | 
         | 2. Why is the code duplicated? If it's "incidental
         | duplication", i.e. code that happens to look the same, don't
         | refactor. Only refactor if there's actually a reason why the
         | code is the same. Which is to say, attempt to predict the
         | future: if a change is made to one instance of the code, do I
         | expect it to be replicated to the other instances too?
        
         | scarface74 wrote:
         | That can be boiled down to the "Rule of 3".
         | 
         | My CTO often asks me to implement a feature to do X and make it
         | "generic enough to handle future use cases". My answer is
         | always the same - either give me at least three use cases now
         | or I am going to make it work with this one use case. If we
         | have another client that needs the feature in the future then
         | we will revisit it.
         | 
         | Of course, there are some features that we know in advance
         | based on the industry how we can genericize it.
        
           | [deleted]
        
           | rdiddly wrote:
           | "Premature optimization something something..." ;)
        
           | RealDinosaur wrote:
           | I think the catch all term for that is YAGNI.
        
           | specialist wrote:
           | After witnessing the collateral damage of many software reuse
           | projects (anyone remember "components"?), I came up with a
           | different ruleset, useful for "compromising" with "software
           | architects":
           | 
           | First, translate the data.
           | 
           | Second, divine a common format and share the data.
           | 
           | Third, create the libraries for this common format, to be
           | reused amongst projects.
           | 
           | I have never reached #3 in my professional career. Sure, we
           | wrote the libraries. But other teams, projects have never
           | adopted before whole effort became moot.
           | 
           | So I kept my projects in tact and moving forward, while
           | letting mgmt think they're doing something useful.
        
         | daxfohl wrote:
         | I call these "spaghetti abstractions", and they're the worst
         | kind of spaghetti.
        
         | yodsanklai wrote:
         | > Then you need to start passing options and configuration into
         | your helper method... and before long your helper method is
         | extremely difficult to reason about
         | 
         | In which case, you should split the helper function ( extract
         | sub-part common to all cases, and report the differences where
         | the helper function is called).
         | 
         | I think I would most of the time go with de-duplicating as
         | early as possible, as long as the helper function only has few
         | parameters and can be described in plain english rather easily.
         | 
         | To me the cost of having to refactor the helper function later
         | in the process is less than dealing with duplicated code.
         | 
         | Duplicated code causes many issues. You mentioned introducing
         | bugs, but it also makes the code harder to read. Every person
         | who reads the code has to make the de-duplication effort
         | mentally (check that the duplicated parts are indeed
         | duplicated, figure out what they do, and on what parameters
         | they differ...).
        
           | specialist wrote:
           | Upvoted. We'd probably come up with different
           | implementations, I strongly prefer composition and
           | "interpreter" style code, but whenever I've seen casual
           | mutations in different dataflows, it was because of doing one
           | off changes while ignoring the whole.
        
           | barrkel wrote:
           | Premature optimization. Duplicated code is only evil when
           | there's a bug you only fix in one place and forget about the
           | duplicates; in almost every other case, it's easier to reason
           | about and is more resilient in the face of local changes.
           | 
           | Abstraction is often like compression, and compressed data is
           | easier to corrupt. Change the implementation of an
           | abstraction, and you put all consumers of it at risk. It's
           | not an absolute good.
        
             | yodsanklai wrote:
             | > it's easier to reason about
             | 
             | Consider you have 4 times a block of 10 lines of code, they
             | are identical except for a couple of parameters. The person
             | who reads the code has to 1. figure out what the code does
             | 2. see if the duplicated parts differ in some subtle way.
             | 
             | The alternative is to replace the duplicated parts with a
             | function that has a meaningful name. This makes the code
             | easier to read. It's not a premature optimization. It would
             | make sense to keep it duplicated if you're in an
             | explorative phase and not sure yet what the final design
             | will be, but I wouldn't submit a patch where parts are
             | obviously similar. I'm not sure it would pass review.
        
         | mfateev wrote:
         | Go error handling is a good example of this. So far all the
         | attempts to reduce the repetitive `if err != nil { ... }`
         | through some abstraction failed. Look at
         | https://github.com/golang/go/issues/32825
        
           | renox wrote:
           | In the language maybe but both Rust and Zig show that it's
           | possible to have much less 'bloat' for error handling even
           | without using exceptions.
           | 
           | I'd say that go designers have still work to do: Zig
           | especially show that you can be a 'simple' language and yet
           | have both sane error handling and generics.
        
         | m0zg wrote:
         | And a rule for Java programmers as well: nobody is going to
         | "extend" your program. If your interface has only one
         | implementation, you do not need the interface at that time, and
         | possibly ever. Nor do you need DI or whatever other
         | masturbation "best practices" Java gurus prescribe. When it
         | comes down to it, Java is a simple, pleasant language. So
         | people invent all sorts of indirection to appear smart. Don't.
         | Just do it simply and readably, with as little indirection and
         | abstraction as possible.
        
         | detaro wrote:
         | And in the other direction, when adding flags etc to a method
         | that was created to reduce duplication, consider if splitting
         | it into two "duplicate" copies or copy it to the call-site
         | requiring the flag isn't the better alternative.
        
           | danabramov wrote:
           | Yes. If extracting and deduplicating is in your toolbox, so
           | should be inlining and duplicating.
        
         | konschubert wrote:
         | you can also try to reason about the situation to figure out if
         | the duplication is incidental or inherent.
        
       | crazy5sheep wrote:
       | I don't agree the issues OP later discovered has anything related
       | to `refactoring` itself, but more a issue of premature
       | optimization.
       | 
       | my 2 cents, an interface is defined, it shall not be modified for
       | no good reason. Even if you do, you can still have some way to
       | make sure it can be compatible with the original system. and I
       | don't believe you can't extract some common behaviors of those
       | repeated code, and use them within the interface, refactoring
       | doesn't mean you have to rewrite the whole project, it can be
       | done by piece by piece. reducing a line of duplicated code can
       | save you a lot of efforts on maintaining the project in its life-
       | cycle. a lot of times, I have seen a code change was made to fix
       | some bugs were forgotten in other place which duplicated the same
       | original code.
        
       | whoisjuan wrote:
       | If there's something that I have learned about refactoring code
       | that is repetitive into "cleaner" shorter code, is that the
       | refactored version looks better but it's way harder to
       | understand. When other people try to look at the "cleaner"
       | version they have to spend more time trying to understand it and
       | mentally untangle the abstraction.
       | 
       | I like syntactically shortcode as long as it's clear. I also
       | understand that sometimes shorter code has some small performance
       | advantages that can add up in languages like JavaScript where the
       | size of the files can become a loading speed bottleneck.
       | 
       | But to be honest it really bothers me when someone tries to make
       | perfectly fine and readable code into something different just to
       | satisfy some weird intellectual urge to make things more
       | abstract.
       | 
       | Sometimes long code is not only easier to read and understand,
       | but it also helps to create a better technical outline of
       | decisions that otherwise will get lost in the reasoning of
       | whoever is writing that code.
        
       | mattacular wrote:
       | "First you learn the value of abstraction, then you learn the
       | cost of abstraction, then you're ready to engineer"
        
       | temac wrote:
       | > A healthy engineering team is constantly building trust.
       | Rewriting your teammate's code without a discussion is a huge
       | blow to your ability to effectively collaborate on a codebase
       | together.
       | 
       | I'm against the idea that people should be attached to "their"
       | code (that is: the code they wrote). Now I _also_ understand that
       | humans that humans, but the priority should be to make them
       | evolve toward more detachment from their work and acceptance that
       | what they design  "can" (actually will) be imperfect, rather than
       | avoiding upsetting them even when it would not be justified to be
       | upset. Plus one essential purpose of source control is to be able
       | to make changes, and revert them if they were "wrong"; or for any
       | other purpose. Maybe propose a patch instead of committing
       | directly, but that's really a cultural matter about how projects
       | are organized.
       | 
       | I don't want to ask of permission for an improvement. If there is
       | a need to have formal authorization of maintainers responsible
       | for parts of the code, they setup just that. Otherwise, I'm
       | certainly going to improve "your" code, _in some rare cases_
       | without even telling you (that 's not a goal in itself to do it
       | behind your back, obviously, and I also value collaboration --
       | but that should not be a problem). The question that remains is:
       | is it really an improvement. If you are not sure, then maybe
       | don't commit. If you are, do it (following your local rules), and
       | if it ends up being a mistake, yes, it will be reverted, and so
       | what?
       | 
       | You should not take issue of your work being reverted (for good
       | reasons), like other people should not take issue of "their" code
       | being modified. Better ask for forgiveness than permission.
       | 
       | > For example, we later needed many special cases and behaviors
       | for different handles on different shapes. My abstraction would
       | have to become several times more convoluted to afford that,
       | whereas with the original "messy" version such changes stayed
       | easy as cake.
       | 
       | Then re-expand the code later.
        
         | tcbawo wrote:
         | The quality of a team is the quality of the communication. If
         | the architecture and design isn't well communicated, you get
         | people going off in the wrong direction, or polluting a clean
         | design. Also, people are most attached to their code based on
         | their time investment. If you trash someone's code/changes, you
         | trash their time, which could have been more efficiently
         | decided with a conversation ahead of time. If you find yourself
         | surprised by design changes, find design flaws in a code
         | review, or have different definitions of "improvement", the
         | communication in your company may be lacking.
        
         | yxhuvud wrote:
         | You want trust, but you also want code review. The example
         | lacked both.
        
         | the_unproven wrote:
         | I also think it's fine to change the code someone wrote. Just
         | because someone wrote it, doesn't mean it's the right way to do
         | it. I often find myself rewriting the code, it's the natural
         | process of code evolution. It just feels that it should be more
         | readable, efficient etc.
         | 
         | Although, if the change is essential or it requires more pair
         | of eyes, I'll just make a PR(MR) and let the people review it.
        
         | mannykannot wrote:
         | There is a delicate balance: a sense of ownership can encourage
         | pride and responsibility, but it can also impede cooperation.
         | 
         | > Better ask for forgiveness than permission.
         | 
         | Not in this case; you are likely to piss people off, especially
         | if there is a consequence you have overlooked.
        
         | skybrian wrote:
         | In an environment where all code must be reviewed, when you
         | make a change like this you send it to the original owner for
         | review. Or at least someone on the same team, if they're not
         | available.
         | 
         | "Don't be too attached to your code" means trying to review
         | improvements to the code you just wrote objectively. Can you
         | accept changes with good grace?
         | 
         | But you can't get to the point where you have a smooth-working
         | team if you have philosophical differences about what
         | improvement looks like! If one person's improvement is another
         | person's regression then those difference need to be worked out
         | and some kind of synthesis agreed to. This can take a lot of
         | time, but it's necessary work to get to that ideal.
         | 
         | On the other hand, a lot of work gets done by teams that are
         | _not_ smooth-running teams that are in philosophical agreement.
         | It may even be a good thing to have a diversity of opinion and
         | avoid group-think? You have to be able to accept some messiness
         | though.
        
         | danabramov wrote:
         | I think there's a balance. There's a difference between
         | gradually improving something, or improving it at some point
         | later -- and literally rewriting 100% of code someone has just
         | landed over the night.
        
           | slavik81 wrote:
           | I agree with you. To me, the action felt wrong when he
           | described it. I wasn't sure why at first, but I think perhaps
           | because the work was not in service to any actual task.
           | 
           | If he was in charge of writing the next piece of
           | functionality for that code, it would be poor teamwork to
           | completely refactor it without discussing the reasons for the
           | design, but at least it would have been within his area of
           | responsibility.
           | 
           | This is also the reason why I like having code review. The
           | review would have been a good place to raise his concerns.
           | They could have had their eventual conversion earlier, before
           | feelings were hurt or wasted efforts were made. It would even
           | help in the opposite case, where the author's code was
           | legitimately poor and the reviewer had good suggestions.
           | 
           | It's not a panacea, but I find code review helpful. In my
           | experience, review was the time when a lot of knowledge-
           | sharing occurred. Some might feel that only senior developers
           | should review, but as a junior I learned a lot about why the
           | author made the choices they did. I learned how people
           | expected the code to change, about language features or
           | pitfalls, etc., and it helped me grow as a developer.
        
         | rubatuga wrote:
         | I mean, it's nice to talk about ideals, but it's also highly
         | unrealistic that people are able to separate the code they
         | write and what is says about them. Especially if you are part
         | of a newly formed team, you must make sure that there is trust,
         | respect, and clear communication, because this is the stage
         | where most misconceptions occur. Upon building a successful
         | foundation, you can test new team dynamics such as changes in
         | communication that tradeoff that initial safety for more
         | efficiency.
        
       | pier25 wrote:
       | Principles are not rules. Also, maintainable and readable code
       | are of uttermost importance.
        
       | rlonn wrote:
       | Have to push this fantastic article again - if you read it and
       | follow what it says you won't make these mistakes:
       | https://programmingisterrible.com/post/139222674273/write-co...
        
       | boyadjian wrote:
       | I totally agree on this post. Being too zealous about code
       | duplication is counter-productive. Don't be more royalist than
       | the king.
        
       | zallarak wrote:
       | As PG said, take on as much technical debt as possible: it's
       | literally leverage.
       | 
       | Now sometimes "clean" code is the worst of both worlds. It wastes
       | time and isn't really clean.
        
       | aazaa wrote:
       | > ... My code traded the ability to change requirements for
       | reduced duplication, and it was not a good trade. For example, we
       | later needed many special cases and behaviors for different
       | handles on different shapes. My abstraction would have to become
       | several times more convoluted to afford that, whereas with the
       | original "messy" version such changes stayed easy as cake.
       | 
       | The article's starting example and revision clearly illustrate
       | how the original code was changed. Duplication was removed - just
       | like so many advocate for.
       | 
       | Unfortunately, the article doesn't state the changed requirement
       | that broke the new design, leaving that to the reader's
       | imagination. And I can imagine cases in which the revised code
       | would be superior to the original.
       | 
       | It sounds like the problem arose from the need for specialized
       | handles on different shapes. If so, I don't see how using various
       | createXHandle functions (where "X" is an identifier associated
       | with a specialized handle) would necessarily cause convolution.
       | It could become quite convoluted if not done with care. For
       | example, keep the createHandle method, but pass customization
       | parameters to it. But that's really the naive way to go.
       | 
       | What we'd be faced with is nothing more than the kind of
       | specialization requirement we usually see with Object Oriented
       | programming. We can use composition over inheritance to great
       | effect there. We can extend the author's refactored design and
       | end up with something clean and maintainable.
        
       | cmdshiftf4 wrote:
       | So the two cases against writing the most legible, succinct code
       | _given the specifications at the time of writing it_ are:
       | 
       | >Firstly, I didn't talk to the person who wrote it. I rewrote the
       | code and checked it in without their input. Even if it was an
       | improvement (which I don't believe anymore), this is a terrible
       | way to go about it. A healthy engineering team is constantly
       | building trust. Rewriting your teammate's code without a
       | discussion is a huge blow to your ability to effectively
       | collaborate on a codebase together.
       | 
       | There's no question about this. Nobody likes the self-proclaimed
       | savant who works in isolation and makes sweeping changes to the
       | codebase or other people's work without collaborating and gaining
       | some consensus. If it's a change worth making it should be a
       | simple case to present to your (hopefully) equally intelligent
       | team.
       | 
       | There is a difference, it has to be highlighted, between
       | refactoring someone's code in order to extend it yourself and
       | simply re-writing someone's implementation because it doesn't
       | suit your requirements. The former is part of the job, the latter
       | should at the very least be an opportunity to mentor the person's
       | whose code you want to re-write in _why_ it was suboptimal and
       | guide them on the changes you 'd like to make, or even give them
       | the chance to make it themselves. This is kind of what code
       | reviews are supposed to do.
       | 
       | That does not negate the need to structure and optimize code to
       | remove duplication whatsoever. It's not an argument against clean
       | code standards and it's weak that it amounts to 50% of his case
       | here.
       | 
       | >Secondly, nothing is free. My code traded the ability to change
       | requirements for reduced duplication, and it was not a good
       | trade. For example, we later needed many special cases and
       | behaviors for different handles on different shapes. My
       | abstraction would have to become several times more convoluted to
       | afford that, whereas with the original "messy" version such
       | changes stayed easy as cake.
       | 
       | Time changes, requirements change. It's part and parcel of our
       | jobs in software development. Writing code that at one point is
       | optimal and most legible for the cases present should also be
       | done to try to make it refactorable and extendable.
       | 
       | It is much easier to refactor and extend code that isn't riddled
       | with duplication and mangled with hardcoded business logic.
       | Abstract your code and write your implementations well, name
       | things in a way that people can read it and write tests that
       | describe what's expected from it.
       | 
       | Refactoring well isn't easy work. Refactoring a sprawling legacy
       | codebase with a lot of duplication and legibility problems is
       | _significantly_ worse.
       | 
       | I'm not saying we need to be dogmatic here. If you're given the
       | opportunity to develop new code you should be aiming to do the
       | best job of it given what you know _now_ , in a way that will be
       | comprehensible to you, or whoever needs to touch that code
       | _next_.
       | 
       | We all know that there are problems with premature optimization
       | caused by "best practices" evangelists who'd happily drive up
       | time-to-market and operating costs/complexity exponentially in
       | the name of having the codebase and applications / services
       | architecture in line with whatever he or she has read lately from
       | "thought leaders" in our industry, but writing the code for a
       | given application in line with the above isn't one of them.
        
         | scarface74 wrote:
         | _It is much easier to refactor and extend code that isn 't
         | riddled with duplication and mangled with hardcoded business
         | logic. Abstract your code and write your implementations well,
         | name things in a way that people can read it and write tests
         | that describe what's expected from it._
         | 
         | Especially in a statically compiled language - "extract
         | method", "extract class", "pull members up", etc. is an
         | automated, guaranteed safe refactor (ignoring reflection) .
        
         | mntmoss wrote:
         | The code is not large enough to need maintenance at a fine-
         | grained level.
         | 
         | There is a secondary rule to the DRY "rule of three": If I can
         | blow it away and rewrite it so easily, there is nothing to
         | reuse or refactor in it. The feature is done, and we are into
         | code golf and speculation, neither of which are productive uses
         | of time. In my experience the success rate of speculative
         | refactors like the one author made has perhaps a 50/50 chance,
         | so no better than the initial strategy. It's the requirements
         | themselves and the application of techniques to avoid various
         | classes of errors that give code direction and structure - not
         | the aesthetics at a moment in time(which is what author took
         | issue with).
         | 
         | If you spot multiple approaches on the first try, you can add a
         | comment with a date outlining alternatives so that the
         | conversation may be resumed later when the new requirements
         | come in. But at all times you're always at the mercy of
         | "discipline", and there's no preemptive measure that avoids
         | that.
        
           | Rapzid wrote:
           | The author also didn't sound like a particularly senior
           | engineer at the time for many reasons. So the original author
           | and the "boss" may have been taking into consideration
           | timelines and future work/requirements coming down the pipe.
           | 
           | A very valid reason could have been as simple as "We are re-
           | visiting this in a couple sprints after feedback and will
           | have a better idea of how it needs to change. The extra day
           | spent on this wasn't worth pushing getting it into peoples
           | hands, and we don't know if it would be a waste." The author
           | would have known this if he started a conversation about it.
        
       ___________________________________________________________________
       (page generated 2020-01-11 23:00 UTC)