For work, I was recently asked to evaluate a few different 3rd party libraries. After a few days of research, I ultimately rejected all of them. When asked why, I wrote up a document about all the things I look for when I’m evaluating whether or not to implement a library. A coworker of mine then encouraged me to type it up for this blog.
There are plenty of reasons why you may want to use a 3rd party library to implement a piece of work. Maybe you have a small team and you really need to get a complex feature done quicker. Maybe you don’t want to solve a problem that’s already been solved and open sourced for consumption. Or maybe your designer just loves the look of MBProgressHUD.
In any case, it’s important to know what you’re putting into your application &em; especially when it goes wrong. Below are some examples when my choice in library has either worked out or gone terribly wrong. I’ve excluded the names of the libraries to not shame the hard work of my peers. Instead I’ll give a small blurb about what problem we were trying to solve by including it.
// Framework Size
Every byte that a framework takes up is a byte that we make our users pay for, with their data, when downloading the app for the first time or when updating to a new version. In order to keep the burden on a user’s data plan to a minimum, we should try to find the slimmest libraries possible. If we don’t, we’re accepting that we don’t care about our users or the cost of our apps to them.
Case study: Framework A (393 KB) vs Framework B (227.8 MB)
Framework A is a popular framework to aid with networking calls. Framework B is a library that aids the user in collecting data.
An app I helped build used approximately 30% of Framework A’s functionality to perform all networking tasks. The ratio of size to usefulness is acceptable because we gain a key piece of functionality for a relative low cost to the user. Obviously it would be better if we used closer to 100%. However, it’s an acceptable compromise given how small and light weight Framework A is.
Whereas the app used approximately 50% of Framework B’s functionality once per new member. This library is used to guide the user through collecting some information. This is a large library that we make every user download, every time, regardless of whether or not they use its functionality. You could have been a user for years and are downloading the new update. Still you have to download this bloated library. While 50% is a decent number, it’s still a very large package that the user would have to spend their data downloading whether or not they use it.
// Framework Support
If we’re going to base portions of our apps on 3rd party libraries, it’s important that they are well support by the developer(s). The reason being, should a developer introduce a bug and then stop supporting the library, or refuse to fix the bug, we are left to either fix it ourselves or create our own version of the library (if the library is open source). If the library is not open source, we’re left with a known issue that we cannot fix. It is also important that when a bug is found it is quickly resolved by the developer(s). Otherwise we’re left at the mercy of the library owner to decide when our users are no longer effected by the bug.
Case study: Framework A vs Framework C
Framework A is the same networking library from above. Framework C is a fairly popular library that lets the user perform some navigation with swipes.
The team I was on determined that Framework A, a networking library, was an acceptable 3rd party library because of its level of support. It is an open source project that has become an industry standard. Which means that, when a bug is reported, several thousand developers are notified and a fix is often made quickly. This is especially important as my team and I planned to remain on the latest version of Swift – so our libraries will need to be ready and updated when we upgrade Swift versions.
Whereas my team found an issue with Framework C. When we reported the issue the developer was not interested in fixing it. Because the library was built into a core part of the visual architecture, my team elected to fork Framework C’s repo, make the necessary fix, and use that fork to import the library. This is dangerous because the developer who made the fork is no longer on my team. So we are reliant on them never deleting their forked version of that library. And should another problem arise with the library, we have no way to have the issue fixed unless we fork their fork or they’re more kind than the original developer.
// Framework Stability
Perhaps the largest concern is around the stability of the framework. If the framework introduces crashes its usefulness becomes moot, in my opinion. Including a library that crashes your app, with any frequency, is an incredible disservice to your users. Therefore making sure a library has a good release history, with minimal reverts or crash fixes, is an important factor when evaluating a library.
Case study: Framework A vs Framework D
(if you haven’t noticed yet, I’m a big fan of Framework A)Framework A is the same networking library from above. Framework D is a library for tracking in app events.
There have been less than a handful of times that Framework A has introduced a crashing bug. Each time a fix was released in a couple hours to days with a fully documented cause/resolution. They rarely introduce issues because of Framework A’s wide reach and expansive test suite.
Whereas, when looking through their release history, Framework B constantly introduces crashes (often at launch) which results in reverts instead of fixes. It is worth noting that, even if they revert their crash, you would need to do a release and hope your users upgrade to an unaffected version of your app.
// Additional Concerns
There is an additional the concern of compromising the integrity of existing code architecture in order to support/use a framework. This can often result in a “square peg in a round hole” scenario where the app will either crash or behave in unexpected ways. This can add an overhead to integrating a library if major rewrites are required to support the library.
Given the above qualities and examples, it’s important to weigh the potential risks of including a library against the time it would take to develop a solution yourself. The questions I often ask are:
- How long would it take me to write this myself?
- How much of the package solves my problem?
- Does another, smaller, package solve the same problem?
- What’s the cost, to the app and the team, if this package stops being supported?
- What’s the potential risk to the app should this package stop working in a deployed version of the app?
- How does this library stack up against our standards?