This is a follow up to my earlier posts about the NuGet conversion project I’ve been working on. Since my last post, my team put out the initial version of the package and updated the rest of the system to reference it. This magnified some of the other existing problems with the system; there is lots of app code leftover in some older parts of the system that makes it more difficult to understand if all of the dependencies are resolving in a way that will work correctly.
My team ended up running into some diamond dependency problems regarding versions of the newtonsoft.json serializer. There were three different major versions of newtonsoft.json in the system. One was the newest version in its major version line, which also happened to be the newest major version. The larger development team already had a couple of versions in the GAC which caused some complications, since the application would pick up a version from the GAC that was not necessarily the one you expected. Since some versions of newtonsoft.json do not maintain semantic versioning, combining that versioning issue with the app code resulted in code that indicated it was correct at compile time but was when the app code went to compile at runtime, failed. Unfortunately, the portions of the application using app code were all older, and also had few unit tests associated with them, if any.
When the larger development team was using ilmerge they had been instructing it not to merge the newtonsoft.json dll, because it was assumed to be in the GAC. My team had debated adding the newer versions of newtonsoft.json to the GAC to work around that deployment issue, but decided instead that we wanted to get away from using the GAC altogether, and this seemed like as good place to start as any. Unfortunately, that meant that we had to add literally hundreds of copies of the newtonsoft.json dll to source control, since it keeps a working copy of all of the various services and batch jobs. Previously the larger development team had been acting like every developer had the entire running system locally. The long term modularization effort will invalidate this assumption. However, in the short term, we need to let each team understand their own dependencies as they move out of the larger monolith.
As a part of this project, we ended up pushing the upgrade to the newest version of newtonsoft.json to most of the application, since as we converted everyone to start consuming our package, they took on the package dependency on newtonsoft.json. We also spotted an odd change to how xml documents got serialized to json. Previously the xml elements <foo/> and <foo></foo> serialized to the same json content of foo:null but now <foo></foo> serializes to foo:””. It’s not a big change, but it’s hard to tell what that sort of things this will impact, given the test coverage challenges in parts of the application.
My team seems to have hit the end of the road with this package. While we’ve got more packages to create, we expect most of them to be less complex, since they are only used in tens of projects rather than hundreds and they also don’t pull in other third party dependencies. The whole ordeal turned out to be much more complex than we thought. While we reap some tangible benefits – like being able to control the release cadence of the package – now most of the benefits are still further down the line. The intangible benefit is that we find and get to confront all of this technical debt we accrued over the years and do something to modernize the older portions of the application.