Executive summary: Consider a parallel replacement or supplement of a working system, rather than trying to make a hard to modify system work for a new task by modifying it. This can have huge payoffs, (and should always be considered for legacy systems).
I read a piece today that reminded me of a how a few key design principles tie together at much larger and more strategic ways than are intuitively obvious. They are really important for guiding IT and development teams, and unfortunately, traditional “it’s OK to be non-technical” administrative management completely misses this sort of approach, unless it is able to build a team that can do this and listens to that team. (This is very rare in my experience, as the same impulse to try to stay out of technical conversations builds teams that are focused on easy administration, rather than effectiveness!).
The key principles that have to be balanced are:
- Don’t repeat yourself (DRY)
- The Liskov substitution principle
- Create an abstraction layer
- The open/closed principle
- All of these principles must be balanced and applied at any level in a system (Dak’s Hypothesis)
It’s worth discovering or reading for yourself, too. Here’s a personal story about how this fits in with management and leadership. In a reboot startup of a technology solution, a truly terrific team that I helped restart and grow came up with the replacement idea, but at a larger scale. Instead of trying to fix a large subsystem of the product, three really sharp team members proposed to discard it, and re-implement just at the interface layer. This was brilliant, despite the fact that this meant “abandoning” about 70 person-years of effort; this is one of the easiest to explain examples of avoiding the “sunk cost fallacy” that I’ve seen. I embraced this enthusiastically, as I had seen this work at a much smaller scale, and we could prove that it would work by testing across the interface boundary. A change that would have taken us at least 6 weeks and 8 people was done in 2, by 2 people, more reliably, and with fewer defects (just one, actually, but that’s a story for another day). It also meant that we made a deadline for customer acceptance, and achieved another round of venture capital funding, so it was a complete win from every perspective.
If there’s just one thing that I see as most important for you to remember about this story, it is this: There’s always a creative and economic tension between “just fix it / refactor existing code / don’t repeat yourself” and “replace or duplicate it.” It’s critically important, in my experience, to understand the complexity, execution and maintenance costs of each of these choices, and not make decisions using these as slogans; they need to be thought through in some detail. Take your time, write down the decision and justifications, and publish that. Reflect on those decisions, every few decisions, and see what has worked, and what hasn’t. This is a powerful tool for better decision making, influence, and culture change.
A directly related concept, which I mention here as another way of remembering and applying this, is touched on by an old joke: “There are two hard things in Computer Science: naming, caching, and off by one errors.” Naming is hard, and abstractions require names. If the name is odd, hard to remember, or seems convoluted…you should think about whether or not it’s a good abstraction. The answer should be “no” from time to time, and that’s OK. If the answer is always “yes, I just need a better name,” then you and your team are making mistakes, because not all abstractions are good (or should live forever). Remember that you can undo these mistakes by refactoring abstractions, or by factoring abstractions out, as well.
[If it is helpful, I will add links for key concepts in the above, based on reader feedback]
Here’s the piece by Sandi Metz on when to duplicate (or re-implement) objects or classes. This is something that Bertrand Meyer first wrote about in “Object-Oriented Software Construction” as the Open/Closed principle way back in 1988; it was a really great book at the time, and it helped guide my design practices…leading to being open to doing this for much larger solutions, as I mention, above.
‘I’ve been thinking about the consequences of the “wrong abstraction.” My
RailsConf 2014 “all the little things” talk included a section where I asserted:
> duplication is far cheaper than the wrong abstraction’
And in the summary, I went on to advise:
> prefer duplication over the wrong abstraction