15 ms·
Goodbye, clean code (2020)
- kstenerud 3y agoYou could have just moved the repetitive math into separate functions and called them from the resize functions. The resize functions themselves only looked repetitive because they were forming an interface, which is why refactoring them away was wrong. But the math they performed is a perfectly valid target for cleaning the code.
- Tade0 3y agoExactly. Seems like the obvious way to go and this is what I typically do. The end result is of course a huge bag of small, pure functions, but they're easy to test and refactor so it's never an issue.
- gpderetta 3y agoAnd you can re-inline and modify the special cases in the future if necessary.
- mattkenefick 3y agoEspecially since it was a refactoring, it's generally better to handle those in stages if you're working with a team. There are lot of ways/patterns for solving the same problem... but tearing apart an existing interface being used by others isn't a good start. The best part about abstraction is that you can modify the underpinnings to be more flexible without hurting the rest. A good step would be to create more flexible math functions underneath, like you're saying, and leave the rest alone. Afterwards, there can be deeper conversations with the team about how they want the interfaces to communicate to provide an obvious facade but an abstract implementation.
- raverbashing 3y agoYup I feel that Clean Code and Uncle Bob is like modern tiktok influencer hustlers. It's feel good whishy-washy crap that has some amount of truth but in the end it ends up being very non-productive Not to mention UB was all butthurt the other day when people found out a conference he was invited to had fake speakers in its lineup. But hey, I guess it takes one to defend one.
- JaDogg 3y agommm.. this is an interesting take. I have been a zealot of sort in the past (intern/junior time), but now coming to same conclusions about these cargo cults.
- teddyh 3y ago> UB was all butthurt the other day when people found out a conference he was invited to had fake speakers in its lineup. But hey, I guess it takes one to defend one. Firstly, what does this have to do with clean code? Secondly, “butthurt” is not a word I feel correctly expresses his comments. From what I can tell, he advocated for a skeptical and cautious approach, and wanted due process to take its course instead of mob justice to run with the first impression, as it always does. <https://x.com/unclebobmartin/status/1729465103781695982 https://x.com/unclebobmartin/status/1729465103781695982>
- raverbashing 3y agoThanks for the link, you scroll down and see the rebuttal by Gergely > Confirmed speakers at DevTernity 2021, 2022 and 2023 and JDKon 2024 do not exist. There were & are no such engineers at Coinbase or Meta. > I shared this fact and said no conference should list fake speakers. There is no "crime" there per se, having a fake speaker in your lineup is a doozy, but it's different from, let's say, saying Bill Gates (with his picture) will be at your conference with no attempt of doing so. Now I do think the reasons listed by the conference organizer are feeble at best, but (moderately) plausible. I'd never put a placeholder saying so and so are "Engineer at Coinbase" and giving them fake names/pictures
- teddyh 3y agoA reasonable rebuttal. But how are his original comments therefore “butthurt”? This was what I was arguing against, remember? You seem to be making the same misinterpretation of my comment as people in that thread; simply because some comment is not 100% supportive of one side, you think it must therefore be defending the other side. He expressed concern that mob justice was being perpetrated rashly, and people are interpreting that as support for the other side. Similarly, I was arguing against your categorization of his argument as being “butthurt”, and you immediately think that I am supporting the other side of the argument, and therefore present me with rebuttals to that argument, instead of what I actually wrote.
- parasti 3y ago(2020)
- kubb 3y agoI feel like what you’re describing is bad abstraction. This is the real issue, people designing things off two or three examples, not making sure that what they have is general enough to accommodate future usage.
- jackblemming 3y agoThis is completely right. People read about design patterns or DRY, usually apply them wrong since they're still learning... and then act like it's the source materials fault?
- hardware2win 3y agoWell, it kinda is? Teaching materials should show how to not refactor too. Also have u seen refactors in clean code? Guy refactors thread safe code by introducing static variables which make code not thread safe, but hey! At least it is a little bit shorter!
- ajuc 3y agoYup this is the worst part of Clean Code. I've seen real-life bugs caused by this kind of refactoring. The best part is that the same commit added unit tests so our coverage grew over the magic 80% bar, but of course unit tests don't usually test for race conditions.
- resonious 3y agoIf there is a source material that many people are "applying wrong", then I'd question the quality of that source material.
- sime2009 3y agoDesign patterns, for example, really should only be studied once you have quite a bit of experience with complex code bases under your belt. You need to have done battle with some nasty code problems in bigger code bases before you really understand the problems design patterns are trying to solve. Inexperienced developers can't be trusted to apply them because they don't have that judgement. It just looks like a shiny thing.
- atoav 3y agoClean code is bullshit. Don't get me wrong: I like to have beautiful and clean code very much. But code has to be maintainable, performant, reliable, communicative, adaptive and all kind of other things before it has to be clean. If your clean code hurts those, you made the code worse. Sometimes you will just have to accept that things take the number of lines they do and having them duplicate in different places is a feature as you (or someone else) might have the reasonable desire to change the individual parts. Whenever your sense of aesthetics overrides practical concerns you should pause and take a step back.
- cultureswitch 3y ago> Sometimes you will just have to accept that things take the number of lines they do and having them duplicate in different places is a feature as you (or someone else) might have the reasonable desire to change the individual parts. The trick is always to figure out whether you are in that case or whether you are in the case where someone will want to change the shared logic everywhere at once. In my experience, the latter is vastly more common, and this is what DRY optimizes for.
- atoav 3y agoThat is true, but this is not case in the example. DRY is often a good choice, but you can also use it to make logic shared that very likely never should have been shared. Untying that knot later on can become very hard compared to code where someone just had repeated themselves. So no DRY is better than wrong DRY, but well applied DRY is of course better still (depending an what we are optimizing for).
- antman 3y agoPrevious https://news.ycombinator.com/item?id=29239861 https://news.ycombinator.com/item?id=29239861 212comments https://news.ycombinator.com/item?id=22022466 https://news.ycombinator.com/item?id=22022466 575 comments
- dang 3y agoThanks! Macroexpanded: Goodbye, Clean Code (2020) - https://news.ycombinator.com/item?id=38366222 https://news.ycombinator.com/item?id=38366222 - Nov 2023 (1 comment) Goodbye, Clean Code (2020) - https://news.ycombinator.com/item?id=29239861 https://news.ycombinator.com/item?id=29239861 - Nov 2021 (212 comments) Goodbye, Clean Code - https://news.ycombinator.com/item?id=22022466 https://news.ycombinator.com/item?id=22022466 - Jan 2020 (575 comments)
- hiAndrewQuinn 3y agoPart of the reason I enjoy languages like Haskell is because of the abstraction maximalism enshrined at the language level, rather than the coding level. We all agree on what an Applicative is supposed to do. The challenge shifts right in the idea-to-code pipeline to finding the right Applicative for the problem. Most OO design patterns have natural, well defined equivalents in such an environment, but the difference is this way helps minimize the amount of project specific abstractions you have to deal with. The downside as a beginner is of course a greater upfront cost to learning the language, and quite frequently opening up another Haskeller's work and realizing there are like 12 compiler extensions you've never heard of that you now need to grok. But even there I would argue that's a net win: you can carry those compiler extensions with you to all projects in the future. (The downside as an expert is realizing you have to get a PhD to get a sense for how much RAM your cats will gobble up!)
- pluto_modadic 3y agooh, oh my. The golang opposite where you don't have language extensions and should be able to grok everything about the language in your head all at once... yeah I'm going with "simpler language".
- hiAndrewQuinn 3y agoI'm not dissing Golang, I use it actively, both at work and in my own projects. There's a lot to like about it. There's also a lot to like about Haskell. Complaining about something which you don't understand isn't a good look on anyone, though.
- Dylan16807 3y agoCould you please address the tradeoff if you're going to post on the issue, and not a specific bullet point? How do you feel about the increase in project-specific abstractions in Go? Or do you disagree with that framing?
- tejinderss 3y ago> The downside as an expert is realizing you have to get a PhD to get a sense for how much RAM your cats will gobble up. Go one step further with affine types and use Rust. You get haskell type system with predictable performance.
- bionsystem 3y agoOn another note, props for the writer to : - actually write a story relevant to the lesson learned, and not make up some fable that takes 1/3 of the article before even starting to make a point - not have any sort of popups asking me to subscribe or login - not have any sort of annoying javascript animation that gets in the way of reading the article it's rare enough to be noted.
- abdellah123 3y agoThe most "surprising" thing about both clean and unclean code ... is that they DON'T USE CLASSES. > Use the platform, use JavaScript !!
- janosdebugs 3y agoI found that the best use case for classes is dependency injection. Have a constructor, inject your dependencies, then use them in one or more functions. However, you can do the same with functions: function new_foo(dependency) { return function(bar) { // Do something here } }
- Gepsens 3y agoHow is your refactoring clean ? Lmao if this is clean code I'm the Queen of england...
- hardware2win 3y agoThe thing is, majority of ppl cannot evaluate this too and we end up with code with clean code ^tm traits that sucks
- flohofwoe 3y agoEverybody has different taste and opinions what "clean code" is supposed to look like (best example of this is "for-loops" vs .map()" - IMHO nested loops are usually more readable than a function chain which does the same, but other people have the opposite opinion). IMHO the core problem of the situation described in the article is that the guy simply rewrote a piece of code without before talking to the author/maintainer/owner of that piece code.
- seattle_spring 3y agoCan you share how you would clean it up?
- zelphirkalt 3y ago> My boss invited me for a one-on-one chat where they politely asked me to revert my change. I was aghast. The old code was a mess, and mine was clean! Sounds like a weird thing, if not toxic, of the boss to do. Is the boss a developer? Then why are they the boss and not an equal? Are they in a managing position? Then why do they get involved with the developer's work? Don't they trust their own employee? I could imagine it maybe, if they were a business of 10 people. Or perhaps the title "boss" is wrong and they meant senior and they themselves being junior dev or so. Otherwise it is really weird and the boss should get out of their face and let them do their job.
- oytis 3y agoOr maybe the whole story is made up.
- Kiro 3y agoI've never had a boss who couldn't code. Very strange thing to rant about.
- oytis 3y agoEven if they can it doesn't mean they should. People managers should manage people and let engineers engineer. Even if they are former engineers themselves
- concordDance 3y agoIt's possible the colleague expressed they were upset to the boss.
- lmpdev 3y agoMy father was a magazine editor in the 1980s. Paragraphs for his publications had to be short due to the limitations of magazine layouts. “For the bulk of your work, a paragraph can only be one or two perfectly written sentences” he insisted. I feel like there’s a parallel from that to writing functions. Magazine readers, and programmers both read high density text rather quickly. We should make it easier for future readers to quickly understand your point/function. We should write short, correct functions. Only add abstraction when you absolutely have to and write more documentation in the case that you do. Edit: missed the length of the function comment, ignore my diatribe
- camillomiller 3y agoHow is this positive? Respect the limitations imposed by a framework or structure instead of thinking how that could be improved? Conciseness is a value if it helps the communication and understanding, but it’s not an absolute value. And that is true for code, as the post explains quite well.
- albertzeyer 3y agoBut the point here in the article is actually that the longer code was better than the shorter code.
- ranting-moth 3y agoThis is equally as much about not being a besserwisser. You get a PR to review and you rewrite the code without talking about it? Yes, that's a besserwisser.
- noduerme 3y agoYou're wrong, your initial corrections were correct. Your boss will now have to spend 4x as much money to modify every class that ever relied on Ovals and Rectangles if/when he realizes there's another way he might want to modify them.
- vorticalbox 3y agowhat if you want to process different things for each type of shape? then you will have to refactor it all out again. there is a talk by James Power [0] during which it he speaks about whether the repetition is intention or coincidental. [0] https://www.youtube.com/watch?v=-z2eqLwVmzw https://www.youtube.com/watch?v=-z2eqLwVmzw
- cogman10 3y agoYou didn't catch the end where they explicitly say > 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. Clean code is easy to understand and to change. Ideally, any given file or method only deals with one concept. Messy code usually results from someone merging concepts to avoid duplication. After that happens, differences in the concepts cause the code to become much harder to reason about. I've seen this particular problem happen a million times. The worst code I ever stepped into was completely DRY. When, where, and why something happened wasn't something the original authors could answer. That's because everytime they found code duplication, they'd abstract. And everytime that didn't work, that ended up adding little "if (this instanceof Foo) special case;" to get over the most recent bug.
- seattle_spring 3y agoJust curious, what does your software engineering career look like? Length, education, etc.
- noduerme 3y ago
- olivermuty 3y agoI was expecting this to be a rant against Uncle Bob for his weird comments around the fake women speakers at the tech conference. Very different, but also informative :)
- azangru 3y ago> I was expecting this to be a rant against Uncle Bob for his weird comments around the fake women speakers at the tech conference. It would have been very unfortunate if it were. If an article, entitled "Goodbye, Clean Code", had been written in response to Uncle Bob's twitter life, what it would have demonstrated would be that the author thinks that people with bad opinions have nothing of value to teach about their area of expertise. Too common a position these days.
- rzmmm 3y agoIf someone is interested in further contemplation around this, I highly recommend the book "A philosophy of software design" by John Ousterhout. In my opinion, it gives good reasoning why clean code is sometimes praised and sometimes criticised like it is here. I highly agree with Ousterhout that software complexity is mostly caused by obscurity and (cognitive) dependencies within abstractions. With that in mind its easier to see why Dan failed to improve the code here.
- deafpolygon 3y ago[dead]
- ludovicianul 3y ago> Firstly, I didn’t talk to the person who wrote it. This might be an issue in itself sometimes. People identifying with the code they wrote. When you are part of the team, the code belongs to everyone. Everyone should be able to change it if it makes sense and all quality gates are passing.
- solraph 3y ago> When you are part of the team, the code belongs to everyone. Everyone should be able to change it if it makes sense and all quality gates are passing. Yes, but actually no. Context is important here. If that code had been written six months ago or even a couple of weeks ago? Have at it. But, the OP states "My colleague has just checked in the code that they’ve been writing all week." then "It was already late at night (I got carried away)." If spent all week on something, working out the all the details, checked it in at 5pm, and then came in the next morning to discover that someone stayed up rewriting it rather than waiting till the next morning to talk to me about it first, I'd be absolutely livid.
- ludovicianul 3y agoIndeed, context is very important. But also how people identify with the code they produce.
- yungporko 3y agosure everyone should be able to change the code, but somebody is immediately refactoring new code to align with their own opinions and making it worse in the process is not ok. i would immediately revert the commit if somebody did that to me (and then tell them why of course)
- gardenhedge 3y agoDid that to _you_ or did that to the shared code? I think that is the point being made.
- 3y ago
- davnicwil 3y agoIn all the things I've ever built I'm not sure I can remember a time where changing the same thing in a few places was all that time consuming. I can remember lots of times where debugging an abstraction was very time consuming, though.
- lakpan 3y agoThe changing part is not time consuming, is having to fix the same bug over and over because you didn’t realize this same function was copy-pasted in 7 different files. It really gets worse when you realize this a year after the first bugfix, still dealing with a stupid bug you fixed a year prior, if it wasn’t for copy-pasted code. I’m also against DRYing up unnecessarily, but if the code is a 100% match in intention and/ord behavior, then it’s going to be deleted.
- davnicwil 3y agojust to challenge that, why would you not realise the function is copy pasted in this scenario? I mean, you'd see that the function is inlined in the place that you discover the bug, so you already know that changing that function's code isn't going to fix similar bugs anywhere else right?
- cultureswitch 3y agoHow do you know where the function has been copy pasted? How do you know whether it has been copy pasted in the first place? The bug may be latent, hard to find, or express itself very differently in different places. It is in fact, a different bug if it originates from code in a different place, even if the code is largely identical.
- lakpan 3y agoThe example in the linked blog is easy to detect, but often duplicate code exists across files, often unrelated. Just today I deleted several React components that literally only varied by name and were intentionally copy-pasted. I only realized because I the one I edited was imported by the same file as others.
- d--b 3y agoWhy is everyone stating what he should have done instead? This is a perfectly legitimate lesson. In finance, we are constantly dealing with products which are somewhat alike but not quite. Equity options vs Fx options ? Sure, they're options, they have a strike, we price them using some version of Black Scholes, etc. But oh boy they are so different. The temptation for new joiners to factorize a lot of behaviors is huge, and many times we are in the shoes of the OP's boss, telling the younger devs to remain calm and keep things separate. It's not about saying goodbye to clean code, it's about actually maintaining a clean code by not overabstracting.
- lifthrasiir 3y ago> It's not about saying goodbye to clean code, it's about actually maintaining a clean code by not overabstracting. But the title says so! :p I get the whole point of this post, but it can easily be read as an excuse to actually messy (as opposed to "non-clean") code. The author doesn't actively distinguish them, so others do.
- ReleaseCandidat 3y ago> Why is everyone stating what he should have done instead? ... In finance, we are constantly dealing with products which are somewhat alike but not quite. Yes, but we are talking about geometry. What the (usual) handles do are affine transformations (translation, rotation, scaling and mirroring), if the scaling is uniform, these are similarity transformations. And are guaranteed to work for any shape. Which leads to the real problem: you can't (well, shouldn't) abstract something, if you don't have enough knowledge about that - especially what new possibilities may show up in the future. For example if somebody thinks that the only possible ovals are circles and ellipses, they will be quite surprised when the first "real" oval shows up.
- marcosdumay 3y agoWhat goes back into finance, because rewriting a Black Scholes predictor every time one instrument needs it would be insane. And yet, it's what this code seems to do.
- 3y ago
- albertzeyer 3y agoI think I went into the same trap as well quite often. And then I exactly ended up with the problems as they are described, i.e. adding further special cases becomes really complicated and convoluted in my abstraction. But I really find this difficult. How to decide what abstraction is ok and which is not? Since I did this mistake a few times, I now sometimes tend to try to think a lot about this, which slows me down a lot, and in the end, I still not really sure whether I made the right decisions. Any suggestions how to decide such things? See also John Carmack about code duplication: http://number-none.com/blow/blog/programming/2014/09/26/carmack-on-inlined-code.html http://number-none.com/blow/blog/programming/2014/09/26/carm... I have read much advice on this topic, but still, I think I often struggle to make the right abstractions.
- paweladamczuk 3y agoI think it's so specific to a given codebase that it's hard to give advice that generalizes well. I have the same feelings as you here, I often feel a little lost trying to decide how much duplication is appropriate in a given case. I try to not overthink it in the difficult cases. There are many other places in code where it's more obvious, because you can see the history of how people worked with the code, what was the frequency of changes and edge cases added to it etc. Often it's also just about the readability of the code, I tend to go by the "how confusing it will be for the next person if I defuplicate this code in a smart way" metric.
- _aqmj 3y agoThe problem with these kinds of articles is that they disprove an idea but leave you without any concrete guidance on what you should do instead. Yes, abstractions could become obsolete because we didn't foresee the future (rightfully so), but what would you do instead? At any point in time, you have a limited amount of information and you should come up with the least stupid code that you can. Overdoing abstractions almost always leads to this terrible result, but you can't just call it "goodbye clean code", this is more of a marketing post than an actual useful informative one.
- IshKebab 3y agoThe thing to do instead is to keep the code simple and concrete, even if it is duplicated a bit. I think maybe what you mean is it doesn't give you any guidance on when to do that, other than "sometimes". That's just a matter of taste and experience. It depends on the specific code and circumstances.
- bigtunacan 3y agoThe long answer is a bit complicated, but the short answer is you should duplicate code. It is far less work to dedupe WET and abstract later once you truly understand the correct abstraction than it is to try to untangle the wrong abstraction later. Or as Sandi Metz would say, "Duplication is far cheaper than the wrong abstraction."
- TheCapeGreek 3y agoDoes every post need to propose a new One True Way? Letting go of the Old Way is just as valuable without having a preferred replacement. It's similar to the bell curve meme about any niche/skill. A beginner only focuses on the fundamentals, a "mid-level" focuses on all the best tools & methodologies (to the point of overcomplicating things), and the master only focuses on the fundamentals.
- DeathArrow 3y agoI don't care about clean code. I care about readable code, easy to change code, efficient code. Of course, I applaud the virtues of OOP, SOLID, design patterns if I sense an interviewer is an Uncle Bob disciple. But I try to steer clear of Uncle Bob disciples, as I don't like living in the kingdom of nouns. [0] [0] https://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html https://steve-yegge.blogspot.com/2006/03/execution-in-kingdo...
- cobertos 3y agoI've written this pattern 10s of times now. There's a lot of ways to get it wrong according to my normal[0] but going and doing something weird in the "boring" interaction handler code usually burns me. I'd argue for "cleaner" code here. Every code base has it's tradeoffs, though. But I don't think the conclusion should be "goodbye, clean code". Clean code is a goal for maintainable code; code bases you expect to last >1 year. If your goal is to iterate fast then you shouldn't be looking for maintainable code. And that's perfectly fine! Just don't be surprised when your <1 month code lives >1 year and you're sad. [0]: My "normal" is to abstract as much of the math as possible to Math-only objects (working with "Box", "Rect", etc type math classes) which makes rigorous unit testing easy. Writing all the math _once_ in an update handler and call from start/move/end/whatever depending on the context and how much info you have. It's the easy to draw all the graphics based on your math objects that are now up to date, however that needs to be done.
- jaza 3y agoTests! Tests! Tests! If the author had written thorough unit tests first, they could have then engaged in fearless refactoring, they would have been orders of magnitude less likely to have broken any functionality, and what's more, nobody else would have cared about or minded the change in code. Write whatever dirty abomination you want. Then unit test the crap out of it. Then refactor it into the pristine shining epitome of every pattern fanboy. As long as it works, before and after, nobody will berate you for it.
- baobabKoodaa 3y ago> As long as it works, before and after, nobody will berate you for it. This is not the reality in most places. People care about aesthetics, and about practical issues like how maintainable the code is, even if the code is thoroughly tested.
- HenriTEL 3y agoStill it's quite rude when some people spend a lot of time on some part of the codebase only to find someone rewrite it without discussing it first. Also the point here is about cognitive cost of working on the refactored code, not broken functionalities.
- jpnc 3y agoUnless I'm misreading something the author does not mention breaking anything.
- PUSH_AX 3y agoDRY might be the bane of my existence as an engineer. The vast majority of developers I meet that are self proclaimed as "senior" are extremely dogmatic. They've had roles where it's been drilled into them {{engineeringPractice}} is god tier engineering and it should be applied indiscriminately to everything you write. Being a great engineer is about being able to be pragmatic, learn the rules, then learn where you can break the rules. DRY is like the entry level dogmatic practice everyone adopts, and it leads to some god awful abstractions and it's really hard to explain why having un-DRY code is ok, it's really unintuitive to the "initiated".
- mariopt 3y agoCode duplication sometimes is a good thing but it doesn't prove that clean code is a bad thing. I think you overcommitted a bit on the refactor, if you had replaced those "10 repetitive lines of math" with a function it would have been cleaner. Let's be crystal clear about it, your teammate did a terrible job not creating a function for those 10 repetitive lines. I would be rejecting this PR but never rewriting it. Rewriting a PR is a quick way to insult someone because you're not open to debate and many times you don't have the full picture of why the code was written this way. PRs have to be reviewed and rejected when there are no coding standards, the last thing I want is people committing code and saying "Clean code is not important", this mindset only leads to a codebase that no one wants to work within a matter of months. Communicating better and having some tact is the lesson you should be taking from your experience, clean code has nothing to do with it.
- blowski 3y agoAbsolutely. The lesson is "goodbye to over-applying a rule without considering context-specific trade-offs", which is a lesson that takes time to learn.
- rewmie 3y ago> The lesson is "goodbye to over-applying a rule without considering context-specific trade-offs", I think the problem is the rule itself. A rule of thumb is fundamentally broken if it does more harm than good. The heuristics to drive a decision need to lead the developer to a good outcome if they apply it without overthinking things or have meetings, because that's what rules of thumb are for. Time and again developers tie codebases into contrived knots by mindlessly repeating the mantra "duplicate code is bad code" because they fail to realize that code that looks the same is not the same code at all, and sometimes should not be the same code at all for a number of reasons. Developers need to think hard about whether a refactorization helps simplify a project, and shoving code sections into multiple unrelated code paths is surely a way to do the exact opposite. Moreso when a mastermind developer opts to add conditionals to force similar code blocks to fit other code paths.
- 59nadir 3y ago
- lifthrasiir 3y agoNot only the resulting abstraction is harder to adapt, but the abstraction itself is badly chosen. The first and foremost thing you want to refactor is the repetitive set of arguments. As it stands, all those arguments will come from interacting with handles, so you can reasonably expect that they are deeply coupled with handle changes (for example, it may allow for fixed 1:1 aspect ratio in the future). So they should go to its own object or even class, so that some duplicates can go into its methods while allowing for individual changes. And then you can decide whether you want to refactor more or stop there. Some refactoring changes are clearly beneficial in virtually all counts, others less so, and mixing them is not a good strategy.
- elnatro 3y agoRelated to this: the worst part of all this “Clean code” mindset, it is the idea that having comments in the code is somewhat harmful, because “if there is a comment, the code is not simple enough”. Currently in my second workplace that belongs to that “school of thought”.
- aulin 3y agoI believe the higher the mean seniority (as in time in the same workplace) gets the more a programming workplace resembles a cult.
- cultureswitch 3y agoIf you have a block of code and feel that the block warrants an explanation, that block of code should receive a name instead. A block of code with a name. Behold: a function. Abstraction! Scary! I do think things like types and functions should be documented, and on rare occasions there are tricks which can only reasonably be explained using code comments, but those are extremely rare.
- elnatro 3y agoYes you’re right, but sometimes in interpreted languages it’s difficult to understand what the function does. Python resolves this problem via type-hinting, Ruby relies on comments (although there are some approaches like sorbet).
- zaphod420 3y agoWTF. There are really "anti comment" people out there?! That blows my mind.
- elnatro 3y agoYes, in their view they think that a code comment implies code that needs to be refactored, yes I’m not kidding.
- ilitirit 3y agoI will never understand the general thought process behind these articles. "I'm giving up on X/Y/Z because I've found a case where it didn't work well for me". Isn't that how pretty much everything in the world works? There's no reason to be dogmatic about things like this.
- cybrox 3y agoThis IS the actual lesson they want to convey. "Use <tool> but don't overdo it and attempt to use <tool> everywhere." It's just a bad mix with the clickbait title, a story that has a different root cause and a somewhat obscurely written conclusion.
- ilitirit 3y agoBut surely this should be already inherently known? I have never met anyone that stuck dogmatically to "rules" from things like Code Complete, Clean Code etc etc no matter how much they espouse them. Very simple examples: - 1 assertion per test - Exceptions instead of return codes - CQRS etc All of these are good guidelines in some contexts. I cannot fathom why anyone would think they apply to every situation...
- cybrox 3y agoI unfortunately have. Guy managed to bloat a simple mobile app to 180kloc. Every change we wanted to make after inheriting the codebase required changing abstractions in >10 places and all their corresponding unit and integration tests. I'm talking changes like adding an additional value to a dataset. Everything was abstracted as far as humanly possible. He was a very proud clean code aficionado and would not let anyone from his old team dissuade him. He would also regularly scold his somewhat more junior co-worker when he did not follow his 7 layer abstractions for services, providers, surfaces, use cases and bindings. But alas, I don't want to say you're wrong but there are people that would do well with this simple piece of advice.
- JonChesterfield 3y agoYour colleague wrote lots of code using copy and paste. You refactored it post commit. He complained to your boss, who had a go at you, and now you're going to leave mess in the codebase next time. There's a lesson to be taken from this experience but it isn't that copy&paste is better than writing functions. Your refactor should have gone up as a change to be reviewed, tagging the author. However the escalation to boss who tells you to revert is a really bad sign, as opposed to your colleague talking to you directly.
- lakpan 3y ago> tagging the author Sounds like trouble to me. “Hey I rewrote what you wrote because it sucked. Got problems with that?” I suppose the best solution to this problem would be a “late review” asking for an explanation, offering a solution, and hoping it doesn’t just get ignored, which is the easiest thing to do for the author.
- viraptor 3y ago> Hey I rewrote what you wrote because it sucked. Got problems with that? Reading it like that is just insecurity speaking. If anyone wants to rewrite my code to be more readable, I'd love for them to tag me in the review and show me how they did it, so I can learn. Assuming good intentions and being open to discussion goes a long way :) I'll always tag the author for review if I'm rewriting something recent. It's more "Hey, I was too late to mention this in the review, but I think this improvement was worth the time. Let me know what you think in case I missed something important about the original."
- lakpan 3y ago> I'd love for them to tag me That’s generally what I like too, but often in teams my suggestions are either approved with zero comments, ignored or followed by wasteful reviews by people who don’t know the language they use every day, and don’t bother to google their answers.
- oytis 3y ago
- mrkeen 3y agoAuthor made up his own definition of 'clean code' and kept it in his head rather than defining on the page. So whatever the author is telling you to 'let go of' may or not have anything to do with 'clean code' as you understand it.
- Apocryphon 3y agoClean code is not a suicide pact.
- porcoda 3y agoI'm going to go out on a limb and guess that their "reason 1" was the sole source of the issue. This smells like an instance of the "nobody likes a know-it-all" problem that often arises with junior devs who haven't yet learned that their job isn't just between them and the computer, but them, the computer, and other people: the cleaner version likely would have replaced the dirty version had the author actually had a dialog with the author of the dirty code and mutually decided that there was a better way. The article likely would be better titled as "I learned a lesson about working on a team", not "goodbye, clean code".
- Kiro 3y agoI think the title is fine. It's a classic for good reasons and has been an eye-opener to a lot of devs falling into this exact trap, which you can do even if you're working alone. You overengineer a clean abstraction just to get bitten by it in the future.
- watwut 3y ago> This smells like an instance of the "nobody likes a know-it-all" problem that often arises with junior devs who haven't yet learned that their job isn't just between them and the computer, but them, the computer, and other people Meh, it is usually seniors on power trip who are guilty of this.
- JonChesterfield 3y ago> instance of the "nobody likes a know-it-all" problem Excellent insight. I think this exactly captures the dev environment. The more complicated code was viewed as a threat, the rival worth taking down a peg or two via management chain. For juniors reading this who have the same experience. "Nobody likes a know-it-all" is context dependent. It's absolutely true of lots of professional settings. Simplicity over flexibility, avoid confusing language constructs, preference for lots of time at the keyboard and languages that encourage this. The lifelong learning, software craftsman, reflect on the process philosophy advocated in various places is completely at odds with that setup. Trying to get better is unpopular with those who are not improving. Both are valid life choices. Software has been a comfortable place to put in your seven hours at the office and go home. It's also a world to explore bounded only by your imagination and intellect. Beware spending decades working with those who fear the unknown if you'd like to be one who discovers novelty. Or more concisely, if your incentives are misaligned with those of your colleagues, consider getting out of there.
- jokethrowaway 3y agoYes and no. You need the right balance and the ability to make the right choices. As in for everything. If you are implementing something trivial, duplication is often the right choice. I've worked on complex frontend applications (including graphic editors, social networks) and never got to a point where duplication hindered my understanding of the codebase. The problem I've seen (compounded by React zealots, incidentally!) is abstraction bloat. Think flux and redux - and boy, that complicates the codebase massively. Once we started using React + Redux, our time to production dropped massively, but we blamed it on the new tech and we were "cargo culting" hard. This has improved nowadays as we don't use Redux anymore but we're still producing very large and complex application for the set of features we have. On the other side, I worked on complex backend business logic where people didn't even know what clean code is (think massive payment system) and it was a complete nightmare to try to understand what was going on. When everything you read is incredibly detailed, you can't keep everything in your head, you need to group it conceptually. You can do it in code, or in your head. It's the same reason Go was criticised for not having Generics: without abstraction you'll turn a 100 lines app into 500, making it way harder to follow and fit into your memory (and I'm not talking about RAM). The other issue in the clean code debate is that what's understandable changes from person to person, depending on coding and reasoning capability.
- RamblingCTO 3y agoI don't agree with that being clean code in the first place. It's just adhering to the DRY maxim, which is one perspective on clean code, and imho the worst one. DRY causes you to mix use cases and glueing stuff together just because it's the same code. DRY caused so much problems in my professional life. I'm now in the "DDD, ports & adapters" fraction and I encourage people to duplicate logic as long as the implemented use cases are isolated. That produces code that's easy to read, maintain, test, and is intertwined with the business logic. How often couldn't you explain business logic to stakeholders/customers because the code you write is worlds apart from how the app operates? That's what the author also means with "My code traded the ability to change requirements for reduced duplication, and it was not a good trade." I guess. Really good self-reflection though.
- andsbf 3y ago+1 for this, code should be layout to express business logic, abstractions that difficult the readability of the business logic are not worth it, it is a distractions. Yeah takes a while for juniors to understand when/how to use DRY. Repetition is not a terrible evil, it has its place
- jongjong 3y agoThe term 'clean' is ambiguous. I aim for 'simple' code. That means as few lines of code as necessary, as few abstractions as necessary, as few files as necessary. I have a rule of thumb that every abstraction I 'invent' should be relatively easy to explain to a non-technical person. So far in my 12 year career, I don't think I've ever had to invent an abstraction that was so complex that I couldn't explain it to a moderately intelligent business person and I've worked on some very complex systems.
- 000ooo000 3y ago>Clean code is not a goal. It’s an attempt to make some sense out of the immense complexity of systems we’re dealing with. It’s a defense mechanism when you’re not yet sure how a change would affect the codebase but you need guidance in a sea of unknowns. Vomit. Guy picks bad abstraction, goes rogue and refactors a coworker's change, gets told off by the boss, and then writes a blog post with lofty garbage like the above as though he's an authority on clean code. "Brilliant" jerk vibes. Pass.
- cybrox 3y agoI'm sorry? I also disagree with the authors conclusion but the article is definitely giving me less "jerk vibes" than this reply. The lesson learned in the article should be "talk to your co-worker on why they solved a problem a different way". It should be about communication, which this reply does not shine in either.
- mgaunard 3y agoThe main problem wasn't the duplication, it's modifying someone else's code without letting them review the change.
- Joel_Mckay 3y agoDevOps/Agile always has a serious set of sustainability trade-offs, but in the beginning tends to show relatively quick progress. A great model for service companies billing by the hour for a limited scope product-iteration lifecycle, but a poor choice for building reusable infrastructure assets. =) If you are good... than you will automatically leave a trail of commented stubs, design pattern templates, and working examples.... that set a project trajectory implicitly. Thus, avoiding having to explain choices to people that can't or won't understand (good frameworks can help in extreme cases of stupid). People often entrench themselves in bad ideas/habits. Training peers can be challenging, as sometimes one must subtly repeat the same evidenced concept everyday in a different way for a month till a core simple concept registers (Neurodivergent managers can communicate in this manner even over trivial choices.) Being a good communicator is important when a problem domain shifts into the theoretical (i.e. 0 search results for the Jr.), and learning not to sound disrespectful/irritating takes practice. At some point, a team needs to cut their losses, and confine the weak/obstinate members to an area that matches their skill/will level. This is often the first step in getting laggards to quit on their own, or making due with HR biases. Good luck, =)
- mbwgh 3y agoSince there are a lot of "replies to the author" in here: The article is from 2020.
- bartimus 3y agoThe real problem here was the overall software architecture and development workflow that apparently wasn't geared towards building 2.0-alpha versions of a component while still keeping the 1.0 version untouched.
- denton-scratch 3y agoThis stood out to me: > Rewriting your teammate’s code without a discussion is a huge blow to your ability to effectively collaborate on a codebase together. Frankly, that sounds unprofessional. The author sounds like an experienced developer; that approach to refactoring seems arrogant.
- cultureswitch 3y agoThat refactor was good. The way the colleague was handled wasn't. Repetitive menial code like the one originally submitted should not be accepted, but you shouldn't unilaterally rewrite it either.
- sdk77 3y agoFrom the article: "When we don’t feel confident in our code, it is tempting to attach our sense of self-worth and professional pride to something that can be measured. A set of strict lint rules, a naming schema, a file structure, a lack of duplication." I feel a little triggered. Maybe I'm not feeling confident? No. I've dealt with lots of other people's code and I'm really not bothered by repetition, even not by overuse of abstractions. But. Strict lint rules, a naming scheme and a file structure (in other words, basic coding standards) are, in my opinion, the minimal foundation of any professional software development project. Looking at it this way, clean code is code that is consequently adhering to a given coding standard.
- phendrenad2 3y agoI don't know where the author learned about DRY, but I'd be shocked if it wasn't accompanied by a warning that DRY is only a general guideline, and in practice it's beneficial to allow some duplication to enhance code readability.
- stevage 3y agoYeah, I think I agree with the learning. A good middle ground would involve building up some helper functions, so you get something like: let Rectangle = { resizeTopLeft(position, size, preserveAspect, dx, dy) { doLeftHandleThing(...); doTopHandleThing(...); // something else too }, Then you don't lose the ability to quickly override things when there are special cases or requirements change, but you can keep the overall code repetition down a bit.
- k__ 3y agoI think, most of deduplication issues come from (1) premature optimization and (2) doing "technical" instead of "semantic" deduplication. (1) When you pull things out too early, you might miss the big picture and constrain yourself in the long run. (2) Sometimes things look similar, but aren't. By deduplicating without taking semantics into account, you can end up with a nice looking function at definition side, but at call side it looks too abstract. Both of these issues give you something like "createHandle".
- chrischen 3y agoWhen I first heard Dan Abramov talk about this I also recoiled a bit and was a bit offended. But the takeaway isn’t that abstraction is bad… it’s premature abstraction is bad. In fact just because it can be simplified does not mean the abstraction or simplification fits. Just because you can draw a circle around a common set of things does not mean that set is semantically significant. For example all humans have arms and legs, and you can make an abstraction encompassing those features, but it’s an incomplete abstraction if you miss the head or other features characteristic of an actual human. Before a domain is concrete a premature abstraction actually adds to technical debt.
- sgbeal 3y ago> Rewriting your teammate’s code without a discussion is a huge blow to your ability to effectively collaborate on a codebase together. It's a mistake to believe that the code belongs to any one teammate. Code in a shared project is the project's code, not any individual's code. Folks stuck on the idea that any given part of a project is "their" code would do well to look up the term "egoless programming" and start applying it to their work.
- sidcool 3y agoPlease add a 2020 tag to the title. @dang
- nickysielicki 3y agoAnyone who takes a change to a piece of software personally is lame. Take the patch, don't take the patch, it's absolutely mundane.
- debarshri 3y agoI think the point of DRY is to avoid side effects. For eg. If you repeat same code 10 places and in one instance you decide to change the logic, now you have 9 places with old logic and 1 place with different logic. Removing duplicate code for readability and making code clean is second order affect in my opinion. Times have changed since pragmatic programmer [1] was written. Lot of the code we write today does not have the longevity nor it needs the resilience that was required in past decades. It is purely because things move very fast, engineers iterate very fast these days. Lot of principles still hold true but we have to pick and choose what's right for a given problem or situation. [1] https://en.m.wikipedia.org/wiki/The_Pragmatic_Programmer https://en.m.wikipedia.org/wiki/The_Pragmatic_Programmer
- JonChesterfield 3y agoThat pragmatic book is very keen on code generators. Distill the information to some variant on ASCII tables and then derive all the redundant forms from it as a compilation step. I think that's the right approach. I'm totally up for generating C++ from JSON if that's the available data representation. So far, essentially everyone I've worked with has hated code generation in all forms. In language mechanisms may or may not be acceptable (C++ templates more likely to be OK than C macros). Outside language mechanisms - python writing source code during the build and similar - very hard to get past review. I'm curious whether that aligns with other people's experience.
- magicalhippo 3y agoWe duplicate code to avoid bugs. We have a lot of customer integrations, and often the source system is one we've integrated with before. So we usually copy the whole integration and make some tweaks. Invariably our customers want some data massaging and custom logic, and by duplicating we can't screw up another customer's integration when we make changes. Of course we do have some code in shared libraries, like parsing dates and numbers, cleaning mixed utf-8/latin1 input and such. Of course, that does mean we might have to change many integrations if something fundamental changes. But overall it has worked very well for us.
- fadzlan 3y agoThe point is how should such code grows? If it meant to grow on its own, separately on different requirements, then its not duplication. It's just a code that looks the same, for now. Everything comes with a price. The Clean Code book basically argue on one side, on what you can gain with such practice. It's not gospel, its something that argue on benefits on certain practice. As a developer, you probably are more privy on what is a better trade off based on your project. Do what make sense. You may default on writing "messy" code, or writing "clean" code, before you find the middle ground that make sense, and thats okay. Its a journey, not a destination. It takes experience to make a good trade off in your daily coding. Learn from your mistakes and move on.
- civilized 3y agoRead literally, the word "clean" in a coding context is most naturally interpreted as "observing a consistent style at a basic syntactic level" (e.g. camel case vs snake case), or "having a minimum of irrelevant clutter" (e.g. variables and functions that are defined but never used). It's about the sort of things that a linter looks for. Unfortunately, "clean" has been stretched and concept-creeped to the point of meaninglessness in software engineering, especially by the book of the same name. Now, "clean" has become an invitation to enforce ideology on complex questions we don't understand. Once something is declared not "clean", action must be taken to mitigate the primal fear of contamination, even though we don't really know what "clean" and "dirty" mean in a coding context. We should stop using this vague crutch word for everything we approve and disapprove of in code, and find more accurate words to express our feelings. If we think code is repetitive, we can call it repetitive, and have a conversation about whether repetition is good or bad in this context.
- bazoom42 3y agoSome people are incapable of understanding context and trade-offs. Every rule must be either “always” or “never”. Always use inheritance! Oh, it caused fragile code in this instance. Lesson learned - never ever use inhertance! And so forth. In this case, the author is confusing de-duplication with creating a particular abstraction, and when the abstraction turns out to be a bad fit for the problem, they decide code duplication is actually fine. This is the wrong lesson.
- Tainnor 3y agoThe problem here is that changes are committed directly to the main branch without a review. There needs to be some sort of peer review (I don't care if via pairing or with a classic PR) for every code change exactly to prevent an escalation like experienced by the author. The boss was a bad boss, instead of reprimanding you, they should have realised that they were missing a good process. In a team with a code review culture, an overeager newcomer might attempt something like this (and tbh, whether it was a good attempt or not is impossible to judge without knowing the code and its context) and a peer would have said "yeah, thanks but no" or "good idea, but let's try it like this instead", etc. Independently from that, I do think that one shouldn't just refactor code without good reason because even if it's bad code, it might be code that rarely needs modification. The best time for refactoring is when you need to change behaviour and you realise that the old code structure is making things too hard. Unfortunately, I think the wrong lesson was learned here.
- regularfry 3y agoCode review after merge is perfectly fine. Better, in some ways.
- Tainnor 3y agoThat may work in some cases, definitely a no go in a workflow where deployment is fully automated via GitOps, i.e. every push to the default branch triggers a deployment to prod.
- regularfry 3y agoWhy?
- Tainnor 3y agoI answered this here: https://news.ycombinator.com/item?id=38580236 https://news.ycombinator.com/item?id=38580236
- akkad33 3y ago
- jacknews 3y agoI even think this conflates 'clean' with 'duplication'. The first code is clearly 'clean' conceptually, although there's plenty of duplication, it's very clear what's going on, it's 'flat'. The re-worked code with an abstraction is more complex, even though it's 'tighter' in some way, it's suddenly multi-leveled, and so less clean conceptually.
- civilized 3y agoI think we should stop stretching the word "clean" to encompass everything we approve and disapprove of in code. Your discussion of the underlying issues is perfect - the author's coding dilemma is a classic tradeoff between the complexity of repetition versus the complexity of abstraction. "Clean", if it means anything at all, is not the dimension on which these options differ. I elaborated on this in a separate comment here: https://news.ycombinator.com/item?id=38568178 https://news.ycombinator.com/item?id=38568178
- pftg 3y agoFirst version was cleaner, and new code is, obviously, not clean at all, because it requires much more energy to learn then first one. Interesting that author misguide DRY code with Clean code
- lysecret 3y agoI mean the blog is called overreacted sooo..
- deleted 3y ago[deleted]
- sebastianconcpt 3y agoIt went from one extreme to the other. Is not cleanest code or its opposite. You have a gradient of options in how you'd code. Here is another way to present the issue discussed by the author: Every level of indirection you add will have a cost for the next developer that needs to extend or maintain it. If, for whatever reason (making code "cleaner" for example) you didn't do it gracefully/welcoming/invinting-to-change/self-docummented enough, then you increased costs, which is the same as being aggressive to business margins. So what's a more interesting conclusion? Get over childish reactions of saying "goodbye clean code" but embracing improved discernment on when and how to introduce it.
- JaceLightning 3y agoArticle is dumb. He says don't write readable code for two reasons: 1) refactoring someone else's code might hurt their feelings. 2) you might need more functionality later. Wut. Write clean code. Write better unit tests.
- pjmlp 3y agoWorking in enterprise consulting, usually with plenty of external partners, made me become used to "it works" and "fullfils expected behaviour" as already good enough in most cases, even if the code is not clean.
- Piraty 3y ago"clean code" aims to optimize readability and thus maintenance cost, not optimize SLOC.
- butterisgood 3y agoHad a coworker and I collaborate on code during the day to have me come back the next day to it all having been rewritten. I pointed this out to my manager who did nothing. I asked to be moved to another project as I figured 1. This person was very passionate about the project but wasn’t good with feedback all the time. I stayed available for sometimes pointless code reviews. The project succeeded anyway. And the code is actually still pretty good today to be honest. Sometimes a difference of opinion is just a mismatch of objectives 2. I felt if management didn’t want to help with this situation I had to protect myself and my own self esteem, and sense of contribution to the team. It’s weird how much “feelings” can and honestly should come into play in a technical role. Was this the best outcome? I don’t think so. I think each of us could have stuck it out on the project working together longer. But it was not feeling like we had management support to do so, and everyone took “the easy way out”. The good news is this didn’t create a ton of technical debt and I still have a high opinion of the other developer to this day.
- deleted 3y ago[deleted]
- jakobov 3y agoCheck out the book Code Is for Humans if you are into coding books.
- deleted 3y ago[deleted]
- flavius29663 3y agoClean code explicitly addresses situations like this: the code "seems" identical for the time being, but it's not in the long term, because it applies to different objects, that will evolve independently. This is in the book, so I am not sure why they're saying "bye Clean Code", it should be "I should read Clean Code again".
- rakoo 3y agoRob Pike once said "A little copying is better than a little dependency" as part of the reasons why Go is the way it is, and the more I use programming, the more I understand what he meant. Repeating yourself is not a problem in itself. What matters is grasping the unit you're currently reading and possibly modifying. DRY often means adding another abstraction, but if the abstraction is not orthogonal enough you now have to consider 2 units instead of one, and you've made it worse.
- romankolpak 3y agothis resonates strongly with me because i just had to nuke an abstraction invented by my colleague, which solved a small DRY issue but introduced a big change difficulty issue. All we had to do is do some repetitive work for values of a dictionary (stringify and lowercase). We ended up having an abstraction of a dictionary with smart value conversion behaviours, which brought pain every time the business wanted some added custom behaviour (e.g. don't lowercase this property, make human-readable that property, etc). Younger me would keep piling up complexity onto this abstraction. Modern me just duplicated some `str(..).lower()` calls, removed the whole thing and went home happy.
- javier_e06 3y agoThe developer cycle: Small feature-> Coder -> Architect -> Maintenance. Every line is a potential bug. Less lines less bugs. Not all bugs are created equal. If one studies how information is carried on living organisms whose maxim is to keep information surviving through time we will see duplication. Lots of it. Aging is the action of duplication of incomplete/incorrect functionality. Is normal. Decreases the level of effort going forward. All projects age. Some have a productive life and gracefully die living a beautiful garden behind, some can't die and turn into tumors. Is all food for thought.
- deleted 3y ago[deleted]
- ccorcos 3y ago“Getting high on abstraction” is an awesome phrase from this article. Would make a great title too.
- throwbadubadu 3y agoHard lesson learned the hard way ;) Abstracting and clean coding around seemingly abstractable and similar fresh code (or even existing one!) without knowing the details that lead to that (agreed, often also not the best craftswork, but anyway) or the near future, is often the culprit of the later big tangled mess to be. Also really, not just refactoring someones code without talking, but just pushing? Not even a PR? Imagine a workplace where everybody does this the whole time, lol. The boss asked for a revert for many good reasons ;)
- francisofascii 3y ago> "Let clean code guide you. Then let it go." Good post. Good advice.
- dclowd9901 3y agoI fight on this even with experienced engineers. Clean code !== DRY code. Clean code is code where it’s easy to see what impact changes have.
- nathell 3y agoThis article always reminds me of this excerpt from re-frame’s docs [0]: > Now, you think and design abstractly for a living, and that repetition will feel uncomfortable. It will call to you like a Siren: "refaaaaactoooor meeeee". "Maaaake it DRYYYY". So here's my tip: tie yourself to the mast and sail on. That repetition is good. It is serving a purpose. Just sail on. [0]: https://github.com/day8/re-frame/blob/master/docs/correcting-a-wrong.md#a-final-faq https://github.com/day8/re-frame/blob/master/docs/correcting...
- gspencley 3y ago"Clean code" needs a re-brand. It seems like constantly, over my 25+ year career, I'm seeing never-ending push back against design patterns, abstractions, de-duplication etc. There are always the same reasons: - Abstractions make code more complex - We don't have time to write clean code - It's all just your opinions and preferences The purpose of clean code is to make code SIMPLER, and easier to maintain as requirements change. The value of software is precisely its ability to change over time. Otherwise we could stick to fixed circuits which are FAR easier and cheaper to implement and maintain. Therefore, if you did not achieve these goals with your refactor, and your boss can make a persuasive argument that your refactor made it HARDER to maintain as requirements change into the future ... then your refactored code wasn't "clean", now was it? As for not discussing the refactor with the original developer, that's outside the scope of clean code. Has nothing to do with whether or not clean code is good or bad, or whether your changes were "cleaner" or not. That's a process and etiquette discussion. Just because you did a dick move and went cowboy doesn't say anything about whether or not clean code is valuable.
- foobarian 3y agoOne thing I learned in industry is that the best cleanly written code does not survive contact with product. Sometimes the technical debt is encoded in the product requirements themselves, and no amount of refactoring or best practices can fix it, only mitigate the pain.
- gspencley 3y agoSure. We see that all the time. Error handling and security are often afterthoughts, for example. We engineers tend to get "commissioned" to build quick proof of concepts and once the business sees their vision come to reality they don't want it to be thrown out and redone with architectural consideration, they want to rush it to market as the "MVP" as quick as humanly possible. This is a reality of our industry that we need to manage and find ways to cope with. When it comes to certain architectural decisions, there are things that are very hard to change later on, and sometimes you don't know how the product will need to scale, or what challenges the engineering team will be faced with a year, two years, 5 years down the line. This is where we need to make our best guesses and we can't always get it right. When it comes to the rest, making the code as simple and easy to change is the best we've got. I was recently reminded by someone I look up to and admire that not everyone has the "gift" of being able to think "top down." This came up because I am often frustrated by the claim that "we don't have time to write this cleanly." It's a frustrating claim to me, because I don't find that writing short, single responsibility code that is well labelled takes any time at all. I also spent time learning how to work TDD so I can write unit tests as part of the development and design process rather than having to go back and write tests after the fact. But a lot of developers build "bottom up", where they write really long functions or methods, or dump everything into a single file and then think about separation of concerns, and layers and isolated "components" later on and thus need to spend a lot of lengthy time refactoring after the fact. That initial "bottom up" process is the "getting it to work" part of the process, which is fun for most devs. But if they then need to refactor after it is tedious and laborious and not fun at all. And I think this is probably where the vast majority of the push-back and friction amongst devs really comes from if we look at it from a human point of view. If you enjoy the process of DESIGNING software, and thinking top down, you won't find refactoring to be a chore or time consuming. You will understand how a well chosen abstraction can SIMPLIFY rather than complicate. But if you like to solve problems primarily, and to build things you haven't built before, and by "building" it means getting something that "works" up and running quickly ... then you don't want to spend your time reading books on design patterns, or refactoring your PR because the Principal told you it's not up to standards.
- HippoBaro 3y agoAbstracting code is always a dangerous gamble because they rely on invariants. In this case “the shape all resize the same way”. When the invariants breaks, the abstraction collapses and the code can become much more convoluted than it was originally. I’ve seen it many times. In my career I’ve seen many many bad code abstractions and very few good ones. As measured by how long before they break. I’ve asked the engineers that came up with those if there was a trick to it, and the answer has always been “dude it’s the 10th time in my career I’m writing that stuff”. Good abstractions come from domain experience. If you’re writing something new, don’t abstract it. If you feel smart about it, that’s a bad sign. You don’t feel smart when you’re writing something for the 10th time.
- donatj 3y agoI've been doing this a long time and one of the things I've learned is the more abstract the code, the more likely it is a changing business need will completely break the abstraction in unforeseeable ways. Good code is easy to change. Frankly, after years of falling heavily down the OO hole, I've come around to see procedural with as pure of functions as reasonable as probably the easiest to maintain long term. Code is easy to follow and easy to modify.
- pyrale 3y ago> Firstly, I didn’t talk to the person who wrote it. I rewrote the code and checked it in without their input. The most egregious problem doesn't sound like a code issue at all to me.
- charles_f 3y agoThreads from the previous 2 times out of 5 submissions that this caught on and was profusely commented on and dissected: - Nov 2021: https://news.ycombinator.com/item?id=29239861 https://news.ycombinator.com/item?id=29239861 - Jan 2020: https://news.ycombinator.com/item?id=22022466 https://news.ycombinator.com/item?id=22022466
- cratermoon 3y agoThe problem with the example has been discussed elsewhere: the design is wrong. Of course refactoring but keeping the design more or less the same won't work.
- sasaf5 3y agoThe epitome of "no duplication's" failure is CMake. It subsitutes two duplicated build systems with a crudely unified version of both. What before were duplicated lists (tedious to maintain) become an algorithm (difficult to maintain). Add to it the plethora of other build systems and you really have something that has failed its unifying mission.
- chasing 3y agoYoung engineers can be childlike sometimes in that they hear a rule and feel like the rule MUST BE ENFORCED at all times, regardless of nuance. Coding best practices are tools. The wisdom is in deploying those tools properly.
- moistoreos 3y agoThis experience has zero to do with clean code. The title is very much a misnomer and incredibly misleading. This is an elaboration on the experience of abhorrent engineering culture at this company. From people who can't professionally speak with one another to a manager who cannot seem to effectively solve the core issues underlying the problems at the company. Instead of a moment of reflection on HOW to improve the root cause of the problem, it feels like they're kicking that can down the road. Two things I'd like to point out: 1. It's nice to see some form of humbling commentary from the author; albeit, I don't think it targets the right solution to the problem. 2. I still think there's a lesson here for any org to digest and that is communication is such a vital and integral part of "a raising the tide lifts all boats", so to speak.
- zalox 3y agoIf you can see the abstraction the code is perfect.
- enginaar 3y agoi guess everyone is a little confused about what clean code is. I thought the first example was clean code until author claimed theirs is.
- bunderbunder 3y ago> My code traded the ability to change requirements for reduced duplication, and it was not a good trade. This is the the one that really clinches it for me. I think it's important to be aware that "clean code" standards came out of the early-mid 2000s contract development community. "Maintainability" means something different in that context, for two killer reasons. First, you're very likely to walk away from the project after a fairly short time period. Maybe a couple months, maybe a couple years. In 5 years, though? It's almost certainly someone else's problem. Second, you probably bill by the hour, or something like it. So decisions that make the code resistant to future change aren't really a bad thing, because, while they do make that hypothetical future maintenance work more expensive, you also get to charge more money to cover those costs. I'm not trying to cast shade on contract development shops here. Business is business. But I do think that those of us who are developing software for ourselves might be operating under a somewhat different incentive structure.
- T3RMINATED 3y ago[dead]
- summerlight 3y agoIn this particular problem, I see that there's a certain threshold where replacing duplication with abstraction really pays off. But everyone has different views here and there and no one really has a good answer. So we have two choices: 1. Proactively refactor the code. This makes it a future prediction problem, which is never easy. 2. Keep it as is, refactor when it really becomes a pain. You gotta do much more work than where you made a right prediction. Many hardcore engineers (including me) prefer the option 1 since it's more of fun, but in my experience, we're usually not great at making a good bet.
- joestr87 3y agoI think the main thing you’ve got to ask yourself when abstracting duplicated code is: are these things very similar because they are intrinsically linked or is it slightly coincidental. I.e if we ever have to change B will we always want to change A in the same way? If the answer is that you’re not sure, it’s probably better to duplicate, and see what the case is when it needs to change again - and then decide whether to abstract or not.
- kazinator 3y agoThe main thing you have to ask yourself, will these duplicates ever need to be special-cased, and how hard will it be? Will someone have to write monolithic handling for that case from scratch, or are there ways of hooking or overriding individual behavioral choices?
- gumby 3y agoThe problem here is not understanding which are the ends and which the means (I assume from other things in the essay that the author has since figured this out). I see this problem a lot in people who memorize but don't understand the GoF book (Patterns) so you see huge stacks of singleton envelope factories. The point of not repeating yourself is so you can fix a bug in a single place, and understand common behavior. As it happens it can also reduce code size, not that that's a big deal for most people these days. In this case of seemingly duplicated code the different implementations were not really common, at that early stage only coincidentally so, and it was known that they would eventually diverge. So even if DRY is desirable (generally it is) this case was one of premature optimization. Patterns and rules of thumb like DRY should not become fetishes; they are conventions to be picked up when they make life easier and communicate something useful.
- kazinator 3y ago> Each shape (such as a rectangle or an oval) had a different set of handles, Yet, that's not what the code says. The objects have multiple methods with similar signatures representing handling. The right thing here is to make the handles objects. The objects know what their parent is and send it messages "I have moved". There is one method in the shape which is reponsible for handle-initiated movement. The object looks at which handle has moved (it's an argument), and other state like Shift constraint, and adjusts its representation accordingly. The behavior of how to respond to which handles should still be the responsibility of the shape. Commonality there could be factored out into some common functions such that if you need to special-case something, the in that shape you stop using the common functions entirely, or use them as a fallback for whatever behavior remains that is common. Multiple dispatch is made for this; the movement behavior is a combination which shape and which handle. With a precise specialization of a multiply-dispatched method, you can code behavior for an exact shape and handle, overriding any less specific definition. This is all a Solved Problem.
- kaveh_h 3y agoAs a freelancer and consultant I’ve seen this drive or urge for simplifying coding go to the extreme to become pointless or even very damaging at a larger scale. An idea that sometimes popup in some ambitious people are usually centered around making programming easier or more foolproof by developing a platform that supposedly would make that easier and safer to build software systems within an enterprise. What these people seldom realize is all the effort that needed to build a good platform from scratch versus finding and contributing to a suitable OSS project. This is what has happened at a client I’m working for now. An architect thought it would be a great idea to develop such a platform with multiple components like a runtime, a visual designer to create flow diagrams that are finally transformed that into code, integrations with databases and lots of other features based on code generation from configuration files. After some years of development this platform have only managed to create hurdles for the only project that have tried to adopt it. The documentation is outdated and lacking, the extensibility is lacking, the performance is not great, there is one consultant who is still developing it and charges a fortune and other teams avoid it like the plague. While this has been going on other great open source alternatives have been developed or matured.