About a year ago, I wrote and released a library that buttons to the top of AutoMapper, an object mapping library written by Jimmy Bogard and one of the most popular NuGet packages out there. It's called AutoMapper.Attributes and its basic idea was to be able to define simple mappings using C#/VB.NET attributes. It was meant as a kind of a toy library, but I released it and have been pleasantly surprised at how folks have reacted to it, to the tune of over 25,000 downloads in two years - not too shabby if I do say so myself!
The best way to test software you've written is to dogfood it, so I did what any normal developer did and used it both at work and in personal projects. It worked for a while... that is, until it didn't.
lol and what is that
— Jimmy Bogard (@jbogard) December 1, 2017
Glad you asked, Jimmy!
As I started using it more and more, I slowly came to the realization that the library itself is an anti-pattern. The idea of it is completely flawed, and here's why.
Fact One: Mapping is hard.
Unless the object maps are very simple (and if you're mapping, they almost never are), attributes do a very poor job of capturing the nuance of many mapping use cases.
Fact (really, opinion) Two: Maps should be separate from the objects being mapped.
This is a little prescriptive, but by and large, mapping attributes (or mapptributes, as I call them, ha) cross an invisible boundary that, in my opinion, shouldn't be crossed. Attributing classes with information about other classes they're being mapped to is total betrayal of separation of concerns.
Fact Three: Facts 1 and 2 led developers in my own organization to work around the limitations of my library.
The most painful realization that mapping attributes were the wrong solution was when I saw people using my own library in ways I never intended. I remember going over a use case with a junior developer where he did horrible things to the code in order to get AssertConfigurationIsValid
to not throw. I remember him describing (kindly) how my library wasn't sufficient enough to do something that I considered to be fairly critical, so he wrote his way around it.
The first thing I asked myself was, why didn't you stop using the library then? That was the moment that I started to realize my library was the wrong solution to begin with.
So, a few lessons learned.
One: Maintaining open source software is hard work.
I don't get nearly the volume of issues that other libraries do, but I felt a tiny bit of the pain of having to answer to folks that say, "your software doesn't work for me and here's why". Of course I was happy to help, but it was often hard to prioritize that when my nights were occupied with family/work/self-care/etc. Maintaining the library became a bit of a chore.
Two: The best way to know if your software is good is to use it yourself.
This isn't particularly an open source thing, but the best way to know that the software was good or not was to use it. It was great until it wasn't. I didn't truly feel what that felt like until I realized that my own creation was quickly becoming my codebase's own worst enemy. To that end...
Three: Realizing your software was the wrong solution is humbling.
When I wrote it, I thought that my library was a cool use of attributes and was a good way to reduce the amount of code I was writing for attributes. What I realized instead was that my library's flawed premise was causing me to write more code, and more painful code at that.
This is a humbling experience and I highly recommend it - it's good to be reminded that you truly don't have all the answers.
Finally: You have to know when to quit.
It happens all the time - abandoned open source projects. This one was a tiny, tiny one and it's time to let it go. To that end, I'm not doing any more maintenance on it. It'll live forever in my Github repo as a good lesson learned in dabbling in open source.
Now, to deal with all the codebases I have that use it...