Scalable levels of Code Reuse
Having been a part of various cross team code reuse conversations as a practice lead, here are my thoughts on architecting for sharing code between projects and teams.
There is the well understood (and maintained) concept of single purpose OSS libraries which you can find all over NPM and I personally write and maintain plenty of those. But beyond single purpose libraries is richer, multi objective code reuse. The current hot example is a component library.
There are few levels at which you can create such reusable code each with progressively more effort required by the core contributors. Before you decide which level you want to operate in, be sure that you will be allowed to provide support to prevent developer burnout, something that I’ve witnessed internally as well as externally all too commonly because of operating in the OSS movement for as long as I have.
Code reuse is a topic I’ve approached in the past as well. In that article, I approach it from an engineering management perspective. In this post however, I want to approach it from a developer perspective as it’s easy to let passion blindsight one from the consequences of their actions. Caveat emptor.
Base Level — Folder
Take even the simplest of UI applications, there will be some logic / UI that will be used multiple times in the project and probably in future projects. A simple example would be a button with particular styles.
The quickest solution is to move these pieces into folders dedicated for code reuse. This level code of sharing is something that you should always do. It provides benefits both to you and your team:
- UI logic keeps away from business logic.
- Single responsibility principle comes into play. You don’t want to be debugging buttons when you should be debugging page level issues etc.
- Helps discoverability even within the project. When building some new screen you can look for what is already done, so you don’t keep recreating the same pieces again and again.
Even though this is something to aspire towards, there are plenty of (if not most) UI projects (and backend ones too) that don’t find ways to isolate reusable sections out of business logic. If you manage to do it, good on you 🌹
Sustainable as individual — Template
You’ve built a project. Great job 👏🏼. Now you need to build the next project. Now would be a good time to take that re-useable folder and move it out into a template. A template is just a project you can use as a base (git clone) for the next project.
At this point you are now explicitly doing work that is not directly related to the task you are assigned to (building the next project). So, a few things would be required:
- Time to move this code out into a template.
- Probably clean some invalid imports.
- Write docs on how the template is organised.
- More docs on bootstrapping a new project with the template.
However these tasks are definitely scalable in terms of developer support. Because every new project starts with a clone:
- No one who clones your template has to stick with your tech choices.
- People contributing back (e.g. updating the dependencies like React) will not break the project you are actually working on (which will be another clone).
Once you done, you start saving on iteration zero of new projects 🌹
Giving someone access to your projects — Library
So you built a template. Good job, now you can get started with new projects quicker. The next step (and its a steep one so tread carefully) is to take the template, isolate the things that you are finding to be consistent across these new projects and move them into a library.
One thing to mention again right off that bat: You are doing multiple projects, you are validating stability with proven reuse — and reduced churn over time. Without this proof, moving it into a library will probably slow you down.
Additionally, there will be ongoing effort required (beyond that of a template):
- Each code change is considered a code change in your existing projects. The code change agent might not be aware of its impact on all the projects that rely on library. This means that changes will be done slowly.
- If you are depending on a library (instead of cloning from a template), any issues you find in the library mean that you have to fix it in the library. Additionally the simple task of applying the fix in the library (already a slow process) means that you have to update the version of the library used in your projects and action all the breaking changes that a version difference might introduce.
- A library is a dependency not just as a starting point but also in the future. If the library changes its direction, you projects will need to do the same.
- The tech choices made by the library must continue to be the tech choices in your project. You can diverge but then you will have a mix of library and project specific tech choices (e.g. you might end up with a mix state management frameworks, CSS-in-JS process etc).
- Makes on-boarding harder. New citizens to your project need to up-skill on the project as well as the library.
A library is definitely achievable, however it is a significant investment in terms of time (contributing, fixing, community building and knowledge sharing). The only way I’ve seen it succeed is with dedicated resources and understanding of complexity of the task you are undertaking 🌹.
Your problems are now my problem — Framework
The final step and the holy grail of code reuse is a framework. It takes as much of the choices (and burden) away from the users of the code as possible. It chooses to take responsibility of ensuring all the transient dependencies work, the different parts of the code are consistent and work together to provide a cohesive system. When done with a conscious effort of providing strong opinions and tech choices (are side effect of taking on the burden of tracking dependencies) a framework can greatly speed up delivery times for new projects.
Framework are intentionally limiting what you can do in your projects. They literally provide the frame that you need to stick to. While this can be limiting, it can also be a great driver for consistency. Breaking changes in external dependencies can many times be handled internally by the framework reducing per-project churn (of course if the project buys into the limitations and doesn’t go off the rails too much).
However, frameworks need the most amount of love, probably more (or at least equal to the projects that use it). In addition to the burdens of libraries there are additional responsibilities that come with a framework.
- Since projects will be limited by choices (and equally faster in delivery), the framework will need to ensure that the choices demonstrated are on top of modern trends and the right choice. Frameworks might need significant rework from time to time.
- Beyond the simple onboarding required for libraries, frameworks need further support and conversation around why certain things are disallowed, being open for expansion if they should be allowed, and educating on alternatives.
Frameworks are really something that can’t be done without continuous oversight, ensuring new ideas don’t go too far from the original frame 🌹
Finally there are a lot of libraries out there that claim to be loose about their opinion but come with strong dependencies. These libraries present themselves as opinion free, but still force you to use certain tech and yet avoid any responsibility (and burden) of keeping up to date with that tech. Stay away from those.
Also in the absence of any roadmap, long term project plan or support system in place, don’t take on libraries or frameworks as you are depending on a non-existent entity to provide you with support and guidance. A template is a more honest version of such libraries/frameworks: essentially stating the obvious — fork here and realise that you are responsible for its future 🌹.
If you enjoyed this post, give it a clap 👏🏼