Repeat yourself, do more than one thing, and... — programming is terrible


76 bookmarks. First posted by nicferrier august 2018.


If you ask a programmer for advice—a terrible idea—they might tell you something like the following: Don’t repeat yourself. Programs should do one thing and one thing well. Never rewrite your code from scratch, ever!.

Following “Don’t Repeat Yourself” might lead you to a function with four boolean flags, and a matrix of behaviours to carefully navigate when changing the code. Splitting things up into simple units can lead to awkward composition and struggling to coordinate cross cutting changes. Avoiding rewrites means they’re often left so late that they have no chance of succeeding.

The advice isn’t inherently bad—although there is good intent, following it to the letter can create more problems than it promises to solve.

Sometimes the best way to follow an adage is to do the exact opposite: embrace feature switches and constantly rewrite your code, pull things together to make coordination between them easier to manage, and repeat yourself to avoid implementing everything in one function..



Repeat yourself, but don’t repeat other people’s hard work. Repeat yourself: duplicate to find the right abstraction first, then deduplicate to implement it.

With “Don’t Repeat Yourself”, some insist that it isn’t about avoiding duplication of code, but about avoiding duplication of functionality or duplication of responsibility. This is more popularly known as the “Single Responsibility Principle”, and it’s just as easily mishandled.



Gather responsibilities to simplify interactions between them

The only real difference between pushing something together and pulling something apart is that some changes become easier to perform than others.

The choice between a monolith and microservices is another example of this—the choice between developing and deploying a single service, or composing things out of smaller, independently developed services.

The big difference between them is that cross-cutting change is easier in one, and local changes are easier in the other. Which one works best for a team often depends more on environmental factors than on the specific changes being made.

Although a monolith can be painful when new features need to be added and microservices can be painful when co-ordination is required, a monolith can run smoothly with feature flags and short lived branches and microservices work well when deployment is easy and heavily automated.



Modularity is more than reducing things to their smallest parts.

A layer of small components with no shared features creates a need for a layer above where these features overlap, and if absent, the user will create one, with bash aliases, scripts, or even spreadsheets to copy-paste from.

Even adding this layer might not help you: git already has a notion of user-facing and automation-facing commands, and the UI is still a mess. It’s always easier to add a new flag to an existing command than to it is to duplicate it and maintain it in parallel.

Similarly, functions gain boolean flags and classes gain new methods as the needs of the codebase change. In trying to avoid duplication and keep code together, we end up entangling things.

Although components can be created with a single responsibility, over time their responsibilities will change and interact in new and unexpected ways. What a module is currently responsible for within a system does not necessarily correlate to how it will grow.



Modularity is about limiting the options for growth

A given module often gets changed because it is the easiest module to change, rather than the best place for the change to be made. In the end, what defines a module is what pieces of the system it will never responsible for, rather what it is currently responsible for.



This means recognizing which bits are slightly more entangled than others, knowing which pieces need to talk to each other, which need to share resources, what shares responsibilities, and most importantly, what external constraints are in place and which way they are moving.

In the end, it’s about optimizing for those changes—and this is rarely achieved by aiming for reusable code, as sometimes handling changes means rewriting everything.



Rewrite Everything

The reason rewrites are so risky in practice is that replacing one working system with another is rarely an overnight change. We rarely understand what the previous system did—many of its properties are accidental in nature. Documentation is scarce, tests are ornamental, and interfaces are organic in nature, stubbornly locking behaviors in place.

If migrating to the replacement depends on switching over everything at once, make sure you’ve booked a holiday during the transition, well in advance.

Successful rewrites plan for migration to and from the old system, plan to ease in the existing load, and plan to handle things being in one or both places at once. Both systems are continuously maintained until one of them can be decommissioned. A slow, careful migration is the only option that reliably works on larger systems.



The reason we say “Never Rewrite Code” is that we leave rewrites too late, demand too much, and expect them to work immediately. It’s more important to never rewrite in a hurry than to never rewrite at all.



null is true, everything is permitted

The problem with following advice to the letter is that it rarely works in practice. The problem with following it at all costs is that eventually we cannot afford to do so.

It isn’t “Don’t Repeat Yourself”, but “Some redundancy is healthy, some isn’t”, and using abstractions when you’re sure you want to couple things together.

It isn’t “Each thing has a unique component”, or other variants of the single responsibility principle, but “Decoupling parts into smaller pieces is often worth it if the interfaces are simple between them, and try to keep the fast changing and tricky to implement bits away from each other”.

