C# – Gotchas When Shipping First Class Library

ccompilationproduction

I'm a Web Developer about to unlock the "First Class Library Published" achievement in my career and I'm sweating bullets (I was up all night stressing out). I'd love to tap the experience of the community to see if anyone has any suggestions or recommendations for making sure this goes as smoothly as possible. Are there any specifics or gotchas I need to be aware of? Anything special about the build process that can come back to bite me?

Here's where I'm at:

  • Library is unit tested and has approx 97% code coverage
  • API is well documented and xml docs for intellisense support have been created
  • I've ensured that public/private class accessors are accurate and correct. The same goes for all getters/setters
  • Error handling isn't as graceful as I'd like it to be, but I'm up against a deadline and have accepted that its an "as good as its going to be" for now
  • No friendly logging. Debug.Writeline was used extensively…I've learned recently that this is a reflection of my inexperience 🙁

Your advice is greatly appreciated!

The library will be used to generate reports. Standard hat — connects to readonly database, performs calcs, formats and outputs data to response stream.


I was tapped as a fringe resource to fill in for one of the programmers that quit, and this task was given to me as a "cut your teeth" project. The class library is going to be released for other programmers in the company to use while they write production code.

Best Answer

Lock-in the API

The art of effectively building an API is as much about managing expectations as it is about structure.

When I say API I'm specifically referring to how the public/internal classes/methods are named and what their access level is (ie private/public/internal).

If you're worried that the code may not be completely ready for prime-time you could always initially publish it as beta.

Releases:

  • Beta (ie pre 1.0)

    • may contain multiple API breaking changes
    • may lack backwards-compatibility changes between versions
    • may have a lack of polish
  • Official (1.0+)

    • API is locked in until the next major release
    • any changes introduced should guarantee backward compatibility
  • Minor (ex 1.1)

    • contain bug-fixes and-or feature implementations
    • may add-to but not take away from the defined API

If you think the API needs to be battle-hardened some then release it for a while as beta. That signals that it is available for use but shouldn't be used for production and/or mission-critical code.

Many people treat numbered versioning schemes like hogwash but when they're used effectively they can be used to provide some wiggle room until you get the structure sorted out.

Your assumptions about how it will be used are wrong

No matter how well something is designed, people will find a way to abuse or create an alternate use.

One way to handle this is to lock down as much of the implementation as possible using accessors (ie private/public/internal) but no amount of design or engineering will give you as much insight as releasing the code to the users.

It really doesn't matter how 'perfect' you think your code can become, your users will prove that it's not.

I would argue that this is the primary reason why it's always better to use an existing codebase rather than do a full rewrite. At best a complete rewrite will trim the bloat but there's a high likelihood that the new codebase will contain as many (and possibly more) bugs as the original codebase.

In your case you're battle-hardening from scratch so you might as well get started.


It sounds like you have the rest of your bases covered. API documentation is vital and tests will be good for ensuring stability when changes are made in the future.

Implementing a consistent logging scheme will be important before the code is released for production because you'll need a way to globally enable/disable/filter the logs. BTW, in most cases logging only really involves importing a library and changing the output calls from Debug.WriteLine() to something like Logging.Debug(), Logging.Info(), Logging.Error(). The logger itself just provides a standard implementation for configuration, filtering, and a wider range of output schemes (ex files, console, etc).

Other than that, I'd look to get the code out and being used. Even if only by a small number of users to start.