Advice


Here is my personal advice on how to create a successful library for Boost or otherwise. I don't lay claim be the originator of any of these. They are derived from many different source of software development ideas and methodologies. Many of these sources contain overlapping ideas with different terminology.

Write Code, Concepts, Tests and Documentation Concurrently

This is what we usually do to make a library or other body of code:

  • write all the code

  • write some tests

  • change all the code and tests until the tests to pass on our platform

  • start writing documentation and examples

  • upload it and ask people to try it out

This approach has a couple of problems.

  • Coding is fun, while the ancillary tasks can be very boring, tedious and frustrating. So leaving these other tasks as an afterthought results in poor and/or incomplete documentation, testing, and concept definition.

  • Conceptual errors are often discovered when writing documentation, tests and concepts. Discovery of these errors usually results in changed to the code which ripple through the whole library and create a lot of work.

  • Poor/Incomplete documentation/testing/concepts mean that fewer conceptual errors are discovered before code is made available to users.

  • Users will be shipped code which is weak on documentation, tests, and examples and has conceptual errors. Often the library writer doesn't do this intentionally, it's just an effect of the way the code has been developed. Users will discover these problems, reject the library and move on. If the library writer get's any feedback it is likely to be of limited usefulness.

  • So reworking code and documentation after everything is "done" results in a huge amount of extra work - if the work every get's done.

The basic problem is that the ancillary tasks create a lot of useful information and this needs to be cycled back into the library code before anything is shipped. Cycling this information back sooner saves wasted time.

Here is what I recommend instead:

  • write a small group of classes. functions, or templates.

  • use concepts - what are concepts?

  • write documentation for this group

  • write and newly required concept checking classes

  • write a program to test this code

  • Repeat above for the next group.

  • When there is enough to be truely useful to someone, upload the package as ask people to test it. The package may not have all the features planned for it, but it should have enough functionality to be useful.

  • Monitor feedback.

  • add features and make adjustments and repeat cycle above.

In contrast to the first approach.

  • Coding, testing, documentation, are divided into shorter tasks. So the tedium and frustration are much easier to deal with.

  • Information gleaned from documentation, testing, concepts, and user feedback is received sooner and saves much rework and back tracking.

  • The result is a higher quality library which:

    • Exhibits "conceptual integrity". That is, code with a clearly defined purpose which is explained in an way which makes it obvious what the code is meant to do and how to use it.

    • Motviates the user to take the code for a "test drive" by including the code in his own application. This should that convince the user that the library is bug free, useful, and easy to use.

    • Results in the user returning positive feedback and request for more features.

    • Motivates the library writer and perhaps other users to add features to the library.

Use Concepts and Concept Checking Classes

include concept checks (also known as "parameter constraints") on template parameters to check template parameters. These provide compile time checks on the arguments used in template instatiation similar to the way that C++ type checking provides compile time checks on the arguments of function calls.

Boost Concept Checking Reference contains of list of widely used concepts checking classes. It's very easy to use these in your own class and function template definitions:

#include "boost/concept/assert.hpp" template<class T> class my_class_template { BOOST_CONCEPT_ASSERT((std::EquallyComparable<T>)); };

This will cause a compilation error whenever one invokes my_class_template<T> on any T which is does not support the == operator.

Be prepared to Create Concept Checking Classes classes when your library defines new concepts.

Keep Notes as You Make Changes

Many libraries have a section entitled "Rationale". This section is very helpful for anyone who want's to use the library. The problem is that if you wait until you're done to write this section, you can't remember what the key decisions were and why you made them. That is, you don't remember all the dead ends you discarded to get your final finished product. If your library gets to review, someone will suggest that it you should of done it using method X instead of method Y

"Easy" way - don't keep notes. Here's what happens.

  • At some point in the development, you discover that you want to change a design decision. This means you have to use method X instead of method Y. Generally this will occur more than once during the development.

  • Finally you get everything done, and submit your library for review.

  • Now some smart guy will make a good case for using method Y instead of method X which you used. Of course you know that since you've been down that road. But now you don't remember exactly why method Y couldn't be made to work.

  • So you sort of fake it with a glib response which only provokes your critic to make an even stronger case. Now everything has escalated to the point where you have to go back and make a really exahaustive explanation (maybe even involving sample code!). This sucks up a huge amount of time.

"Hard" way - keep notes on your decisions as you go:

  • When you discover you want to change a design decision, add an explanation to your log.

  • Keeping such notes diminishes the possibility that you accidently change a design decision back to one that has previously been determined to be a dead end. Don't laugh - this is not hard to do!

  • When writing documentation, take these notes, clean them up and include them in a section called "Rationale". This makes writing this very useful documentation trivial.

  • Users and library reviewers will be able to see your case before they make their "suggestions". This short circuits lot's of pointless discussions. There will likely still be differences of opinion, but all the issues will be visible to all parties at the same time.

Use Other Boost Components

If there's already a boost component which performs some function you need - use it.

Use the Release Branch for Testing

If you're making a library which you hope to get accepted into Boost, it will very likely depend upon other boost library components. Do not test your code against the Boost Trunk. Consider the following:

  • You're using Boot Test Library to test your library.

  • The Boost Test author makes a change and tests it on his own system.

  • He uploads it to the trunk for testing on all other compilers/OS combination which Boost Supports.

  • Over the next few days it turns out that the code is broken on some platforms he couldn't test on. So he endeavors to make the code fixes required.

  • Meanwhile, you've updated your local copy and you test your new library. But now you get a number of subtle problems of unknown origin. You have to spend a lot of time tracking down errors which are not in your own code at all! This is a huge waste of time.

  • Eventually, the Boost Test Library author get's all the tests passing and the problem goes away - IF you happen to update your local copy from the trunk in the meantime.

  • This scenario supposes that you've only got one Boot Library dependency in your code. In reality, due to the nested library structure of all software libraries, you'll actually be dependent on dozens of other libraries which your are not even aware of.

Using the Boost Trunk copy of libraries is a huge waste of your time - don't do it!

Use a Version Control System

Understand that Writing a Library is Different

Comment on This Page