If you were a chef at an upscale Michelin-starred restaurant, would you buy vegetables and meat from random, unverified sources? The cost of almost any average project is measured in hundreds of thousands or even millions of dollars. I believe that our industry should have the same approach as restaurants.
The first question to ask yourself right away: do you really need a new dependency? Could the problem be solved using the current environment, such as the language or installed libraries? For example, there's no need to install an additional library to generate UUIDs. Node.js and browsers support it out of the box: crypto.randomUUID()
The second question: do you need the entire library? For instance, if you only need a dropdown, is it worth installing something like Bootstrap? Perhaps it's better to limit yourself to a single, focused library with an unstyled dropdown component from Radix UI?
Okay. We have a few candidates in mind. So, how do we choose the right one?
A beautifully formatted README? A well-known name? More forks, stars, and downloads than others? Unfortunately, these factors alone aren't enough. Here, we are selecting a service provider. We want any issues that arise to be resolved quickly, the functionality to remain up-to-date, and, above all, for the service to be safe and reliable. Simple external metrics don't always indicate the quality or long-term suitability. Before installing what we've found on the repository catalog, it would be great to visit the GitHub repository and analyze its content.
I have prepared a list of criteria that I have been using for the last few years. I hope they will help you choose the most suitable libraries. It's essential to consider them comprehensively and, in some cases, make compromises when choosing between them.
Disclaimer: I am not criticizing the libraries mentioned below or trying to discourage their use. In some instances, I have intentionally omitted names to focus on the criterion example while maintaining factual accuracy.
1. Security
How safe is it to use? It may sound like fiction, but yes, dependencies can be dangerous. For example, an interesting feature was added to a library with 500k downloads: it tries to replace all files on the computer with ❤️ if your IP address falls within a specific range.
An interesting fact is that this dependency was used in vue-cli.
How can we discover such issues? Check the issues page, or try googling by the library's name. Usually, such information surfaces quickly. Also, Snyk can be used as an automated tool for security checks.
2. Maintenance
When was the last release? How often do releases occur? Regular releases ensure that issues are resolved and updates support constantly changing technologies. In the context of mobile development, regular releases also ensure that the project compiles successfully.
Here's an example from the world of Go: the authors of a library with 18.2K stars decided to stop maintaining their dependency and archived it. This means that, in a few years, the lack of support and updates will become a problem. Now imagine installing a similar dependency without checking GitHub first. It's sort of checking the expiration date of products.
Here is an example of frequent good releases:
3. Open / Closed Issues
1. What is the ratio of open issues to closed ones? How willing are the authors to accept changes? It's possible that you might need to contribute something someday. For instance, this library is quite popular and has a 98% percentage of closed issues. Only 18 are open.
2. How quickly are critical issues resolved? Once, I chose an ORM with 31k stars, but at some point, we encountered a problem that blocked us. We had to look for workarounds and eventually switch to another solution. Unfortunately, almost four years have passed, and the problem still hasn't been resolved.
Such issues can be identified by sorting by the most commented.
3. Has the contribution process been organized by the creators? Is there a clear, defined workflow in place? For example, the creators of Next.js even recorded a 40-minute video about their contribution process.
4. Code Quality
Yes, there may be a lot of code, but it's always possible to examine its different parts. How is the project organized? Is it understandable, and well-structured, and do good practices apply? The worse the code is written, the higher the likelihood of the project's demise in the future. Many small candidates were eliminated at this stage for me.
5. Test Coverage
Does the library have tests? What is the test coverage? How were the tests written? Even if maintainers review merge requests, there is a chance that something may be overlooked. There are a lot of different people contribute to the library. Normally, test coverage information is displayed on badges at the top of the repository. However, if it is not, we can always search for tests in the project. For instance, the formatjs
library family has excellent test coverage and includes various types of tests.
6. Library Size
Mobile applications often have large dependency sizes and the whole app can be even more than 200MB, which can cause issues during cellular network downloads and consume a lot of storage space. This is especially problematic for front-end CSR apps, where slow internet speeds can dramatically increase loading times.
For web projects, there is a great tool to determine package sizes: Bundlephobia. Of course, server-side rendering and tree shaking might reduce the size, but this needs to be always verified.
A popular example is date manipulation libraries. The functionality provided by dayjs (2.9KB) might be sufficient, eliminating the need to install moment.js (72.1KB) or date-fns (26.8KB).
7. Number of Dependencies
All the points listed above are multiplied, to some extent, by the number of dependencies in the entire dependency tree of the project. A great tool to check the complete dependency tree: https://npm.anvaka.com
8. License
Have you ever thought about this? I hadn't either. For example, the MIT and Apache 2.0 licenses allow for the free use of libraries in commercial projects, while some GPL v2 licenses have specific requirements and restrictions. In one of our projects, we had a table prepared by a lawyer to check all our dependency tree's licenses. So if you see something unusual in a license, it's better to consult a lawyer to avoid problems during an audit. We can extract all licenses from existing npm dependencies using the legally utility or the same tool mentioned above in the previous point.
P.S. I'm not a lawyer, and this wasn't legal advice. It's a rare and specialized case that something might not be suitable due to the license, but it's still possible.
The End!
Thank you for reading my article! The key point of it was to show real-world examples that shallow and fast decision-making sometimes can lead not to the best option. By considering these criteria, you will be able to make a more informed decision.
Please feel free to leave any comments or suggestions you may have. Don't hesitate to share your experience in the comments as well. Your likes and comments inspire me to write new articles. Happy cooking :)
Top comments (0)