How we effectively share and sync code between our Node.js microservices without compromising their independence or creating coupling, using Bit.
Lately, I’ve been hearing about the dangers of code sharing between microservices leading to coupling and maintenance overhead.
While there’s little doubt that code sharing can be very helpful, many teams are concerned about creating coupling between services via 3rd party libraries, and by corrupting specific business logics with over generalization.
I’d like to share from our own experience how we share and sync useful code between our services without hitting any of these pitfalls, using Bit.
The very idea of a microservices relies on better scalability, separation of concerns, resilience and development speed through better modularity.
This is exactly why coupling services together to an external shared-library undermines the reason we use microservices in the first place, as it couples their independent development to that of a 3rd party external library.
Shared libraries are also often bloated with all the features needed for every service, which in turn bloats the services themselves.
In our Node.js microservice architecture we share more than 250 (!) components of code between our services, without using a single library.
This becomes possible thanks to Bit- which turns “components” of code into building blocks that can be shared and developed from different projects.
Using Bit, you can share independent components between different services, make changes from any of them and keep all your changes tracked and synced across your codebase. No shared libraries, no coupling between services.
Let’s see an example.
Like for other teams, many of our services communicate with our user-service’s API to perform a user authentication for different purposes.
Before Bit, all of these services contained the same duplicated code that “talks” to our user-service. Making a change to this code would mean manually changing it in all our services, which is pretty arduous.
The things about Bit is that the shared code doesn’t actually live in it’s own separate repo, and no other services are coupled to that repo or its development. Instead, you can think of it as “manged copy-pasting” — where you can keep multiple instances of the code in different services, while Bit will track and sync changes between them (depending on your own update strategy). So- no coupling between services and they are not tied to any external library.
We used Bit to seamlessly isolate our
express/user-auth middleware directly from its source repository and share it to the cloud as a usable component.
From there, use install it as a package with NPM in different services such as
organizations and a few others.
Now comes the really awesome part: When we need to change this components, we can simply use Bit to import the code itself into any of these repositories, make the changes, and sync the update across our codebase.
We use Bit’s cloud hub to organize all our components into collections (called Scopes) that can sync changes between our services, and also make our components available to our entire team to find, use and develop.
This distributed workflow eliminates the coupling that shared-libs would create, and enable us to “manage our copy-pastes” between micro-services.
Well, first of all, publishing 250 or even 30 packages to NPM would require maintaining and making changes to 30 more repositories.
Even if we ignore the publish overhead itself, we find it much simpler to not keep dozens of extra repositories, but rather isolate components and share them directly between repos and projects (more about isolation and dependencies with Bit).
Second, we can make changes to the code from any of these repositories. Meaning, any team member can import the component’s source code into any of these repos, make changes, and Bit will be able to track and sync these changes across repositories.
You can even install the component as a package, and when a change is needed simply import it into the same repo, change it, and eject it back to being a package dependency when sharing it’s new version to the Scope, or as a new component into a different Scope (more about versioning with Bit).
This way, you don’t have to maintain or be coupled to the development of any additional repos and projects, the overhead of publish becomes nearly 0, and every component can be easily changed from any end repository.
Another problem I’ve heard teams concerned with is the generalization and reuse of code which is by nature specific to a certain service’s business logic.
First thing’s first, if the code is too specific- don’t share it. Shared code should be fit to share, and that’s really up to you to decide between them.
However, Bit’s workflow makes it possible to share code and evolve even code which would otherwise might be considered too “specific” to share.
For example let’s assume a piece of code that was written specifically for a certain service’s business logics, but can be modified for use in other services.
This becomes possible since Bit lets you very easily share this code without changing it in the origin service, and still make changes to your code from any other repository, and share the new version to a Scope of your own.
Much like with micro-organisms, this kind of distributed evolution breeds creation without compromising on perfectly fitting different use-cases.
Our own team has been using Bit to share and sync over 250 components of source code between our Node.js micro-services. We don’t use shared libraries for this code, and we don’t couple any of our services to an external project.
Every developer on our team can share, find and develop any of their components from any service or project they’re working on, so that code can be written once and evolved over time.
We have successfully scaled the numbers of our services and shared components while keeping maintenance simpler and development rapid.
Bit isn’t limited to Node.js components / modules, and can be used with any JS functionality such as UI components (React, Vue), util functions and more.