Jonathan Saring

@JonathanSaring

5 Practical Ways To Share Code: From NPM To Lerna, Git Submodules and Bit

November 26th 2017

Between multiple repositories, monorepos and micro-services the discussion about sharing common code between projects is increasingly raging.

Sharing common code between projects and repositories is a key factor for better modularity and faster development, but it’s also complicated. I’ve written about it before, sharing from our own experience as a team.

Here is a practical overview of 5 methods for sharing code between these repos and projects for 2018. Just remember, down the line it’s really all about communication between people, culture and keeping modularity in mind.

1. Bit

Bit brings newfound Simplicity and Scalability to code-sharing, as your entire team can collaborate and easily share code between projects.

It’s an open source project and a component-platform which together helps teams turn reusable code units into shared-components.

Bit lets you automatically isolate reusable from any of your JS projects, with an automated dependency deception and resolution mechanism. This helps Bit make the component reusable, with zero refactoring needed.

Then, you can reuse the component from other projects (with NPM/ Yarn or Bit itself), and even develop and sync changes between different repositories.

The “magic” lies in the fact that Bit doesn’t just handle packages; it handles source code components across different projects. This means it can isolate, update and sync components anywhere- so you can share more code at ease.

Bit also provides discoverability and collaboration for the components you share, which are organized in visual collections in the platform with per-component testing, build, visual rendering and more.

Here is an example React project and a matching collection of components.

The “downside” of Bit is that in order to install code with the NPM / Yarn client you will have to configure the open Bit hub as a Scoped registry.

2. NPM with / without Lerna

Sindre Sorhus with 1000 NPM packages

NPM is an amazing thing that happened to JavaScript, opening the door for code reuse and collaboration around reusable modules and libraries. With all the complaints about this ecosystem, we couldn’t imagine life without it.

As you probably know all about NPM, let’s focus on a few limitations and how to overcome them. Making smart choices from the get-go saves time later.

Dan Abramov favors many modules

First, it can be hard to setup and maintain many repositories for many packages. For this reason, some projects are built as multi-package repositories, also known as “monorepos”. Tools like Bit and Lerna (see below) can help you turn projects into multi-package repos, you can learn more here.

This also leads many teams to choose shared-libraries as a solution for sharing many smaller components (see below), as it’s hard to have a package for each.

Second, when someone else publishes a package you are limited in your ability to develop it, often leading to a pull-request to the packages’ repo. Tools like Bit help mitigate this problem, as it lets you bring the component right into any repo, make changes and share a new version.

Third, there is a discoverability problem as you scale. It’s hard to find and choose from many small packages, which leads to wiki sites and long docs. Rollup’s author Rich Harris wrote:

“Many blog posts — scratch that, entire websites — have been created to try and mitigate the difficulty of finding what you need on npm…”
It’s up to you to evaluate the library: does it have tests? Can you understand the source code? Is it actively maintained? Is the documentation easy to find and consult?

Lerna

The Hydra from Lerna: Looking at its tail, I think it’s about to fall down

Keeping different packages in different repositories can quickly get out of hand and make it very hard to update changes across your projects.

Lerna helps you to keep and configure multiple packages in a single repository. It can help mitigate the pain of different repos for different packages, and help build and test the project as a whole. This way, you don’t have to keep and maintain separate repos for different packages.

To learn more about going monorepo check this out:

3. Shared and common libraries

The advantage of shared-libs is that you keep all your shared code in one repo, which is easier to maintain and distribute than multiple micro-packages. However, unlike Lerna monorepos, they will be consumed as one package.

Keeping all your shared code in one repo forces users to add the entire library to their project with redundant code, dependencies, complexity and weight, all to use a single component.

A React MaterialUI button component — do I really need a whole library?

It also makes the process of updates and modification very cumbersome, as every change requires the owner of the project to update the package. This can impair the adoption of these libraries within organization. Discoverability for different components within the library is also an issue.

These problems led communities such as Lodash to work long and hard in order to publish their components as individual packages to NPM. Google’s Polymer project (by Eric Bidelman and other OSS wizards) also keeps over 100 web elements in over different 100 repositories.

Lerna can be used to separate components within the library into packages within the repo. Bit can be used to share components from existing libraries.

Example:

4. Git sub-modules

Git is the SCM of choice for most dev-teams. It allows you to put one repository as a subdirectory of another repository, creating a single working-tree for the entire project, and one project can use code from another project.

Lessons learned in the trenches?

There are various problems with Git’s submodules. First, they only work on master branch. Second, submodules create highly coupled code between the various projects and make it hard to merge and collaborate on cross-repo tasks. A submodule repo also has no idea that it is nested, and might have a dependent repo.

There are various tools that provide additional automation around the Submodule feature, such as git-subtree, gitslave, braid and giternal. These tools try to improve some of the usability issues of Submodules, but are not supported by a specific vendor and have different drawbacks.

5. Copy-pasting code

Because let’s face it, what did future me ever do for me?
When your teammate yells YOLO and goes rouge

To be honest, it is perhaps the most commonly used practice for code “reuse” on earth. I’d like to think that in most cases it’s the result of the lack of a “cheap” effective alternative and somewhat chaotic delivery cycles.

The problem is, code duplications are not cheap at all. Far from it.

A classic problem for future me.

Duplications are an ever-growing debt in your code base. You will quickly lose control, making maintenance a nightmare and delivery cycles ever longer. Many problems will only be discovered after delivered to production.

A recent study found that half the code on GitHub is duplicated. Our research found that a Javascript function like is-string was duplicated over 1,000 duplications of 100 different implementations in only 10k GitHub repos.

Think about the new features that could have been written if more people would share code, rather than duplicate or reimplement it. Think about the costs of maintenance and long delivery cycles for your organization.

Sharing code is about people

Each project and every developer has their own set of concerns, tools and workflows. Still, sharing code is the key to true modularity, which becomes increasingly popular in todays’s ecosystem and provides great advantages.

We chose to build Bit. No matter what method and tooling you choose, it’s important to encourage a culture that breeds sharing and collaboration.

After all, sharing between projects starts with sharing between people.

More by Jonathan Saring

More Related Stories