To library, or not to library

To library,  or not to library

A huge fucking question.

I know I normally focus on OO stuff... and I wish I had more OO crap to ponder... but there's nothing really sticking in head recently... soo... other shit. I want to try and go weekly... I'm gonna slip to monthly though.
This isn't my main deal, but I like to share.

Let's talk Libraries. Or packages, or nuget, or some form of shared or distributed code.

I'm in C# land, so I'll stick to this eco-systems terms and tools. When I'm talking about a Library, I tend to mean a project in a solution that produces a DLL for something else to consume.
This CAN be turned into a nuget package, but doesn't have to be. Which is kinda the point of this post.

Before I jump into a library, why do we want a library?
Code reuse? No.

Code Reuse

I take code reuse to mean that an object in the project can be REUSED to facilitate the creation of additional behavior in the system. This is code reuse. A library is not code reuse. We're not "reusing" code, we're using a library.  Similar, yet significantly different. Mostly in the "I can change my code, the library is static".

If not code reuse, what else?
Maintainability? Not entirely.


I argue that the maintainability cost of a library is higher. Changes to the library are going to have broader impacts and require a lot more verification before calling it good to go.

Fine - why? (mostly because I primarily hear these two reasons).


We should library-ify code when the readability of the code in the solution is improved by doing so.
Yes - improved readabilty is improved maintainability - but these are different reasons to do something. I distinguish between them.

At work, we had to mad dash to create some functionality for a badly planned waterfall project. Our team doesn't do waterfall, but no one else could do the work so we got pulled in.
This was done on the tail end of an experiment to see how it felt to copy and paste code into each Azure Function project instead of trying to create an abstraction. It wasn't doing the copy and paste. Some small tweaks happened here and there showing that code hadn't stabilized yet - but over all wasn't too terrible.

Then this project hit. A 1/2 dozen almost identical projects with JUST enough variation we didn't abstract. We have a 1/2 dozen classes named "Notification" in the same solution.
The code is a PAIN to navigate.

We have small variations in almost every class, which is why I am FINE with what we've done. Trying to work all of this into a single abstraction as we went along would have been frustrating. We have a really good picture of what areas change, and what abstractions need to exist.

We will still have a bunch of duplicate code, but primarily as Knowledge Classes.

A knowledge class is a class implementing an abstract class to provide concrete instances for ctor arguments.

This is very small duplication, and tends to be things that are specific to the project. In this case, it's a Cosmos Database and Collection. It COULD be in the shared project, and maybe it'll move there... but it's also OK duplicated in each AzureFunction project.
Some of the projects touch multiple collections, and EVERY project doesn't need to have those classes, so... let's shove them all into the executed projects.


I'm rambling here. It's been a few months and some pretty hefty debates about when and why and how to move from copy/paste code across projects to turning it into a library.

Even not, refactoring the code into a library requires small modifications to make everything work together. It's the small tweaks each individual project made as we wrote each one. It improved, so we need to generalize those improvements a smidge more than we had.

I like the approach, and it's made it clear that multiple executable projects should not copy/paste code. It's a killer for readability. Yeah, a bug fix in one needs to be done a few places... or does it? If it's not seen in the other ones is it a bug in them?
Once things are abstracted, yeah, you can get that for free; but it doesn't mean it was needed for all of the projects.

Anyway... Once you create a library in your solution... what if something else needs that?
We're abstracting our base cosmosdb interactions. This is DEFINITELY common across most of my teams projects... How do we share this new abstraction across multiple solutions?


Not NuGet

Do not nuget-ize something because it's useful to be shared. That's... going to make life hell. Every team I've seen take that approach has 2 things happen.
Usually nuget packages eventually want to become a circular reference, which it can do, and then you're stuck trying to unravel that or encounter strange HARD to repro bugs. That's my biggest concern of the "NUGET ALL THE THINGS" approach - you'll become circular and may not know it.
The secondary, and the fix to becoming circular is you have a few independent packages, like a logger, or a CosmosLib, and then an "everything else" package. To avoid the "A needs B, and B needs A" you... don't avoid it, you stick them in the same nuget package.

Then it's a dumping ground, and it's hell.

One of the hellscape reasons is change is nearly impossible. If anything can depend on the thing you're changing; and you don't want to break anything... it's SUPER careful work. And validation. And finding users. And helping users when you ended up breaking it anyway...
Code becomes archaic and crufty and hard to understand or work. Each new need is slapped in and kept 'distinct' to not risk breaking existing users.

Yes - it can all be avoided with proper time, tests, and dedication - which... when in a rush... Not happening. Let's not pretend the real world doesn't impact how we update "the team nuget packages".

Updating it - What if it doesn't do what you want? Do you go update the nuget package to add the functionality you need... or do you just write your own so you don't need to bother with the overhead?
We skip the bother.

Copy And Paste

As I do with a few files, once a Library shows it's value to be in multiple solutions, copy and paste that sucker around.

If you are REALLY concerned about "how do we get updates into older solutions" ... create a repo, and do a sub-module... or sub-tree... or whatever "sub" aspect your source control does. But check the code INTO the existing project. The build machine shouldn't have to pull it down separately.

Much like when I get to a point that files copy/paste between projects no longer get modified, when a project no longer gets tweaks THEN I start to CONSIDER it for a nuget package.

This is a HARD sell for me. I don't like lots of random packages scattered about. Especially if not team limited. I'd rather build it, and copy/paste a dll into the project than make a nuget package too early.

I don't see nuget as a way to bundle code to share. It's extra steps and hassle if that shared code changes. I don't want that headache or concern about making a change. I've worked on projects that had a lot of "packages" and when I have to work in 4 different code bases to add a new feature... there's something wrong with how things are put together.

NuGet is for libraries that are generalized enough to use without modification. If you need to modify it; you shouldn't have nugetized it.


I don't actually have much to post right now. No backlog or nothin... so... Rambling.

Show Comments