It’s never “Don’t Rewrite!”, but “Don’t abandon what works”. Build a plan for migration, maintain in parallel, then decommission, eventually. In high-growth situations you can probably put off decommissioning, and possibly even migrations.
dry  srp  programming  bestpractices  refactoring  maintenance  modularity  onethingwell 
7 weeks ago by cdzombak
Repeat yourself, do more than one thing, and rewrite everything If you ask a programmer for advice—a terrible idea—they might tell you something like the following: Don’t repeat yourself. Programs...
programming 
8 weeks ago by geetarista
If you ask a programmer for advice—a terrible idea—they might tell you something like the following: Don’t repeat yourself. Programs should do one thing and one thing well. Never rewrite your code from scratch, ever! [...] The advice isn’t inherently bad—although there is good intent, following it to the letter can create more problems than it promises to solve.
programming 
9 weeks ago by epochblue
2018-08-05 If you ask a programmer for advice—a terrible idea—they might tell you something like the following: Don’t repeat yourself. Programs should do one…
from instapaper
september 2018 by iany
programming is terrible
Programmieren  Blog  Text 
september 2018 by derjan
If you ask a programmer for advice—a terrible idea—they might tell you something like the following: Don’t repeat yourself. Programs should do one thing and one thing well. Never rewrite your code from scratch, ever!.
devops 
september 2018 by muhh
"Usually, a rewrite is only a practical option when it’s the only option left. Technical debt, or code the seniors wrote that we can’t be rude about, accrues until all change becomes hazardous. It is only when the system is at breaking point that a rewrite is even considered an option. Sometimes the reasons can be less dramatic: an API is being switched off, a startup has taken a beautiful journey, or there’s a new fashion in town and orders from the top to chase it. Rewrites can happen to appease a programmer too—rewarding good teamwork with a solo project."
a:Thomas-Edward-Figg★  p:Programming-Is-Terrible★  d:2018.08.05  w:2500  instructional  programming  software-design  software-development  from instapaper
august 2018 by bankbryan
The problem with always using an abstraction is that you’re preemptively guessing which parts of the codebase need to change together. “Don’t Repeat Yourself” will lead to a rigid, tightly coupled mess of code. Repeating yourself is the best way to discover which abstractions, if any, you actually need.

As Sandi Metz put it, “duplication is far cheaper than the wrong abstraction”.
programming  abstraction  bestpractices  software_engineering  software_architecture  development  inspiration  advice  from instapaper
august 2018 by andrewsardone
As Sandi Metz put it, “duplication is far cheaper than the wrong abstraction”.

You can’t really write a re-usable abstraction up front. Most successful libraries or frameworks are extracted from a larger working system, rather than being created from scratch. If you haven’t built something useful with your library yet, it is unlikely anyone else will. Code reuse isn’t a good excuse to avoid duplicating code, and writing reusable code inside your project is often a form of preemptive optimization.

When it comes to repeating yourself inside your own project, the point isn’t to be able to reuse code, but rather to make coordinated changes. Use abstractions when you’re sure about coupling things together, rather than for opportunistic or accidental code reuse—it’s ok to repeat yourself to find out when.
software-development  cultural-norms  refactoring  advice  to-write-about 
august 2018 by Vaguery
2018-08-05 Repeat yourself, do more than one thing, and rewrite everything If you ask a programmer for advice—a terrible idea—they might tell you something like…
from instapaper
august 2018 by wjbr
Repeat yourself, do more than one thing, and rewrite everything
If you ask a programmer for advice—a terrible idea—they might tell you something like the following: Don’t repeat yourself. Programs should do one thing and one thing well. Never rewrite your code from scratch, ever!.

Following “Don’t Repeat Yourself” might lead you to a function with four boolean flags, and a matrix of behaviours to carefully navigate when changing the code. Splitting things up into simple units can lead to awkward composition and struggling to coordinate cross cutting changes. Avoiding rewrites means they’re often left so late that they have no chance of succeeding.

The advice isn’t inherently bad—although there is good intent, following it to the letter can create more problems than it promises to solve.

Sometimes the best way to follow an adage is to do the exact opposite: embrace feature switches and constantly rewrite your code, pull things together to make coordination between them easier to manage, and repeat yourself to avoid implementing everything in one function..

