Design – Is a common library a good idea

designgo

I've always thought that a "common library" was a good idea. By that I mean a library that contains the common functionality that is often needed by a few different applications. It results in less code duplication/redundancy.

I recently read an article (can't find now) that said this is actually a bad idea and went as far to say it was an "anti-pattern"

While there are upsides to this approach. Versioning and managing change means regression test for the suite of apps that use this library.

I'm kind of stuck in a rut for my new (Golang) project. Code deduplication has been hammered into me over the years but I feel like I should try it this time around.

While writing this, I am beginning to think that this "common lib" approach is the result of skimming on architecture? Perhaps my design needs more thought?

Interested to hear thoughts.

Best Answer

Libraries and re-use are absolutely a good thing. They have one giant downside, which is that if not carefully managed, they become the equivalent of the drawer in your kitchen that holds all of the odds and ends that don't go anywhere else.

I saw this in action when I became responsible for the first ports of an entire business unit's worth of code (mostly new to me) to 64-bit systems and doing a complete overhaul to our build and packaging, a lot of which was being done by hand and sometimes not very well.* We tended to build up what we shipped out of a stack of applications, where the client would say, "I'd like a system that does A, B, D and F, plus things M and N that you don't do yet and slightly different glue integrating them all." What all of it had in common was a junk-drawer library that had, over a couple of decades,** accumulated all of the things people thought should be re-usable. To make a long story short, a fraction of the code in the library wasn't used anywhere and was dragging a lot of dependencies into every project we shipped. We were expending a lot of valuable time building and maintaining those dependencies just so the common library would install, not because we actually needed them.

The moral is that libraries need to be treated like classes and not overloaded with too many responsibilities. Don't put your JSON parser in the same library with your linear algebra functions even if every program you're writing uses both.

Keeping them discrete has a lot of benefits, the biggest of which is that it forces your developers and packagers to come up with a detailed accounting of what their own products actually need instead of just including the junk drawer and the baggage that comes with it. When you set up a system using the built packages, the fine-grained dependencies ensure that only the necessary parts get installed. Even if you neglect your repository and continue compiling the old, crufty stuff, nothing that's no longer in use leaks into what you ship.

There are, of course, exceptions such as libc that cram a whole lot of functions into one library. That's one of the cases where the benefits to doing it that way can be reasoned out instead of blindly heeding the zealot down the hall who insists that any other way than X is always bad practice.


*In the process, I uncovered a binary that had been passed around and had not been recompiled from scratch in six years.

**There's nothing wrong with decades-old code. We had a number of critical algorithms that had been so well proven that we'd have been fools to rewrite them solely in the interest of modernity.