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.
6
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.
1
These are two things that I find are key to releasing software:
- Know exactly what you have released
- Manage expectations
You want to be able to go back and bug fix what you have released and you want people to understand what problem your code will solve.
Knowing what you have released
Make sure you have it correctly versioned and signed (if approriate). Use your source control to taglabel the code associated with the officially released version. This will help you identify bugs easier as you can go back to exactly the source code you released. It will also help down the line when you might have a few different released versions.
Try to make the latest version easy to get hold of and update. Whether that’s an installer, or simply putting it on a common share is dependent on whowhenhow often you will be shipping.
Make sure that you have someone review your final release, including the documentation. It’s very easy to become nervous or excited about releasing software and miss something.
Managing expectations
Document the limitations and make them reasonably obvious to the developers. It is good that you have found them. People are often more understanding if they know the limitations with your software, especially if you have a plan to fix them.
Document how you would like feedback, good or bad. As it is an internal project, if everyone has access to a common bug tracking system, ask them to file bugs against the appropriate project.
In the future, avoid changing the API if possible, this is the one thing that has the potential to annoy your customers. Remember that exceptions are part of the API too, even though in C# they’re not a part of the method documentation. It may be possible to improve the exceptions being thrown at a later date, but you will need to talk to the end users and see what impact it will have.
I have a checklist for deployments that you may find useful. I do desktop development but some of this should translate. Here’s some of it:
General:
- Put in null checks for function parameters that shouldn’t be null. This helps me fail early.
- Remove unnecessary comments and commented-out files. These cause future work.
- Search for any “//TODO” comments. Sometimes I leave notes for myself. Sometimes I forget about them.
- Run a test of my code using the production database where possible. This helps ensure I have all of my database changes in place on the production server.
- Put in copious logging. Especially for an initial deployment. In fact I save logging for the end because my code is usually gelled some at this point. You don’t want to be in a situation where you have a crash and you say to yourself “If only I knew what the value of X was at this time”. Try to plan ahead.
- Try to wrap third-party library calls in Facades. This makes it easy to change libraries in the future as well as provides a checklist of what you require from a library.
.Net specific:
- Ensure I’m calling Dispose() on disposable objects. I use Code Analysis or FxCop to help find cases of this.
- Ensure I’m unhooking all event handlers properly. This prevents memory leaks.