I recently came across the Google C++ Style Guide, and since the folks at Google are geniuses, I thought it would be worth a read. Among the various sound practices, sage advice, and sensible conventions which it laid out, I found this surprising requirement:
Use only approved libraries from the Boost library collection... Some Boost libraries encourage coding practices which can hamper readability, such as metaprogramming and other advanced template techniques, and an excessively "functional" style of programming... In order to maintain a high level of readability for all contributors who might read and maintain code, we only allow an approved subset of Boost features [consisting of roughly five and a half of Boost's nearly one hundred libraries]...
I confess: I love the Boost libraries. I curse my compiler for not supporting Pointer Container. I gaze in awe at the metaprogramming that makes Units and Accumulators possible. I use Format, despite its documented performance problems, because it's so darn convenient. I painstakingly craft Lambda and Preprocessor expressions, in spite of their unforgiving syntax and obtuse error messages, just to have code that's a bit less repetitive and a bit more extensible. (It's truly amazing that the Boost devs have figured out how to add preprocessor-based code generation and lambda expressions to C++.)
But is my approach really best? As already mentioned, the folks at Google are geniuses; maybe they're on to something here? The core goal of the Style Guide authors in restricting Boost seems to be to promote simplicity, which is often in short supply as a software project develops. Some of a project's increase in complexity is unavoidable, as it gains features and adapts to handle real-world problems. Some of a project's increase in complexity is the natural result of entropy and is best handled by a healthy regimen of refactoring. Some of it, though, can only be staved off by a radical commitment to simplicity, as the folks at Google (seem to) suggest, but this raises a number of questions and tradeoffs. For example, is the simplicity of straightforward, somewhat repetitive boilerplate code better or worse than fully generic C++ template wizardry? Is boilerplate code better or worse than depending on a DSL or scripting language to generate code? What about code that's simple to an experienced developer but complex to a novice (or vice versa - code that's simple for a junior developer to write but fails to use simple-to-maintain techniques that a senior developer would know)? To what extent is it okay to make a class's internals complicated if it makes the class simpler to use? Do I use Lambda and Preprocessor because they're the best tools for the job, or do I use them because I find wrapping my head around them to be a more interesting challenge than maintaining the legacy code base I'm working on? Are the benefits (to my productivity and to future extensibility) of adding a dependency on yet another external library worth the costs to my coworkers and future maintainers of having to understand yet another library before they can work on my code?
At this point in my career, I'm not sure how to answer these questions. I suspect that the approach advocated by the Google C++ Style Guide is flawed; if simplicity is the goal, it's difficult to see how rolling your own IPC or threading library could be simpler than using Boost's, and even small classes and functions like optional and lexical_cast can make code simpler and more readable. However, I suspect that my approach is flawed too; much has been written about the fact that even relatively simple programs are too complex to hold in your head at once, and pursuing the design goals of elegance, extensibility, and robustness without also remembering simplicity can too quickly land you in architecture astronaut territory.
Like I said, I love the Boost libraries. But I've been revising some code I wrote six months ago to no longer use Lambda. It's just simpler this way.
No comments:
Post a Comment