Live data from Hacker News

Write code that is easy to delete, not easy to extend (2016)

programmingisterrible.com

81–90 of 102 posts

Re: Write code that is easy to delete, not easy to extend (2016)

#81
post #19

My favorite saying: “simple is robust” Similar in spirit to Lehman’s Law of Continuing Change[0], the idea is that the less complexity a system has, the easier it is to change. Rather than plan for the future with extensible code, plan for the future with straightforward code. E.g. only abstract when the situation requires it, encourage simple duplication, use monoliths up front, scale vertically before horizontally,…

> encourage simple duplication A rule I like to follow: - first time: write it - second time: copy it - third time: maybe refactor it

All such rules seem designed for a person not engaging their brain.

Is this "the same" thing? If so - extract and reference. Or is it "a different" thing which is superficially similar? Then don't.

Knowing when two things are one thing or one thing is two things is most of our job, right?

Re: Write code that is easy to delete, not easy to extend (2016)

#82

Pretty wild that none of this talks about testing or observability. Tests are also something that you need to pay to maintain, but they give the ability of reducing the risk that you broke something when you removed it. Additionally when you've exposed your service to potential external callers you need to both have a robust way of marking some calls as deprecated, to be deleted as well as observing whether they are…

This is going to be a bit of an oversimplification but when you build things that are easy to delete, then you’re not going to cause unintentional bugs when you delete them. It’s once you over complicate things that everything becomes an interconnected mess where developers don’t know what sort of impact changes will have. There are a lot of ways to fuck this up of course. Maybe you’re following some silly “best practice” principle, maybe you’re doing “micro-services” in a manner where you don’t actually know who/what consumes which service. But then you’ve not build things that are easy to delete.

I think external consumption as you frame it is a good example of this. It’s fair to give consumers a reasonable warning about the depreciation of a service, but if you can’t actually shut it off when you want to, then you’ve not designed your system to let things be easily deleted.

Which is fair. If that works for you, then so things that way. I suspect it may not work too well if you’re relying on tests and observations to tell you if things are breaking. Not that I have anything against tests, but it’s not exactly a great safe-guard if you have to let them tell you if you broke something in a long complicated chain. Not least because you’re extremely unlikely to have test-coverage which will actually protect you.

Re: Write code that is easy to delete, not easy to extend (2016)

#83
post #81
post #19

Earlier quoted context omitted.

> encourage simple duplication A rule I like to follow: - first time: write it - second time: copy it - third time: maybe refactor it

All such rules seem designed for a person not engaging their brain. Is this "the same" thing? If so - extract and reference. Or is it "a different" thing which is superficially similar? Then don't. Knowing when two things are one thing or one thing is two things is most of our job, right?

DRY is a terrible, terrible, principle because it’s correct but requires programmers to make this decision. Which they won’t because DRY has thought them that all duplication is bad. The flip-side is what you’re saying, where there are simply things it wouldn’t make sense to duplicate. I’m a strong advocate against basically every Clean Code principle, really anything, which isn’t YAGNI. That doesn’t mean I think you should create datetime services every time you need them. It doesn’t mean I don’t think you should make a “base” audit mixin/abstract when you want to add “created_at”… to your data model in your API.

I think a better way to look at it than “third time - consider refactor” is to follow this article and ask “will this ever need to be extended?”. If the answer is yes, then you should duplicate it.

This way you won’t get a flying dog in your OOP hellscape but you also won’t have to change your holiday service 9 million places when your shitty government decides to remove one of them (thanks Denmark). Between the two, I would personally prefer working on the one where I have to do the 9 million changes, but I would obviously prefer neither.

Re: Write code that is easy to delete, not easy to extend (2016)

#84

My favorite saying: “simple is robust” Similar in spirit to Lehman’s Law of Continuing Change[0], the idea is that the less complexity a system has, the easier it is to change. Rather than plan for the future with extensible code, plan for the future with straightforward code. E.g. only abstract when the situation requires it, encourage simple duplication, use monoliths up front, scale vertically before horizontally,…

You can't wish the complexity of business logic away. If it is vast and interconnected, then so is the code.

Re: Write code that is easy to delete, not easy to extend (2016)

#85

