June 17, 2018

On 3rd Party Libraries

Good Morning,

One of those things, oftentimes preached in the coding community is code reuse. Ideally a problem should be solved exactly once. Everybody who has the same problem, should use this one implementation and contribute to it if changes are necessary.1 There are three main points backing up this idea:

The Good

  • Less development time, because large parts of an application can be made of existing code.
  • Libraries are used and worked on by many developers, so they should have good code quality and should be well tested.
  • Less maintenance, because libraries get maintained by others.

In addition, it is often recommended to concentrate on open source libraries. The reason being, that one can access, change or even fork the library if necessary. Open source is a whole different topic, I do not want to go into right now. Just keep in mind that open source is not only upsides either.

I have been a firm believer of the idea of code reuse for many years. And I do think, that you should write and package your own code in a reusable manner and create a set of high quality in-house libraries to be used in any of your applications.

When it comes to 3rd party libraries, though, I have over time found several disadvantages, which I want to bring to your attention.

The Bad

  • Do you know all those 425 libraries?Any library of decent size has a learning curve. Typically, the library is initially used in a wrong way, maybe even against its design. And it leads to bad application design, and in some bad cases even to the addition of more libraries solving the same problem. No one will want to maintain this code.
  • Libraries often get "plugged together" in a more or less random way. Using 3rd party libraries requires special attention to the architecture and the correct inclusion of those libraries into an application. As architecture is a huge issue in many applications, anyways, gluing together a bunch of libraries can only make it worse.
  • Most libraries offer way more features than we actually require. You might say: "What's so bad about having more features than we need?". Well, those features are overhead. Code we have to deliver to the customer without them needing it. They lead to a greater learning curve because we are required to understand all those features to be able to decide whether to use them or not.
  • And then there are those pesky developers; in my experience, any feature available, will be used at some point. This is especially contra productive when we believe a feature to be a bad idea. Let me give you an example:
    I am a huge friend of dependency injection. As far as .NET goes, there are various good libraries out there, LightInjectNinjectAutofac, etc. But I have rolled my own.2 Why?
    Well, I believe that dependency injection requires a very clear statement about the dependencies a class requires. And this statement is best given in the form of a constructor which enforces the provision of all necessary dependencies. I thus want to use constructor injection only. All those libraries I quoted, allow for property injection. This is nice for the developer, because less code is needed. The downside is that I can create and use an object without filling in all properties. Do you want to account, in every single method, for the possibility that your required dependencies are not there? I don't! That's why my DI-container only supports constructor injection, nothing more, nothing less.
  • We usually find (or stumble upon) some use cases the library does not account for. To solve this, we typically add to it. This is done with wrappers, custom derivatives, extension methods and so on. While this does not at first sound too bad, I have found most of these cases to lead to extremely bad code and architecture.
    The problem is, that we don't choose a library we expect to not have the features we need.3 So when we do find a missing feature, we are usually stumped and in a hurry to get it implemented. What makes it even worse is, that many libraries are not exactly built to be easily extended from the outside.4 While they work fine for what they are designed to do, they often fail when asked to do more.
    This is where the open source argument comes in. Just add the feature and contribute to the library. But does that not defeat our goals? When I use a 3rd party library, I want to rid myself of the responsibility to extend and maintain it. I don't want to understand it's code, I want it to just work. What I certainly do not want is, that I have to get my hands dirty implementing additional features into or even forking the library.

The Ugly

You ask me "What now? Should I be using 3rd party libraries or not?". My answer is a firm and ascertaining "It depends". As all things in live, there is no easy answer, no one right way. What I can offer you is this: Let us consider some questions one should ask themselves before using a 3rd party library:

  1. Do you believe you can write a maintainable, well tested, reusable piece of software that solves the problem at hand? If the answer is "No", don't even bother. Invest your time into finding the best library out there, that fits your needs.
  2. Do you know a library (from deep experience working with it) that fits the bill? If you or one of your more advanced developers know such a library, go for it.5
  3. Do you think (as opposed to "know") there is a library that would solve your problem? This is where it gets complicated. Find out everything there is about the library. Try it out, test it to the core. Try to consider all use cases you may run into (especially those you do not want to run into). And pay extra attention to the correct use of the library in your application.
  4. If none of the above are true, meaning that you cannot find a library that solves your problem, the learning curve is too steep and you get a headache thinking of all those library features, that you do not want to have in your application. Then, you should consider rolling your own. But as always, make it reusable for yourself. Implement automatic tests. Pay special attention to the interface and architecture in general. Your libraries should have an even higher code standard than your applications!

Whenever you use 3rd party libraries, you must only consider those, that are "a safe bet". Make sure the license is acceptable, that it is well maintained and actively developed by a decently sized group, that the code is of high quality and well tested. And do not look at the price.6 A library usually is a lifetime investment, as far as the application using it is concerned. Never choose the "viable alternative" over the "perfect match" because it is free. Those decision will come back to haunt you tenfold in your maintenance budget.

I hope I could give you some pointers as to the selection of 3rd party libraries. Do not make hasty decisions. Think it through, find the best answer you can, and stick with it. And I am sure you will be successful with your decision.

  1. This is, of course, not possible as there are always multiple ways to solve a complex problem, none of which are perfect. The goal still stands, though.
  2. Which you can find at https://github.com/programmersdigest/Injector
  3. Although we should! Do not expect any library to meet all your needs. Think ahead. Implement ways to add functionality before you need it. It will be worth it quicker than you may think.
  4. I'm looking at you, Microsoft, with your sealed classes.
  5. Of course you should still check it, test it and so on. But having a developer who knows your needs well, whose advice you trust, who has lots of experience with the library in question and will most certainly stay in your team for a long time to come, is a pretty good start.
  6. This argument is to be seen in the context of a company. If you are a private developer, the price may absolutely affect your decision (it does for me). But then again, the investment into a library and the risks attached to a wrong decision are not as high as they are for a company with tens or even hundreds of employees working on the application in question.