Live data from Hacker News

Goodbye, Clean Code

overreacted.io

311–320 of 599 posts

Re: Goodbye, Clean Code

#311

Earlier quoted context omitted.

The Rule of 3 is a great rule, except when it isn't. I had a colleague some time ago who wrote a couple of data importers for FAA airspace boundaries. There were two data feeds we cared about, "class airspace" and "special use airspace". These airspace feeds have nearly identical formats, with altitudes, detailed boundary definitions, and such. There are a few minor differences between the two, for example different…

The rule of 3 usually is in reference to small scoped abstractions, not whole modules or subsystems. We're talking about extracting a short function, not significant and potentially thorny chunks of code. But I guess no one explicitly spells this out, so I could see where someone could become confused.

Premature abstraction. Rule of 3 helps. But I found better principle for it:

Any abstraction MUST be designed to be as close as possible to be language-primitive-like. Language primitives are reliable, predictable, and non-breaking. If they do, they don't affect business logic written on top of it. If parameters are added, defaults are provided. They don't just abstract, they enable developers to express business logic more elegantly.

The challenge is to pick the part of the code abstractable to be primitive-like first and make it a top priority.

This is why language features like Rust async, Go channel-based comm, ES6, C++ smart pointer was such hype in their time and is used up until now. It also applies to enabling tools such as React, tokio, wasm-bindgen, express, TypeScript, jquery (even this which is not a thing anymore).

Re: Goodbye, Clean Code

#312
post #231

Earlier quoted context omitted.

One of the areas where I really like "incidental duplication" is in tests. Tests can sometimes be very repetitive and identical, and it's tempting to want to refactor it in some clever way. That's almost never good. On top of the reasons laid out in parent comment, tests also function as unofficial documentation. I like having everything explicit in there, it makes them easier to read and understand.

If you try to abstract away tests, you often just end up re-implementing the same abstractions used in the actual code, and you can end up not catching unfounded assumptions that your abstraction is making in both the tests and the code. There is a scope for having test helpers / utils to make tests easier to write, but you should be minimalist with these.

Tests should also be treated as a form of documentation. A test should reflect the way you'd use the code in real life as closely as feasible.

Re: Goodbye, Clean Code

#313

Earlier quoted context omitted.

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…

The Rule of 3 is a great rule, except when it isn't. I had a colleague some time ago who wrote a couple of data importers for FAA airspace boundaries. There were two data feeds we cared about, "class airspace" and "special use airspace". These airspace feeds have nearly identical formats, with altitudes, detailed boundary definitions, and such. There are a few minor differences between the two, for example different…

Any of these rules comes with "use your best judgement" and not drive off a cliff blindly following it.

Re: Goodbye, Clean Code

#314

> 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. I totally disagr…

> I also think that a salaried engineer who thinks that a piece of code he or she (but almost always he) wrote is "his" or "hers" is totally wrong

This. If some developer get offended when there is some issue in their code or the way it got implemented either they are not mature enough or there is a cultural issue in the team.

Re: Goodbye, Clean Code

#315
> Rewriting your teammate’s code without a discussion is a huge blow to your ability to effectively collaborate on a codebase together.

Debatable. Detachment to one's code is as important as being passionate in delivering requirements and enabling people with your code. A better approach: Anyone should objectively weigh the effect of a change whether it is communicated or not. If it turns out better, the change should be allowed for the sake of delivery, improvement, and knowledge sharing.

> My code traded the ability to change requirements for reduced duplication, and it was not a good trade.

An excellent point from danabramov. Premature abstraction is an ugly creature waiting to ambush you couple months in the future. By that time you'll forget why you did it in the first place and have written a lot on top of that abstraction.

I've been through a phase where juniors and intermediates (a lot of them) are obsessed with abstracting duplicated codes (not their fault, they were at the wrong place at the wrong time while receiving the principle that abstraction is always good).

I meditated for a while on it and found a principle to avoid this issue:

Any abstraction MUST be designed to be as close as possible to be language-primitive-like. Language primitives are reliable, predictable, and non-breaking. If they do, they don't affect business logic written on top of it. If parameters are added, defaults are provided. They don't just abstract, they enable developers to express business logic more elegantly.

The challenge is to pick the part of the code abstractable to be primitive-like first and make it a top priority.

This is why language features like Rust async, Go channel-based comm, ES6, C++ smart pointer was such hype in their time and is used up until now. It also applies to enabling tools such as React, tokio, wasm-bindgen, express, TypeScript, jquery (even this which is not a thing anymore).

Re: Goodbye, Clean Code

#316
TL;DR 1) We should not obsess with clean code, we can't agree on what clean code is.

2) We should also not write dirty code, we cant' agree on what dirty code exactly is (see all the counter examples)

There are few rules of thumbs that are always true with regards to code quality. Getting sucked in a job or argument where code-cleanliness is the no#1 metric and by distinction the "version" of clean code that your boss is telling you is a hellish way to make a living.

We can usually identify and agree on the two extremes: The very very very good code, and the very very very bad code... anything else and mostly all of us as coders are in the middle, and we would be more wise to focus on making the code work then chasing Zen-State-Of-Compilation-And-Code-Quality. It is useless when code exists ONLY to transform data... I've never bought a product based on code quality.

Re: Goodbye, Clean Code

#317
post #150

Earlier quoted context omitted.

Tests rarely have bugs, I find, so generally dry isn’t critical. Also, dry is for security (see below)

As a preventative measure, I write some tests for my tests. Also in TDD style of course. And on a very rare occasion, I have to write a test for those tests as well.

It’s time for TTDD. Start by writing tests for your tests :)

Re: Goodbye, Clean Code

#318

I don't use Ruby, and don't do OOP either, but my favourite talk is still Sandi Metz's "All The Little Things" and I think that's where she says "prefer duplication over the wrong abstraction." That's really changed me. I've since been seeing DRY and other misapplied dogma in a new light and have grown much over the years since.

*don't do _anymore_

Re: Goodbye, Clean Code

#319
It is interesting to see the parallels with my work with solid modeling in CAD. I'm constantly harping on the people I work with to think about what they are working on and structure it in a way that can be edited later (as well as stability). This often means a larger/less efficient feature tree, but it is actually maintainable. Just this week my insistence that we build the model to be flexible meant that we were able to fix something in 5 minutes instead of days.

Updating colleagues work without talking to them is something I often struggle with though. On one hand I absolutely hate it when others change my work without at least getting the history as to why I did it that way. Thus I try my very best to give others the courtesy of discussing it with them first. On the other hand, if something isn't being paid the proper attention, or they aren't making progress, sometimes it is a useful way to light a fire under certain people if asking politely hasn't worked.

Post reply on HN