Package Counts

If you look at just about any feed site, usually one of the first things listed is the number of packages. You can see it on NuGet and Crates.io. Some years ago, NPM used to have it but it's been taken off since I noticed it.

The number of packages is a selling point for developers. It makes a large number to indicate the vitality of an ecosystem or the general excitement of the language.

The problem is those counts are an example of Goodhart's Law:

When a measure becomes a target, it ceases to be a good measure.

With self-serve feeds, the number of packages is unbounded and functions less of an indication of a thriving system and more of a simple function of time. There are a number of reasons for this, most of them predictable.

What the package counts try to sell is the number of “high quality” packages, ones that provide additional functionality or extend services. That is more difficult to quantify, simply because “quality” is subjective.

Don't Repeat Yourself (DRY)

We have a term for writing the same code over and over again, Don't Repeat Yourself which is why we end up creating packages when the language fails to provide them.

Almost every language comes with a “base library” of features. It might be included or is baked into the language. For systems that provide relatively few functions, developers end up creating packages to support it.

Probably the most famous would be left-pad which just added space or zero padding to a string in JavaScript. The key part is that JavaScript didn't, until recently, provide a way of doing left pad easily. So it would be up to developers to create their own. This means there were various that used loops with buffers next to implementations that concatenated strings with substring.

Not Invented Here (NIH)

There are two aspects of Not Invented Here. The first are developers who want a favored tool or library but in a new language. This is things like log4net, log4perl, and log4r. They have their place but as the derivative library evolves with the language, it deviates from the source materials. Knowing log4j doesn't mean you know all the details of log4net.

Some languages try to consolidate that by providing an “official” method of common functionality. A good example is Microsoft.Extensions.Logging and Rust's log crate (log isn't officially, but it came in close enough that it is effectively such).

From my experiences, providing those official interfaces near the beginning have a significant impact in reducing the number of packages. Rust still has a number of logging libraries, but almost all of them funnel through the log crate abstraction.

Base or Standard Libraries

There are some arguments that languages should provide more as part of their base or standard library. Delphi, .NET Framework, and Java have rather extensive BCLs which significantly reduce the number of packages.

However, there is also a drawback to this approach. A BCL is a foundation of a library, functionality that cannot disappear on a whim or even over a ten year period for a mature language. It creates a resistance to change and increases the maintenance for the language itself.

A good example is java.awt (Abstract Window Toolkit). Almost everything uses Swing since Java 1.2 but the AWT remains in the language as a legacy library. It has to be maintained much like the .NET Framework's various System.* packages have to be maintained.

Near to my heart was WebForms in the .NET Framework. I support a WebForms project and it is intimately tied into the BCL and the language. So when WebForms didn't move to .NET Core, I'm left with a product that is nearly impossible to keep with evolution.

I don't think we have a good word for these libraries, but the extension libraries (ECL) work well when they are implemented by the core language but are not integrate to the language and have a well defined life cycle even if the life cycle is “currently recommended with no end-of-life in sight.”

Reinventing the Wheel (RTW)

In my early (okay, still) development career, I suffer from a need to reinvent the wheel. I wrote at least three command-line parsing libraries that worked the way “I want” or did the features I wanted. It took a conscious effort to focus on an existing one, even if it failed in some manner. That is why I used CommandLineParser in C# for so many years and then eventually gravitated to System.CommandLine (despite both of them being still fluid).

As developers, we create endless copies of our version. I made MfGames.Templates to take ideas from WebForms and JSP pages to make a string templating system that let me write C# code. Now, we have Razor pages that do the same thing. But I still took the months to make it because it was a puzzle, it was fun, and I liked making it. If NuGet was around at the time, I would have no doubt have pushed it up in hopes someone would use it.