3 Steps to DRY
Ryan Silva Aug 30 '17
Don’t Repeat Yourself: it’s a crucial refrain to remember. Avoiding repetition in your codebase saves development time and improves maintainability, but getting there isn’t always easy. Repetition can come in many forms, from a copy/pasted low level function to multiple similar UI components with separate implementations. I’ll focus on the latter as I present three steps that help me DRY.
1. There Is No Pattern
Before obsessing about DRY, don’t forget its counterpart, YAGNI: Ya Ain’t Gonna Need It. The quest for DRY can lead to over-engineering: added complexity to handle a pattern that never emerges. While smart engineering is always flexible, be wary of adding large costs to enable reuse if you think that reuse may never happen.
2. Establish a Pattern
If there is a pattern in the system, let it emerge. How long you wait depends on your team and your system, but always actively encourage design details that move the overall design towards one that can be abstractly implemented. This also ensures a consistent experience for your users.
3. Code the Pattern
Once a pattern has been established, code the pattern. Don’t wait too long! At this point the cost of creating a reusable component has obvious benefits, and you want to take advantage of that benefit when the next feature comes along. If you wait too long, you pay double the cost: the initial cost of repeating yourself, and the cost of refactoring it later.
Case Study: “Category Table”
A few years ago I started a new application and I needed a table-like component with rows representing categories that expanded to reveal a form. There were a few of these tables, but all different. I wrote CSS that could be reused between the tables, but I didn’t attempt to write a single component for these “category tables”. I knew that the design was in flux and that making it generic enough would introduce a lot of complexity.
Eventually it became clear that we would use this category table in many places. So when new features were designed using a variant of the table, I ensured that the new iterations were consistent with requirements of the old tables, laying the foundation for a reusable implementation.