Pretty wild that none of this talks about testing or observability. Tests are also something that you need to pay to maintain, but they give the ability of reducing the risk that you broke something when you removed it. Additionally when you've exposed your service to potential external callers you need to both have a robust way of marking some calls as deprecated, to be deleted as well as observing whether they are…

Tests are great, but there’s more to programming than writing tests. People don’t have to mention tests in every article.

Re: Write code that is easy to delete, not easy to extend (2016)

#86

Earlier quoted context omitted.

I am not sure that is something that applies 100%, but I understand the concern. It is my understanding that we should try to build solutions to current problems, and be open to future use cases that could involve small additions in functionality. It would be stupid to design an unmodifiable system just because some parts can be deleted and we are not sure what future needs are. Code should always be easy to extend,…

Conversations like this are always difficult to discuss at a high level because the way we implement the words we use can be very different. Code can be written in a way that a lot of complexity is added in order to make it extensible, or it can be written in a way where simplification is used to make it extensible. Both authors would agree that extensible is good.

That is an excellent and pragmatic point of view.

Re: Write code that is easy to delete, not easy to extend (2016)

#87
post #19

Earlier quoted context omitted.

> encourage simple duplication A rule I like to follow: - first time: write it - second time: copy it - third time: maybe refactor it

Agreed! I'll usually go one step further for early projects and lean towards 3rd time copy, 4th time refactor. Example: So much early code is boilerplate CRUD, that it's tempting to abstract it. 9 times out of 10, you'll create a quasi-ORM that starts inheriting business logic and quickly grows omni-functions. Eventually you may actually need this layer, assuming you're system miraculously scales to needing multiple…

It’s so easy to accidentally write an ORM or a database. I constantly stop and think; is this piece of code secretly a database?

Re: Write code that is easy to delete, not easy to extend (2016)

#88
Personally, I split code into two parts. The business logic and actually implementation. The business logic may be duplicated due to its nature, but it should not have too many duplicated technical details in it. While the business logic can be as shitty as you want as long as you do not handle business logic directly in it and keep it application independent. In that way. If you know things messed up and don't go too well. You have the option to wipe the implementation as a whole instead of forced to fix it and try to find out the actual spec from implementation.

Re: Write code that is easy to delete, not easy to extend (2016)

#89
post #57
post #37

Earlier quoted context omitted.

Failing to account for this gives you Wayland (which at this time is more complex than X11)

Is it actually more complex? I find it more understandable, it’s just that DEs need to write their own compositors.

X11 has plenty of warts, but Wayland has more.

Example: screenshot. X11: "please tell me the pixels in the root window". Wayland: "please tell me the extension number of the portals extension so I can open a portal to pipewire so I can get the pipewire connection string so I can connect to the pipewire server so I can ..."

Example: get window position on screen.

Example: set window title.

X11 is a protocol about managing windows on a screen. Wayland is a protocol about sending pixel buffers to an unspecified destination. All the screen-related stuff, which is integral to X11, is hard to do in Wayland with a pile of optional extensions and external protocol servers which do not interact.

X11 is also more standardized, de facto, because there are fewer server implementations, which is not just an accident but is by design.

Re: Write code that is easy to delete, not easy to extend (2016)

#90
post #89
post #57

Earlier quoted context omitted.

Is it actually more complex? I find it more understandable, it’s just that DEs need to write their own compositors.

X11 has plenty of warts, but Wayland has more. Example: screenshot. X11: "please tell me the pixels in the root window". Wayland: "please tell me the extension number of the portals extension so I can open a portal to pipewire so I can get the pipewire connection string so I can connect to the pipewire server so I can ..." Example: get window position on screen. Example: set window title. X11 is a protocol about mana…

X11 is far more inclined towards the idea of clean separation of policy and mechanism, which I think is becoming more and more evidently correct across the board of programming. When you start talking about libraries and layers, a policy/mechanism split is part of how to write layered code correctly:

base mechanisms that interpret the raw problem correctly (e.g. pixels on a screen, mouse position) -> some policy that is in some ways mechanism with slightly more abstraction (e.g. drawing shapes) -> some more policy-mechanism abstraction (e.g. windows) ...

until you get to your desired layer of abstraction to work at. This goes along with modularity, composition, code reuse. X11 itself has many design flaws, but Wayland's design is untenable.

Post reply on HN