This advice is much harder to follow, unfortunately.
advice  prog  blog 
august 2018 by kmt
You can’t really write a re-usable abstraction up front. Most successful libraries or frameworks are extracted from a larger working system, rather than being created from scratch. If you haven’t built something useful with your library yet, it is unlikely anyone else will. Code reuse isn’t a good excuse to avoid duplicating code, and writing reusable code inside your project is often a form of preemptive optimization.
august 2018 by nexuapex
'As Sandi Metz put it, “duplication is far cheaper than the wrong abstraction”.' <-- this is the best programming advice ever
programming 
august 2018 by aparrish
Invoking the ‘single responsibility principle’, programmers have been known to brutally decompose software into a terrifyingly large number of small interlocking pieces—a craft rarely seen outside of obscenely expensive watches, or bash.
programming  advice 
august 2018 by wholewheattoast
repeat yourself, do more than one thing, and rewrite everything!
august 2018 by kurver
In the end, we call our good decisions ‘clean code’ and our bad decisions ‘technical debt’, despite following the same rules and practices to get there.
code  advice  programming 
august 2018 by tedw
The problem with always using an abstraction is that you’re preemptively guessing which parts of the codebase need to change together. “Don’t Repeat Yourself” will lead to a rigid, tightly coupled mess of code. Repeating yourself is the best way to discover which abstractions, if any, you actually need.
[…]
although one class might do two things in a rather nasty way, disentangling it isn’t of much benefit when you end up with two nasty classes with a far more complex mess of wiring between them.
[…]
Technical debt, or code the seniors wrote that we can’t be rude about, accrues until all change becomes hazardous. It is only when the system is at breaking point that a rewrite is even considered an option.
[…]
In the end, we call our good decisions ‘clean code’ and our bad decisions ‘technical debt’, despite following the same rules and practices to get there.
nützlich  Meinungen  Projektmanagement  Entwicklung  Programmierung  tested  Konzeption 
august 2018 by Stolzenhain
2018-08-05 If you ask a programmer for advice—a terrible idea—they might tell you something like the following: Don’t repeat yourself. Programs should do one…
from instapaper
august 2018 by badboy
2018-08-05 Repeat yourself, do more than one thing, and rewrite everything If you ask a programmer for advice—a terrible idea—they might tell you something like…
instapaper 
august 2018 by ckolderup
2018-08-05 If you ask a programmer for advice—a terrible idea—they might tell you something like the following: Don’t repeat yourself. Programs should do one…
from instapaper
august 2018 by aviflax
RT : repeat yourself, do more than one thing, and rewrite everything!
from twitter_favs
august 2018 by briantrice
RT : There’s some truth to this , but the problem it attributes to DRY isn’t inherent.

If you ha…
from twitter
august 2018 by orta
RT : repeat yourself, do more than one thing, and rewrite everything!
from twitter
august 2018 by mjr5749
If you ask a programmer for advice—a terrible idea—they might tell you something like the following...
p:programming-is-terrible  a:tef  2018-08-06  abstractions  advice  arch  architecture  code-design  code  craft  development  dry  microservices  modularity  programming  refactor  refactoring  reliability  software-design  structure  style  sweng  thought-provoking  tips  wham 
august 2018 by andrewjbates
- Don't Repeat Yourself
-- Can lead to rigid, tightly coupled mess of code.
-- duplication is far cheaper than the wrong abstraction
-- Create abstractions for things that change together
- Modularity
-- Are booleans a sign of code that maybe we have reduced too much?
-- Modules are often changed because they are the easiest to change, not because they are the best place to make the change.
- Rewrite Everything
-- We rarely understand the previous system, and many of its properties are accidental.
-- If a replacement isn't doing anything useful after three months, odds are it will never do anything useful.

"In the end, we call our good decisions ‘clean code’ and our bad decisions ‘technical debt’, despite following the same rules and practices to get there."
august 2018 by aesterline
repeat yourself, do more than one thing, and rewrite everything!
from twitter_favs
august 2018 by nicferrier
repeat yourself, do more than one thing, and rewrite everything!
from twitter_favs
august 2018 by indirect
repeat yourself, do more than one thing, and rewrite everything!
from twitter_favs
august 2018 by moderation
repeat yourself, do more than one thing, and rewrite everything!
from twitter_favs
august 2018 by mike_moran
repeat yourself, do more than one thing, and rewrite everything!
from twitter_favs
august 2018 by feltnerm