Frontend devs, I’d love to get your thoughts on this 👇 Recently, I’ve been working on two frontend projects that share very similar components. In an ideal world, we’d extract them into a shared component library to improve consistency and reduce duplication. However, due to tight timelines, we chose to allow some intentional duplication and move forward without fully abstracting them (at least for now). This made me curious how others usually handle this kind of situation: 🎈Do you build a lightweight shared layer even under time pressure? 🎈Or do you intentionally accept some duplication as a trade-off? (like me) I’d love to hear how you balance delivery speed vs. long-term maintainability in real-world frontend projects! #webdevelopment #react #javascript
My approach for that is to start small. Common components are no longer only a card, input fields and styled texts, most of the time you are not using react in a vacuum and reusing boilerplate code can save you a few hours of work, but it tends to build debt when the codebase is no longer a few months old. I recently worked on a migration of a project that used tanstack for state management on http requests. If I have to spend a few more days making sure that my peers could access a documented component with proper abstraction, that's something i tend to do because, as I said, a project is rarely built with a standalone framework and, most importantly, you are not writing code for you alone. Standards and reliability is key.
I accept intentional duplication under time pressure, but keep components clean and consistent so they’re easy to extract later. Premature abstraction often costs more than it saves. Ship first, validate patterns, then create a shared library once usage stabilizes.
My 2 cents: If you continue with duplication due to time frames, I fall back to documenting what I've done for later improvement or correction. I am a firm believer in "improving overtime". Of course, documentation should follow a solid framework (and not just comment "fix later"😂). Something along the lines of: What is this doing, why did we do this, how does it relate to or impact other components / layers, and what is the work we will do to improve this? This way other developers can also work on it!
Hindsight is great, so I'll go with that first...when said component was being considered for the first project, I would have looked at if from a future flexibility perspective, and determined if the basic functionality could ever be re-used. In which I would have built it from within the shared library from the start, allowing it to grow and be customised by consuming projects. Outside of hindsight, I read another comment about wrong abstraction being worse than no abstraction. I see where that point it going...and even in tight deadlines, I would be inclined to abstract...
If you abstract things too early it can cause unnecessary effort keeping things in sync, it’s tempting to think that in the long run it will pay off. Until you reach that point (if ever) you won’t know. The shadcn registry is an interesting approach. There is a repo of components that can be installed, but the code is source code, so you can shape it to the needs of the repo consuming it, very flexible. If I was to decide to abstract components, I’d choose this option.
I usually lean toward building a very lightweight shared layer, even under time pressure. Not a full design system just minimal abstractions for truly reusable components. It helps keep consistency and avoids duplicating bugs, while still moving fast. For anything still evolving or highly contextual, I’m okay with intentional duplication. The key for me is being deliberate about the trade-off and having a clear path to refactor later.
for me, If the deadline is tight, I’ll still build a shared component (at least the basic one). It’s extra work at the start, but it helps a lot long-term since you avoid duplicating changes and bug fixes across projects. I normally keep it minimal first, then refactor and expand later.
Thank goodness we don’t live in an ideal world. You made the right call by intentionally accepting some duplication especially for short term and with a tight deadline. Long term if you’re up for it with no deadline, you can create this shared layer. But then again by that time…..it would be “If it works don’t touch it, right?”
I call this the “identical twin” or “dual lane” method where you have two components that are pretty much the same in every way, both delivering the same thing but one may be a little faster than the other. I think it’s fine if it remains “twins” meaning just two. But when you have a moment of hot steamy passion with the wife and end up making three or four… then you’re begging for a crazy house. In that realm though, try your best to avoid dual lane components and if you do duplicate, naming conventions are important. Don’t do mainNav and then have mainNavB. I try to include an abbreviated summary to the new file like mainNav_sideBar or simply _alt. Alt always meaning the second version as a means to never allow three or four. This is one reason why I love Vue.js because you can add your v-if or v-show stuff based upon props… meaning you can have your two, three or four iterations of that component within a single file. I know react has it but it’s less impressive on the HTML side. But it does work as conditional rendering. This makes your component more accessible and adaptable to what you need.