package-ecosystems/src/counts.md

48 lines
5.1 KiB
Markdown

# 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](https://nuget.org/) and [Crates.io](https://crates.io/). Some years ago, [NPM](https://npmjs.org/) 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](https://en.wikipedia.org/wiki/Goodhart%27s_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](https://en.wikipedia.org/wiki/Don%27t_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](https://www.nuget.org/packages/Microsoft.Extensions.Logging) and Rust's [log](https://docs.rs/log/0.4.6/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.