Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

That's the same principle which makes it wise to first do some copy pasting before you abstract stuff into a common library. Gathering some (more than two) concrete use cases before you factor out the common functionality makes much better library functions.

A common sign of prematurely deduplicated code is a common function with lots of boolean flags and other knobs to tweak its behaviour for every use case added after it was written.



You owe it to yourself to type out your copied code again. So easy to lose track of context when you’re moving fast. Variables have the wrong name, conditionals can’t be false, etc. Copy, yes, but don’t paste. Do it the hard way.


The ideal heuristic is to only deduplicate towards more orthogonality.

Suppose you started from first principles and navigated down the ontology tree taking one of the shortest paths (well, shortest-ish since it's a hard problem that'll burn up too much time otherwise.) Would you encounter your deduplicated function on the way? If not, it's making it worse.


Rule of 3s. Even more basic than this, never create an abstraction for a routine only used once.


I was on a team rewriting a UI from native to web, so we were moving fast on copying existing features instead of inventing new ones. About four times in 18 months we had triplets of features in the backlog and tried to generalize the implementation on the second occurrence, only to have to do expensive rework on the third. The code and the tests just wouldn’t bend the right way. We had mostly agreed to follow the Rule of 3 but someone kept thinking this time would be different and it never was. The last story was always the slowest and extra time spent on the middle one was wasted.


I blame bootcamp culture driven between 2010 and 2020.

Students learning DRY on day 1 and then applying it to the max before intuitively understanding the problems DRY solves.

I encounter people trying to establish standards and abstract patterns on the first pass of code...


Sports are good at distinguishing drills from practice. Practice is meant to look almost like real play. Drills are something you do so practice goes better, and to narrow your window of harm in practice.

I put, for instance, TDD in the drills category. I don’t think you should live in TDD. nor do I think you should avoid TDD because someone said they thought it wasn’t a viable lifestyle choice. You should do it for a while every six months or a year to knock the cobwebs off and remind you what sort of tests you’re going to need and write code that complements good tests, rather than fighting them.

DRY is a bit more complex. I think DRY in unit and integration tests is a slow death. Tests should be DAMP because requirements change, and so do languages, frameworks and libraries. DAMP avoids the sunk cost fallacy which I’ve seen nerd snipe too many people. Test isn’t useful anymore? Just delete it. Or replace it. Boom, done.


> Sports are good at distinguishing drills from practice

The military also. Individuals learn 'part task' drills (e.g. firing a tank gun), then practice them in a team environment (e.g. the different crew roles working together in a single tank) and then finally (in something fairly unique to the military) exercising collectively: multiple teams working together to achieve a common task. E.g. several tanks coordinating an attack, then adding in infantry, etc.


> 'part task' drills (e.g. firing a tank gun), then practice them in a team environment

Brought to mind "wax on, wax off" from the original Karate Kid movie.

https://thekaratekid.fandom.com/wiki/Wax_On,_Wax_Off


Definitely true, but probably easier to get nerds to rewatch Ted Lasso than Full Metal Jacket.


I’m not sure that would be my go to movie for military discipline and effective teamwork, but I’d sure watch it again.


DRY... Don't Repeat Yourself

DAMP... Do Always More Pasting


Hah!

Descriptive And Meaningful Prose

Just have your test say what it does. Don’t play code gold and get clever. Tests for different features should be able to die separately. No coupling.


'rule of 3s' is way too simplistic. It is on the beginner level. 3 is an arbitrary number anyway. It can be any other number depending on the situation. And creating an abstraction from only one use can be valid. In particular this happens if something gets a bit big while talking to too many other things. E.g., a function receives RPC while also doing something with a piece of hardware, and both of these things are a bit non-trivial. These two things should then not be mixed even when it is the only function doing these two things. I will say though, that creating an abstraction from one example one should expect that some future improvements to the abstraction will most likely be necessary.


I like to think of it as two intertwined rules:

  a concrete problem domain has an ideal solution with ideal abstractions for its purposes
  seek to understand your problem domain to a reasonable extent before writing hard-to-change code
Of course, we don't understand the problem domain perfectly from the start, and neither do we write perfect programs from the start. It's an iterative process of optimization, where you alternatively work on a specific understanding or work on the understanding. Everyone has to figure out that balance for themselves.


>'rule of 3s' is way too simplistic. It is on the beginner level. 3 is an arbitrary number anyway.

That's precisely why it's useful.

"On your discretion" would just lead to endless bikeshedding - as having a useful discretion requires that you are already advanced enough to not need such advice.

It's not that new devs really understand three to be some special number either: just a useful heuristic, which can be 2 or 4 or 5 if needed.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: