Don’t Choose the Wrong Abstraction When You DRY Your Codebase
“Don’t Repeat Yourself” (DRY) is a truism in software engineering, but it can cause headaches if you choose the wrong abstraction. Here’s what you need to know.
Essential Engineering Concepts: WET and DRY
Let’s imagine you’re building a data-driven frontend application that displays some tabular data next to a dynamic data visualization chart.
You’re familiar with DRY (“Don’t Repeat Yourself”), the software engineering mantra that encourages us to not copy-paste code.
But you’re also a realist, so you’re also familiar with WET (“Write Everything Twice”), meaning you write code and then refactor.
You’ve gotten to the point in building this app where you’re using a table component on 3 different pages, so you decide to refactor.
Your goal is a reusable <Table> component that is going to allow a user to select table rows using checkbox and graph that data in the charts.
I have a dire warning for you: don’t choose the wrong abstraction, or you’ll create many more headaches for yourself down the road.
Why You Don’t Want to Repeat Yourself: Copy-Pasta
You start working on refactoring out the <Table> component, and you end up with<Table>, <TableHeader>, <TableColumn>, and <TableRow>.
Everything’s going fine, and you pass a prop as a destructured object that allows the <Table> to support selecting checkboxes.
You’re looking at things, and you realize you need to make the app read the information from the <Table> and load it into the chart.
You make the appropriate connections, and you choose your abstraction: each <TableRow> keeps track of whether or not it’s been selected.
This works great, since you’re able to ask the chart to read the currently-selected rows from the <Table>. You implement it for all 3 pages.
You get a ticket to implement a 4th data type, and you’re super glad that you have the <Table>; you breeze through the code with minimal copy-pasta.
The Critical Problem When Not Repeating Yourself
Things have been going great at work, and you’ve been delivering features so fast that your manager compliments your velocity (coding speed).
You’re writing awesome pull requests (PRs) that get approved in record time, and you’re all smiles. You’re feeling like a WET and DRY pro!
Another agile sprint rolls around, and you catch a ticket to paginate the data. You use your <Table> abstraction and finish pagination quickly.
Things get merged, and you’re moving on to building another data visualization chart, when you get a call from another team member.
The team member shares her screen, and she shows you that pagination seems to be working great, except for one small issue: the charts.
When she selects a few table rows on the 1st page, the chart graphs the data as expected. But when she navigates to the 2nd page, it all gets cleared.
You say you’ll investigate it, so you make a ticket describing the bug. But, all of a sudden, you start to get a sinking feeling as you look into the code.
You chose to manage the selected data using <TableRow>, which worked great when the <Table> wasn’t paginated. But now it’s a huge issue!
Looking at the 4 charts you’ve built, you realize that there are 4 different types of data, and there’s no easy fix. You chose the wrong abstraction! 😱
The Wrong Abstraction Will Torpedo Productivity
Now imagine that your team’s a little dysfunctional, and you’re on a tight deadline to deliver all 8 required charts, even if they’re buggy.
You bring up the <Table> abstraction to your manager, but she takes a look at the sprint and decides that it has to be a “fix later” problem.
You’re a little frustrated, but she explains that the charts work fine as long as you aren’t trying to “multi-select” data across multiple pages.
Sure, you say, but we’re creating technical debt by ignoring this problem. She sighs and says, “I know. But we have to meet the deadline.”
You put on blinders and crank out the tickets. Your <Table> still works pretty great for building these new charts, and you make the deadline!
Your boss gives you and your team a chance to focus on this pagination issue, so you start to work on pulling the data out. It’s a nightmare.
You have to “lift state up” across 8 different pages, each with a different type of data, and reconnect the chart to work correctly on every page.
You realize, belatedly, that you should have waited to make <Table>, or at least you shouldn’t have depended on <TableRow> to handle array state.
The Moral: Be Careful When You Abstract Code
After a few weeks of pulling your teeth, you’re able to get back on track, and eventually you even refactor a reusable state management solution.
But by choosing the wrong abstraction in the first place, you ended up blocking multiple key features like sorting and searching the data.
Your gut tells you to blame that guy who did your PR review — he should have known better — but instead you decide to take extreme ownership.
When you have your quarterly 1:1 with your boss, you admit that the project’s delays were entirely your fault; you chose the wrong abstraction.
You really want to blame your boss for not letting you tackle the tech debt when you first identified the problem, but you don’t. You admit fault.
Your boss understands the situation, and she’s proud of you — you’re a clear leader for your colleagues, and not just because of your coding velocity.
More than anything else, she praises your ability to learn from your mistakes, since she knows you’ll choose a better abstraction next time.
And, best of all, she asks the CEO to give you a small bonus. It’s just a token, but it means the world to you. After all, you’re a WET and DRY pro!
Happy coding! 🧼
Dr. Derek Austin is the author of Career Programming: How You Can Become a Successful 6-Figure Programmer in 6 Months, now available on Amazon.






