Building on top of software
As a developer in 2021, it’s hard to build something useful without using someone else’s code. Why re-invent the wheel? After all, even the standard libraries coming with various programming languages are written by someone else. Similarly, standard libraries also use lower-level OS code(written by someone else), and so on. This is a normal process, software is built on top of other software. However, it should be a mindful process, by thinking ahead/long-term about the consequences and possible technical debts.
As a developer, part of taking ownership in a project means knowing each dependency of the project and why the project needs it. Thinking about and answering these questions before adding another library in your project usually helps:
- Can I easily implement this myself? (remember leftPad)
- Is it alive and well maintained?
- How big is it? (this is especially important for front-end)
- Is the API good and easy to follow?
Implement or adopt — is a bit tricky. I like the saying “The best code is the code not written”, because, the less code you write, the fewer ways for the bugs to pop up, but if it’s something so trivial, up to a couple of hours of work, one should consider implementing it themselves(if the demo’s not tomorrow :)).
One must make sure not to underestimate it though, remember that a well-adopted library is battle-tested. So it’s not only the code you write there, it’s also testing, corner cases, performance, real-world usage, and so on. The devil’s in the details and the community likely came with a working solution long before you. Underestimation is a lifelong problem for developers. I still underestimate complexity after more than 10 years of professional development experience.
Maintenance — The world is constantly changing, so must the software. Stagnant water quickly goes bad. This is especially important with products, as they keep growing and evolving.
The most important thing to check is the community behind the library, it must be vibrant and alive. One must check when was the last release(if this goes in years it’s a red flag). An exception to this is some algorithm implementation i.e. cryptographic, math, sorting algorithms, etc.
One must also check if it’s a one-developer library (highly risky). If the developer loses interest and abandons it, you’re locking your project to dead code and any future found issues in the library means diving deep into the abandoned code and resurrecting the library yourself.
A scenario I’ve encountered with abandoned libraries is locking on transitive dependencies(a transitive dependency is a dependency of one of your project’s dependencies). Consider the following example: your project depends on foo-1.0 —an abandoned library after some time, which uses bar-1.0 — actively developed. Say that your project also directly uses bar-1.0 — the active one.
After some time, bar-2.0 is released— with many advances, features and performance improvements, but is not completely backwards compatible. Because foo-1.0 is using bar-1.0, you’re locked and cannot upgrade to bar-2.0 until you get rid of foo-1.0 or do the upgrade and release a new foo version that is compatible with bar-2.0.
This is one of the technical debts my team had to pay quite a bit, but there are many other problems that could arise with conflicting dependencies, so if interested, you can read more about dependency hell.
For Java, for some well-used Java libraries, developers put so much effort to make them backwards compatible, which is great, but this is not usually the case, especially in JavaScript.
Size — Sometimes libraries are more than we need. For the backends, it’s usually acceptable, but for front-ends, it can be critical (slow mobile connections or SEO optimizations). Sometimes we can workaround, but one must be aware of the bundle/package size at all times. Extraction sometimes can work, but it should be avoided, as at that point you’re taking ownership over that code, hence you need to take care about its future(think about future updates/fixes on the library you extracted from)
Library API — A typical product developer spends half the time reading other’s people’s code, so adding a weird or hard-to-follow API in your code will make your or your fellow developer’s life difficult. Usually, good libraries have good APIs. If the developers did not care enough to make a good and easy-to-use API for their library, it’s usually a red flag.