[Home | Contact | What's New? | Products | Services | Tips | Mike |
Living with Schizoaffective Disorder

Please to Forgive

This site totally sucks when viewed on a smartphone.
I'll fix this Real Soon Now.

Sermon at the Soup Kitchen

On C++ Software Quality and Institutional Resistance to Change.

Portrait of Michael David Crawford

Michael David Crawford, Consulting Software Engineer
Solving The Software Problem
mdcrawford@gmail.com

Copyright © 2005, 2012 Michael D. Crawford.

Creative Commons License
This work is licensed under a Creative Commons Attribution-NoDerivs 2.5 License.

October 28, 2005

I am working on a project with three young programmers and a manager. The oldest of the programmers is more than ten years younger than I. The manager is older, but does not know much about programming beyond how to check our code out of Subversion and type "make" to check our progress.

I was talking to my buddy Leo Baschy yesterday about it. Leo's around the same age I am. He is a Rocket Scientist: he wrote MacsBug 6.2 when he worked for Apple, and spent several years writing an access control application that he is just now bringing to market. Leo Does Things Right. I told Leo I really enjoyed talking shop with someone who had a clue. But I said:

"When I talk to those guys about how to write better code I have the sense that their experience of me is like going to church."

"Many go to church. How many are without Sin?"

"But I didn't learn to preach because I studied at the seminary. It's because I was a derelict on Skid Row until I was saved by..."


"... smart pointers and automated testing."

Contents

Smart Pointers

[Top]

Pop quiz: the Boost Smart Pointers exist because auto_ptr has some problems. What are these problems? Sometimes auto_ptr is the right choice, and in this case, the Boost alternatives do not provide the best solution to the problem. When is this the case?

A partial answer to why auto_ptr might not be what you want appears in my article On Refactoring C++ Code.

Even auto_ptr and Boost's smart pointers don't provide all the different kinds of smart pointers one might want. What other kinds should there be? How would you implement them?

I've already written one for my project and plan to write several more. As a hint, some of them will include Boost smart pointers as members. I'm hoping I can get the company to contribute my work back to Boost, as we are already making our code a lot better with Boost's help.

Automated Testing

[Top]

There must be many other unit test frameworks for other languages. Post links!

Ultimatum

[Top]

October 30, 2005: During Friday's service I said the manager at my startup company knew little more about programming than how to type "make". Well, he and I have been butting heads like a couple of bull moose. He may never have written code in his life, but he has been a technical manager for other kinds of engineers for years and is accustomed to having things done His Way.

By contrast, I made it clear in my interview that all I needed to be a happy employee was not any amount of pay or stock, but management that was supportive of programmers taking the time to write reliable, efficient code. "Jack" (not his real name) assurred me quality was a priority at "Yoyodyne" (ditto) because the cost to our customers of even a single incident of product failure could be a hundred thousand to a million dollars.

Be careful what you wish for, when seeking someone who takes pride in his work: you might get it. After Jack angrily informed me that my position was not to implement better software development methodologies at my new company, but to write code quick and dirty, and get it out the door as fast as possible no matter what the cost to the end user, I wrote a sad email expressing my disappointment that my stock would never amount to anything of value, but then thought better of it and copied the following to the whole company:

Lest you're worried I might get fired for posting all this online, I have only this to say for myself: Fuck 'em if they can't take a joke. I long ago decided I wasn't going to cower in fear that something bad might happen because of something I wrote on the Internet. Every Kuron should understand that about me by now.

None of the names given in the following are their real names. I don't think I've told anyone but a few close friends and family who I'm even working for. We are a startup.

Jack had asked me to spend a couple weeks teaching Bill to write better C++ code, and especially to learn better ways to test it, yet never seemed to allow Bill to actually take the time to do so.

At first I thought Bill was just being lazy or indifferent, but then I remembered what he told me when we first met, that he had actually already read all the books I recommended to him, but Jack wouldn't give him the time to implement any of their advice.

No one involved with Yoyodyne had ever hard of RAII, smart pointers, auto_ptr, Boost or unit testing before I brought them to their attention.

Gentlemen,

After further reflection upon my previous mail I'm prepared to offer you a choice. I will not back down or negotiate. This is an ultimatum. Think carefully before you respond.

Option Number One:

I want two weeks - fourteen days - of Bill's undivided attention and cooperation during which time I will teach him about RAII (Resource Allocation is Initialization), smart pointers and automated testing, and he will implement them in his code. I will check in with him several times a day to verify his progress, and also check out his code at least daily to verify the increasing numbers of his tests both written and passed without error.

That means that if Jack has something important he needs done, then he has to either do it himself or get Joe or Jim to do it. I can't have him taking time away from my work with Bill as he has so frequently demonstrated his willingness to do.

In return for your help, I will complete my project as quickly as I can. I am quite close, the only reason it's not already done is because I was working on testing support for Bill.

Option Number Two:

I will tender my resignation, effective immediately.

Please make your decision by consensus. Don't just leave it up to Jack. That's why I'm copying everyone on my offer.

I want your answer in writing. I won't be accepting phone calls until I have it. Otherwise I would just start shouting at Jack, and none of us want that.

Ever Faithful,

Mike Crawford

It's not just that I faced a certain lifetime of sleeping in the gutter, half-mad from starvation and dirty drugs, until I was saved by smart pointers and automated testing. It's that I turned down several offers from good companies where I would have earned at least a hundred thousand dollars a year, with stock options, because I felt Yoyodyne offered me a brighter future than they did.

That's right folks: I gave up my life of hungry freedom as an independent software consultant for a salaryman role at a corporation, because I felt I needed to find a better way to make a better life for Bonita and myself. I flew out West and spent three weeks crashing on my friend's couch so I could interview in the Valley.

And why did I feel Yoyodyne offerred me a brighter future? In part it was because Jack said I could do my work for Yoyodyne remotely, so I could return home to Bonita. But that wasn't the main reason I accepted Yoyodyne's offer: It was because Jack assured me that quality was a priority at Yoyodyne, and he wanted to put me in charge of implementing my software development methodologies at the company. It can't get much better than that, can it?

I feel pretty betrayed right about now. Pretty ripped off. I feel just like I fell for a swindler's con.

After Jack's initial response, which demonstrated to me that he had not the first clue as to why I was angry at him, I then sent the following reply, again copied to the whole team.

Why the whole team? Because the lot of them are working for stock. They have been getting no cash pay whatsoever, and have no prospect of getting any for several months. I am only getting paid because I made it clear that keeping my wife in art school was a priority. I'm not getting paid very much, just the bare minimum I calculated I would need to meet our living expenses and pay Bonita's tuition. Like the others, my pay is mainly in stock.

I wanted to help them understand just how little that stock was going to be worth someday if Jack didn't shape up and get a fucking clue.

Jack,

I'll be giving you the benefit of the doubt by assuming you didn't read my second mail before you sent me your reply quoted below.

Go read it, then discuss with the team which option the team prefers. Please don't contact me again until all of you have discussed it with each other. If Jim and Joe are out then you need to reach them on the phone.

While I'm awaiting your response I'll be posting my resume on Craig's List. I would rather not get another job, I would rather stay with Yoyodyne, but without resolution of some important issues I will have to look at other options.

It's important for everyone to understand I'm not just trying to be difficult. I made clear to Jack before we even met that a basic precondition of my accepting ANY offer of employment - not just Yoyodyne's offer - was management support of software methodologies that lead to reliable, high performance code. I have no interest in compromising my integrity as a software engineer by contributing to the success of a company that does not serve the best interests of its customers.

I have made this point repeatedly every time you and I have had a disagreement, and I am making it as clear as I possibly can now: if I am going to resign, it is because Yoyodyne does not want to produce quality software.

Life is too short to write bad code.

I stand by the work I've done so far. I've you have any doubt, have Jim, Joe and Bill audit my source code. I've already invited you to have them do so.

Good Day.

Mike

After several hours of heartfelt discussion, my wife Bonita feels I should just resign no matter what they say or do. Based on everything I've told her about Yoyodyne and Jack so far, Bonita feels Yoyodyne is destined for failure, it is not in my power to save it, and even if it were, Jack would never stop making life miserable for me.

auto_ptr and Its Alternatives

[Top]

October 31, 2005: In my first sermon I explained that the Boost smart pointers were created to address some shortcomings in auto_ptr. I gave you a quiz: what are these shortcomings? Boost isn't always the right solution: sometimes auto_ptr is the best choice. When?

Answers with sample code within. Tomorrow: the other kinds of smart pointers you need to make your kit complete.

In my second sermon I explained I gave an ultimatum to my new employer "Yoyodyne", in which I demanded founder "Jack" give me two weeks to teach young programmer "Bill" how to overcome his quality problems. Brother rusty pointed out that commitment to quality is a bad strategy for a startup, and Brother localroger agreed with my wife Bonita that I should leave no matter what because Jack and I will always be fundamentally at odds.

I accepted Yoyodyne's offer because Jack himself explained why Yoyodyne had no choice but to write quality code. But some souls can't be saved: Jack knows The Way in his head, but does not feel it in his heart. That's why I'm posting this link to my resume:

I will accept both permanent and consulting positions. Didn't Jack even read my resume before he hired me?

There are two reasons why auto_ptr might not be what you want.

auto_ptr Doesn't Work for Arrays

[Top]

The simplest is that it doesn't work to with arrays, because auto_ptr deletes its member pointer with just plain "delete" and not "delete []". The second form is required for arrays because the memory manager needs to store the length of the array somewhere with the pointer as a lookup key. Without saying "[]" it won't know to go look.

The effect of using just plain "delete" might be a memory leak or it could be a crash. It's not simply that arrays could be stored differently than single objects - portable code has no way to know - but the destructors for all the objects but the first will not be called. Bad bugs might result if the objects in the array have non-trivial distructors,

I understand Metrowerks CodeWarrior figures out which kind you really should use and does the right thing, but I consider this a misfeature. I would prefer the memory manager called assert( false ) when the wrong kind of delete was used. I'm pleased to report that the valgrind memory debugger says "mismatched new/delete" when you call the wrong form.

I discuss this in further excrutiating detail in my article On Refactoring C++ Code.

Take My Memory. Please!

[Top]

The second reason auto_ptr is probably not what you want to use is more subtle, and will lead to crazy bugs any time you try to put auto_ptrs in Standard Template Library containers: auto_ptr has extremely nonintuitive copy and assignment semantics. The auto_ptr being copied or assigned from hands over responsibility for its memory to the auto_ptr that is being assigned or is the new copy, and resets its member pointer to NULL.

Why?

It really could be no other way, if auto_ptr is going to just manage a single pointer in a simple way. If instead the copy got a copy of the pointer while the original kept it too, there would be a double delete that would corrupt the heap and likely cause a crash.

There are two ways to solve the problem, the simple way and the complicated way. In the simplest cases, it doesn't matter that auto_ptr does the wrong thing when you copy it, because you just don't ever try to make a copy.

However, it is possible to make a copy accidentally, which leads to crashes that are hard to figure out. This happens especially because the C++ compiler will define invisible default copy constructors and operator=() member functions even if you don't want them. For that reason alone, if you have any auto_ptr members, you should explicitly declare your copy constructor and operator=() "private" so a compiler error will be emitted if you should accidentally try to copy or assign an object with an auto_ptr member.

The Simple Solution

[Top]

It's tedious to have to do that every time you want to use an auto_ptr. Error prone too: what if you forget sometimes? Is there an alternative that would automatically force compiles to fail should you accidentally try to copy or assign one? That's what Boost's scoped_ptr is for. scoped_ptr is just like auto_ptr, in that it manages a single object in a simple way, but its copy constructor and assignment operator are declared private. Attempts to copy or assign an object with a scoped_ptr member will fail to compile.

(Not always though: only if you leave the copy constructor and assignment operator up to the compiler-generated defaults. It is possible to define your own that do the right thing. When would you want to do this? I can see good reasons for doing it two different ways. What ways? What would the implementations look like?)

"That's helpful," you say, "in that I won't accidentally make an awful mistake. But isn't there a way to use pointers in STL containers? That's the only way they can hold polymorphic objects!"

For STL containers, you need the more complex alternative to auto_ptr: reference counted smart pointers.

Standard Template Library-Compatible Smart Pointers

[Top]

For an object to be held in an STL container, it needs to have a well-behaved copy constructor. auto_ptr's copy constructor is not STL compatible. What would work is a smart pointer whose copy constructor copies the object whose pointer it holds, but that would be slow and memory-intensive.

A fast, lean alternative is reference counting. The memory managed by a reference counted smart pointer is shared between all the assigned or copied pointers. Each time a copy is made, the reference count is incremented. Each time a copy is destroyed, or an assignment changes which object a smart pointer manages, the reference count is decremented. If the reference ever reaches zero, then the memory being managed is deleted.

If your objective is to hold polymorphic objects in an STL container, then almost certainly what you want is an STL container that holds reference counted smart pointers to your objects.

There are a lot of different kinds of reference counted smart pointers around. Boost offers two, the first being shared_ptr.

The advantage of shared_ptr is that it can be used to manage objects of any class: the objects a scoped_ptr manages don't need to know they are being managed in a reference counted way.

The disadvantage is that a separate reference count has to be allocated that all the shared_ptrs share among themselves, so updating the reference count for one of them updates it for all. Thus shared_ptrs take up more memory and have to allocate their reference count from the heap, so creating the first shared_ptr and deleting the last is slow.

If you create a new class specifically meant to be reference counted, a faster, leaner alternative to scoped_ptr is Boost's intrusive_ptr. The objects being managed maintain their own reference count as a member variable, and provide member function accessors for intrusive_ptr to call to manipulate the count.

That's Great! Is It Thread-Safe Too?

[Top]

Maybe Not! A naive implementation won't be. Thread-safe smart pointers require atomic reference counts.

If one increments and decrements the reference count by just adding or subtracting one to or from it, the smart pointer won't be thread-safe because the code that updates and checks the reference count is a critical region: if two threads update the reference count at the same time, then check the result to decide whether to call delete, one of two errors might occur: the memory might never be deleted, or it might be deleted before the last shared_ptr is done with it - that is, before your client code is finished using the managed object. Most likely this will corrupt the heap and lead to a crash.

Conceptually, the solution is simple: most platforms that support threads also provide atomic arithmetic libraries. All you need to do is increment and decrement the reference count in an atomic way.

Unfortunately, using library subroutines to do the atomic math is slow: each increment and decrement requires a subroutine call and return. Large STL containers full of thread-safe reference counted smart pointers will run a lot slower than equivalent containers full of thread-unsafe ones.

There is a faster solution, but it's not very pretty, and it's completely non-portable. Or rather, it's portable, but it takes work to port to new platforms, and each port must be maintained separately. One can manipulate the reference count directly by using each target processor's atomic arithmetic instructions in assembly code.

Hey! Who farted? This may be skid row, but it's still a church, you know!

I've never used it, but I understand Boost's Thread library provides such atomic math with the platform-specific parts encapsulated so client code can use it in a portable way. But I also know the task of maintaining the Boost Thread library is an onerous one for the Boost developers, and I have read complaints that new processors needing new ports written appear faster than the Boost developers can implement support for them.

Boost's shared_ptr is thread-safe by default, but will run faster if you disable thread-safety in your build. scoped_ptr's documentation details its thread-safety guarantees, and makes it clear that only certain kinds of simultaneous accesses from different threads are guaranteed to work:

shared_ptr objects offer the same level of thread safety as built-in types. A shared_ptr instance can be "read" (accessed using only const operations) simultaneously by multiple threads. Different shared_ptr instances can be "written to" (accessed using mutable operations such as operator= or reset) simultaneosly by multiple threads (even when these instances are copies, and share the same reference count underneath.)

Any other simultaneous accesses result in undefined behavior.

It's important to understand that "thread-safe" doesn't imply "anything goes"; just as with exception-safety, there are different degrees of thread-safety, and one has to take care to understand what is guaranteed and what is not.

I'm more familiar with the ZRef thread-safe reference counted smart pointer in the ZooLib cross-platform application framework, which was written by my other Rocket Scientist friend Andrew Green, his clients Learning in Motion, and Learning in Motion's client, The Ontario Institute for Studies in Education. ZooLib is Open Source under the MIT License.

(Please forgive ZooLib.org's primitive HTML design. I threw it up at Sourceforge in a hurry for ZooLib's Open Source release before I knew much about web design, and still haven't redone it.)

ZooLib's flagship application is the educational multimedia database Knowledge Forum. To allow Knowledge Forum to handle thousands of clients in a fast, scalable way, ZooLib is extensively multithreaded. But ZooLib isn't just for servers: graphical user interface applications written in ZooLib are snappy and responsive in a way that is difficult to achieve with single-threaded code.

ZRef is similar to Boost's intrusive_ptr in that the reference count is held by the objects that are managed by ZRef. They must be subclasses of ZRefCounted, but otherwise client code doesn't need to worry about implementing the reference count code.

The atomic arithmetic used by ZRefCounted is provided by inline assembly code embedded in inline C++ functions in ZAtomic.h. You will see there is a different implementation for each arithmetic operation, for each target processor, and what's worse, for each target compiler on each platform, because every compiler has its own idea of how inline assembly should be written; inline assembly is not defined by the C++ or C standards documents.

It's not hard to port ZooLib to new platforms or compilers, but the very first work required is to implement each arithmetic operation in ZAtomic.h. That's why, sometimes, naive users think ZooLib, being written in C++, should work on any POSIX platform, but find programs built with ZooLib don't work when compiled for an unsupported target processor. (ZooLib also supports Mac OS, Windows and BeOS.)

I describe ZooLib and ZRef in more detail in The ZooLib Cookbook.

But Arrays? What About the Arrays?

[Top]

Boost offers array-compatible variants of each kind of smart pointer: scoped_array and shared_array.

I understand the C++ ISO Standards Committee didn't provide an auto_array because they felt the STL vector template was a better alternative. They failed to understand that vector doesn't serve every need, for example integration with legacy code that returns naked pointers to arrays that become the responsibility of client code to delete.

So is auto_ptr Completely Useless?

[Top]

No, there is a common situation where auto_ptr is the best choice. shared_ptr will do, but auto_ptr is actually better. Naked pointers also work and are more commonly used, but risk leaking memory.

When could that possibly be the case? When auto_ptr's peculiar copy semantics are what you want!

I began to wonder about this when I started to change my code for Yoyodyne from auto_ptr over to scoped_ptr. Being deeply religious, I always completely construct my class' member variables in initialization lists. I don't initialize member variables in constructor bodies if I can possibly avoid it, thus nearly every constructor I write has an empty body.

(Smart pointers are examples of "RAII" - Resource Allocation is Initialization - applied to memory management. Zealous use of RAII is the first step towards the Holy Grail of exception safety. When one uses RAII, one's destructor bodies are almost always empty too.)

The entry for each member variable in an initialization list is not actually its initial value. This is the case for primitive types like integers and pointers, but the entry is actually the parameters for to a call to each member's constructor. It's just that for primitive types, the constructor turns out to be a simple assignment of the value given.

Each parameter passed to the constructor has to be an expression, that is, some C++ code that resolves to a single value. Usually you can calculate each parameter in-place as an expression, but some parameters are more complicated to calculate; they require one or more statements and one must call a static member function that calculates the parameter and returns it as its result.

(Why static? Because the object "this" points to is incompletely constructed until processing of the initialization list is complete and the constructor body is entered. It usually works to call a non-static member function, if one is careful not to refer to unconstructed members, but this requires care and is hard to maintain. Using static member functions keeps one's code Pure of Heart and bug-free.)

Commonly these static member initializers allocate a pointer with new after calculating the object's constructor's parameters, then return the pointer. One can return just the naked pointer, but there is a potential for a leak: what if some other code calls the initialization function, but forgets to capture and delete the result? What if "new" is not called as the last statement in the function, and a later statement throws an exception? You get a memory leak!

The solution is to return a smart pointer. If its memory is not deleted elsewhere, the smart pointer will delete it after function return processing is complete and it goes out of scope. To be more clear: there is a small window of invisible code in between the return statement and the resumption of the code that called the function. The calling code can capture the return value during that window, but if one forgets, returning a smart pointer prevents a leak.

One can't return a scoped_ptr because it doesn't have a release() member function: once a scoped_ptr starts to manage some memory, one can make it manage different memory by calling its reset() method, but one can't make it simply stop managing any memory at all.

shared_ptr will work, but only if the member variable being initialized is another shared_ptr. shared_ptr doesn't have reset() either; you can't initialize a scoped_ptr from a shared_ptr.

But auto_ptr has a release() method! You can initialize a scoped_ptr from an auto_ptr. The scoped_ptr's copy constructor calls auto_ptr's release() method so the scoped_ptr assumes responsibility for deleting the memory when it goes out of scope.

Sample code below: auto_ptr_demo.cpp prints "Hello World!" when it runs. Testing with valgrind proves it does not leak memory or have any illegal memory references.

Coming Soon to a Soup Kitchen Near You: The Smart Pointers Boost Forgot.

You might think auto_ptr and the Boost smart pointers provide all the smart pointers one might ever need, but that's not actually the case.

To understand why, think about how this skid row derelict was saved: by smart pointers and automated testing. The smart pointer templates I've been working on are for memory you don't own, but that test automatically every time you run your program, by asserting that the pointer is still valid every time you dereference it.

Without Further Ado

[Top]

auto_ptr_demo.cpp was formatted using the handy perl script found in Brother tmoertel's How to Post Code to K5 -- the easy way!

I gotta run. I'm going in with Bonita to Halifax this morning.


/* auto_ptr_demo.cpp
 *
 * This demonstrates one situation in which auto_ptr is the right choice,
 * rather than one of the Boost smart pointers such as scoped_ptr or
 * shared_ptr.
 */

#include <iostream>
#include <string>
#include <memory>
#include <boost/scoped_ptr.hpp> // http://www.boost.org/

using std::ostream;
using std::string;
using std::auto_ptr;
using boost::scoped_ptr;
using std::cout;

class HelloSayer
{
public:
  HelloSayer()
  {}

  ~HelloSayer()
  {}

  string asString() const { return "Hello, World!\n"; }
};

class Microphone
{
public:

  Microphone()
  : mSpeakerPtr( getSpeaker() )
  {}

  ~Microphone()
  {}

private:
 
  scoped_ptr< HelloSayer > mSpeakerPtr;

  // static because the object "this" points to is
  // incompletely constructed when getSpeaker is called.

  static auto_ptr< HelloSayer > getSpeaker();

  friend ostream &operator<<( ostream &stream, Microphone const &mike );
};

int main( int argc, char **argv )
{
  Microphone mike;

  cout << mike;

  return 0;
}

ostream &operator<<( ostream &stream, Microphone const &mike )
{
  stream << mike.mSpeakerPtr->asString();

  return stream;
}

auto_ptr< HelloSayer > Microphone::getSpeaker()
{
  return auto_ptr< HelloSayer >( new HelloSayer );
}

The Right Tool for the Job

[Top]

November 1, 2005 - Today's sermon won't be what's listed in your program. I must answer a question posed by Brother th0m after yesterday's sermon as I feel it is of fundamental importance in any discussion of any programming language - not just C++ - and especially, when interviewing applicants for software development positions. Again, jobs where one writes code in any programming language, not just C++.

Engineers of any sort, not just software engineers, will readily agree to the following:

  1. One should use the right tool for the job.
  2. One should hire workmen who are skilled and experienced with, as well as trained in the use of these tools.

Makes sense right? But the mistake nearly everyone makes is to assert that C++ cannot possibly be the right tool for the job when much safer languages like Java or Python are readily available. Evidence that C++ is unsafe comes in the form of bloated, slow, crashy and leaky C++ applications. Examples of such products are easy to find, and all too numerous. I readily admit that many, if not most C++ applications are buggy as all get-out.

But, I assert, that's not because C++ is never the right tool for the job, but because most people employed as C++ programmers aren't the right workmen for the tools: they are either not adequately skilled or experienced with, or trained in the use of the C++ programming language.

I assert:

  1. The requirements of some jobs require the use of tools which are powerful, sharp and difficult to wield correctly. Thus:
  2. A great deal more skill, experience and training is required before any workman is qualified to use such tools.
  3. The use of such tools by unqualified workmen is dangerous. Use by qualified workmen is risky, but less dangerous than using the wrong tool.

The mistake made by most who either write C++ code or employ C++ programmers is thinking that knowing enough C++ to be dangerous implies one is qualified for a C++ programming job. That's just plain wrong: all it makes one is just that: dangerous. Having the brute strength to gouge a chip out of a piece of walnut with a sharp chisel does not make one a fine furniture craftsman.

Brother th0m was moved to jump up at the end of yesterday's service and shout:

for fuck's sake,

what does the very existence of this topic tell you about C++ as a programming language? ANYONE? THIS THING ON?!!?

Brother th0m has an excellent point. But I hasten to point out, one can live a completely righteous life, yet not be saved.

I'll restate his question in a way that will make its answer more readily apparent:

Question: What does the very existence of the United States Army, Air Force and Naval Academies say about the fighter plane as a mode of aerial transportation?

Answer: That's not what fighter planes are for. Fighter planes are for killing people.

If you want to go on vacation, visit a relative or attend a business meeting, you don't travel in a fighter plane: you fly on a passenger jet operated by a commercial airline. If at all possible, you purchase your ticket days or even weeks ahead of time, to save on the fare. In all cases, one travels from one airport to another, and may ride in commercially operated ground transportation at one or both ends.

But if you want to defeat an enemy, whether to defend from their attack or to conquer them, one does not attack with any more advance notice than is absolutely necessary, as the element of surprise is a significant advantage. One must be ready to deliver one's strike to the enemy wherever he may be, anywhere in the world, whether on land or at sea. If an airbase is not available near the enemy, one must take the airbase to the enemy in the form of an aircraft carrier. One does not ride a taxi or bus to an airbase: one lives in barracks on base, or quarters aboard ship, so one is ready to fly a sortie on a moments notice.

Fighter planes are dangerous to fly because killing is dangerous work. Why? Because the enemy defends itself. Fighter planes do their job by raining bullets, bombs and Hellfire upon the enemy until they are killed, maimed or burned beyond recognition. Most enemies I have discussed this with explained to me they don't like this kind of treatment. So they fight back, in the form of antiaircraft guns and missiles, and heat-seeking air to air missiles launched by their own... (wait for it!) fighter planes.

Fighter planes are dangerous to operate even in times of peace because the maneuverability required, not even to win an aerial battle but simply to survive it make fighter jets unstable and difficult to control. They respond to the pilot's lightest touch as if hair-triggered, and are as likely to spiral out of control as to fly straight.

Passenger jets are in safe in part because their wings are titled in a shallow "V" shape known as a dihedral angle. Its effect is to gently press the plane back towards level if it should ever tilt sideways. Not just passenger jets, but small aircraft and even most kites have dihedral angles.

But fighter planes don't have dihedral angles: their wings stick straight out. That makes them dangerously unstable, but it also means they fly just as well upside-down as right-side-up.

Why do we care? Not so some Top Gun academy graduate can get his rocks off flying upside-down: it's so, should he happen to find himself upside-down in the heat of a battle, he can still fight.

What would happen if a 747 pilot, even a trained and experienced one, were to sneak onto an Air Force Base and steal an F-15? I can confidently predict the outcome:

  1. A smoking crater in the ground
  2. Millions of dollars of lost taxpayer money in the form of a wrecked F-15
  3. One dead 747 pilot

I have absolutely no argument with the claim that fighter planes are dangerous. Fighter pilots, even highly trained academy graduates, die all the time, not just in battle but in peacetime training accidents.

But:

Does that in any way imply that a sovereign nation should not have fighter planes?

No.

Let me ask you then: when a nation has a war to fight, should it employ postal clerks or Professional Killers?

Profesional Killers of course: military men and women, soldiers and sailors.

"But we don't have any resumes on file for Professional Killers. Where do we find them? Are there headhunters for this sort of work?"

No: you have to make them yourself, by hiring postal clerks and training them to be soldiers and sailors. Many require only boot camp, but to fight with the most powerful and dangerous weapons, such as fighter planes, the training must include a college degree and flight school, or even better, graduation from a Military Academy.

BROTHER MIKE! Are You OK? Do You Need Help?

[Top]

Oh. I'm sorry... a moment please. (A sip of water sister, please? Thank you. Thank you very much.)

Forgive me brothers and sisters: sometimes when The Spirit catches me, I forget myself. I completely forgot I was even discussing computer programming. Allow me to explain:

Long before I was Saved, long before I was down and out on skid row, I read the words of the prophet Richard, that foretold a return to The Garden. What's more, his Prophecy gave the directions to get there! We must learn again what we were taught by our mothers and our fathers when we were small. To regain Paradise, we must Share.

I knew the instant I read his Prophecy that Richard's way was my way, and immediately commenced study of The Good Books, starting right from the beginning with The Old Testament.

(I have already explained that my path was not a righteous one: tempted by filthy lucre, I lived for many years in The Valley of the Shadow of Death. While I was Saved years ago, I yet continued to sin, as even The Saved are Sinners. We can do little else than strive to do Good Works while begging for forgiveness for our sins. But that's a story for another day.)

But why you ask, did I know so instantly I was to be a GNU hippy? Because, in many ways, I was already a hippy of the more common kind: I already believed one must share. I even owned a Tye-Dye T-Shirt and bedsheet to prove it.

I never served my country, yet I lived the military life: I am a Navy brat.

My father Charles Russell Crawford was a proud officer of the United States Navy. Not just him: his brothers Herb and Ben, my grandfather Herbert, and as far as I am able to tell, very nearly every male relative and ancestor on my father's side of the family for as far back as anyone has any record served their country in the Navy, or the Army during the Civil war.

Speaking of weapons of war and those who wield them made me cry. And I cried, yes brothers and sisters, O How I Cried, as The Spirit caught me, because all I could think of was how I hurt my father so, my father who served his country in Vietnam, because I did not serve as he so proudly expected me to.

No, worse: I slapped my father in the face as hard as I could . During my Senior Year at Armijo High School, I applied and interviewed for the Naval Reserve Officer's Training Corps Scholarship, and fully expected to get it. My father knew I did not want it, but begged me to accept it. He made clear to me that he wanted this for me not so I could go to college for free, but so one day I too could serve my country as an Officer of the United States Navy. My father wanted this for me more, I am certain, than anything he had ever wanted.

But I knew I was, in my heart, a hippy. I knew I was Fundamentally Incompatible with Military Service. I loved my father, and I loved and still love my country, but I knew it would be wrong to accept the NROTC scholarship.

But I was young, and my father could be angry and unapproachable. I did not have the courage to refuse. I admit: I did not have the balls. I didn't decline the scholarship, I simply did not show up for the Navy's medical exam.

My father went to his grave without mentioning it ever again. But I knew what I had done, and how he must have felt about it.

My father never spoke of his time aboard the USS Providence off the coast of North Vietnam as if it were any different than a fishing vacation. But I know that, as the ship's missile fire control officer, it was my father's personal duty to take the lives of North Vietnamese fighter pilots. Did he? I don't know, and likely never will know, as he never spoke of it. But if he did, I know that by doing so he saved the lives of dozens, perhaps hundreds of his shipmates, and quite likely his own.

Saint Gödel taught us that it's not all Black and White: there is a great deal of Gray in between:

Is War justified? If it is, it's not so nearly as often as some claim. But if one finds oneself by whatever circumstance in a battle, is it then justified to kill or be killed? To kill, or let one's comrades die?

This very question torments me, as my father told me it tormented him, and as I know it torments many of our Brothers and Sisters in Iraq and Afghanistan this very day. And that, Brothers and Sisters, is why the Spirit caught me, and that, Brothers and Sisters, is why I cried.

But Brother Mike! Isn't this about C++? Tell me about C++! You've lost me completely!

No, Brother th0m, the topic of today's service is about choosing, or, more precisely, correctly wielding the right tool for the job. C++ and fighter planes are just examples of powerful and dangerous tools that require years of study and practice to learn how to use.

I'll tell you in a moment when C++ is the best tool. But first I want to explain an important lesson my father taught me, that I may pass it on to you. When you wield a tool, whether it be a programming language or Weapon of War, you must do as my father taught me, and wield it Righteously:

Every Engineer's Solemn Duty

[Top]

My father was an engineer too, an electrical engineer. Once a carpenter, he was inspired to enlist in the Navy one snowy evening while roofing a house, when he struck his thumb real hard with a hammer. The Navy sensed my father's potential for leadership and sent him to study at the University of Idaho, where he met my mother. My sister was born while they were still students. After graduation, he went on to Officer Candidate School and was given his commission. The telegram with news of my birth took two weeks to reach him: he was deep in the Phillipine jungle getting trained in survival, as the Vietnam War was just then heating up: the year was 1964. My father's engineering specialty was antiaircraft missile electronics: guidance and control systems.

The lesson my father taught me, a lesson I only now, as I speak, realize for the first time I was ever taught, is to Do My Duty. You already know my father did his for his country. I want you to know that he did his duty to his family as a husband, father and provider, and he did it well. He did his duty as a teacher too: I learned science and engineering at my father's knee, as we worked on projects together. Once we had a contest to see who could make a working telephone from stuff found lying around the house.

Engineers have other Masters who demand duty of us: our profession, our conscience, those who invest in, purchase or use what we design, our coworkers, and the public.

Listen to me carefully, and never forget what I'm about to say. I want all of you to spend some time thinking it over deeply, then I want you to discuss it among yourselves:

There may come a time in your career as an engineer when you will be called to take a stand against your employer's disastrous course of action. When that time comes, your duty is not to your employer, but to your profession, your conscience, your coworkers, your company's investors, its customers, and the public. When your coworkers, investors or customers could be bankrupted, or the public's safety could be placed at risk, it is your solemn duty to take a stand.

Your stand could be an ultimatum: you might lose your job, as I did. You could blow the whistle as I still might. You must accept the consequences: unemployment, poverty, getting blacklisted, sued or even imprisoned. Such may be the cost of doing the right thing.

But when the chips are down, it is your solemn duty to do it.

My father knew from engineering quality: After getting his Master's degree at the U of I after the war ended, he went back to work for the Navy as a civilian. His last job before he retired was overseeing the repair and testing of nuclear submarine reactor control systems at Mare Island Naval Shipyard. Now I ask you: if the Navy decided to send a sub out to sea before my father felt its reactor control system was ready, would he have spoken up about it? Even if he lost his job by doing so? And was thereby unable to feed his hungry children?

I know my father, he would have done the right thing.

Because an engineer named Roger Boisjoly didn't trust his conscience, seven brave and innocent people died. No, he followed standard procedure, by reporting a safety risk to his superiors, then trusted them to do the right thing, despite the fact that they obviously didn't heed his warning:

It got real cold one night when the Space Shuttle Challenger was being readied for launch. The Shuttle's two solid fuel rocket boosters had been manufactured by Morton Thiokol in several sections. Rubber O-rings were used to seal the joints between each section, and covered with high-temperature putty to protect the rubber from the flames. But the rubber the O-rings was made of became brittle if it ever got cold. It wouldn't flex as the sides of the joint vibrated in and out, so that the flames inside the rockets might shoot out through a crack, and make the liquid fuel tank explode.

Realizing the risk, Mr. Boisjoly filed a safety report with his superiors, yet despite the fact that they overruled his advice for fear of losing Morton Thiokol's fat government contract, he did his duty to his company and kept quiet.

But he didn't do the right thing when he realized the Challenger was going to launch to its doom. Why didn't he ring someone up at NASA? We didn't he go to the press? Why didn't he crash his way into Mission Control, arms flailing and screaming "IT'S GOING TO FUCKING EXPLODE!"?

Because he might have lost his job? He probably would have, but I don't think that's why. Gotten arrested? No. I don't know for sure, but I'll hazard a guess: either he because he trusted his company to do the right thing or he didn't want to get blacklisted. And because he didn't trust his conscience, and go against orders - no, not even that - against standard procedure, he has these people to answer to, and their loved ones:

Challenger Crew

Someday you might be faced with such an awful decision. Most engineers don't ever consider the possibility. I'm asking you to consider it now, ahead of time, so if the time ever comes, your mind will already be made up.

What to Consider When Choosing a Tool

[Top]

The hour grows late and I know many of you still need to find a safe place to sleep tonight. Before we close, I'll list some of the factors that influence the choice of language for a software product. Among them are:

I'm sure you can think of many others. But every software architect simply must consider:

"But we don't have any resumes on file for C++ experts. Where do we find them? The headhunters want too much money, and the candidates they submit are never any good!"

Then you must make do with the staff you already have. But that doesn't mean you let them write bad code.

If you have a War to fight, but you have no pilots, then you must teach postal clerks to fly. That's where Brother Mike comes in, you can send your wretched refuse to be Saved at the Soup Kitchen, and to enjoy a free, nourishing hot meal. But all Brother Mike can do is convince them there even is a Way. It takes long, hard study and practice to follow it faithfully. You must purchase The Good Books for your staff and urge them to read them, specifically the C++ texts, and one book, most important of all.

Friends, while I don't want you to steal, do beg or borrow if you have to, but don't let another Sun go down before you have obtained a copy of:

Start with Chapter 4, "Physical Heirarchy", and Chapter 5, "Levelization". We shall discuss these when we cover Unit Testing in a few days.

C++ is the right tool when the design constraints indicate you need choice and control. Garbage collected languages might not be able to satisfy the constraints because they offer only one choice for memory management. C++ is difficult and dangerous precisely because it offers a nearly infinite array of choices. A novice or careless coder might still ship by writing his product in Java, but when a surgical strike is required to deal a deadly blow to the enemy, you need an Academy graduate and an stealth fighter, not a passenger jet and a commercial airline pilot.

At last, our tortuous journey this evening allows me to reveal to you the most powerful and dangerous tool of all. Used with love, skill and care, it is the best tool for nearly every job, but it saddens me to tell you - it grieves me deeply - that used carelessly or in anger, it is the deadliest weapon known to man.

I Am Absolutely Serious.

Why We Fight

[Top]

I know of an even more powerful and dangerous tool than C++. Even more powerful and dangerous than jet fighters. But I used it right here tonight to carry out a difficult task: to help you understand why, even though it is a dangerous programming language, C++ can be the best tool for certain jobs.

I knew this tool was doing its work because I felt its power as I used it. I used it as carefully as I could, but brothers and sisters, I didn't study at the seminary: I don't know how to wield it all that well, and it nearly destroyed me.

But I assert it was the right tool for this job.

I will reveal it to you now. I put it in this little box for safekeeping. Sister Pandora carved it for me from mahogany. Here, I'll open it, just a little, so you can have a look. Shield your eyes, or you'll be blinded:

The Metaphor.

Get back!. Sorry, Brother Jacob! I didn't mean to knock you over, but you got too close. You could have been killed! Please forgive me.

This evening, I used the very simple metaphor of the fighter plane and its pilot to help you understand why C++ can be the right choice, but one must hire a highly skilled C++ programmer to write it if disaster is not to ensue.

Even that simple metaphor was risky as it overwhelmed me even to speak of it.

What other metaphors do you know about?

C++ is a metaphor! It is a metaphor for the central processing unit and memory of a computer. Using C++ as a metaphor makes the computer easier to understand and write software for: C++ is the machine code for a virtual machine that has such hardware opcodes as new and delete.

But wait, there's more: Java is a metaphor too, used in many of the same ways. It is a much less dangerous tool than C++, and so better for younger programmers to use than C++.

And brothers and sisters, while it pains me to admit it, even PHP is a metaphor. We aren't all of us poets.

And here is why I am ready to admit defeat: I don't think any of what I have said to you tonight has changed anyone's opinion on the value of the C++ programming language. I might as well have been pissing off the back off a moving pickup truck.

Here's why: not all metaphors, but some, hold a lock over the human heart and mind that is almost, but not quite impossible to unlock. We believe in our metaphors in such a deep and fundamental way that we are almost always unaware that they even exist, yet we will fight for them with every fiber of our being.

You don't believe me do you? It sounds crazy. I admit that, but explain to me then why my little joke here is funny:

Why do we have to hide from the police, daddy?

Because we use vi, son. They use emacs.

Just a joke. Forgive me, but it helped me explain an important point.

The Right Tool for the Workman, or the Military Way of Life

[Top]

Why do you suppose most fighter pilots feel it's worse to be grounded than shot down? Why did my father join the civil service after grad school, instead of working for the power company for twice the money?

It's the same reason that an Emacs fan will suffer if he must work in Visual Studio. He might ship his product, but every minute spent coding it will be a torment. Why?

In every case, it's because the time, study and work required to master a tool has allowed its Metaphor to capture their hearts and minds. It has to be that way: mastery is achieved only when one has fully come under the power of a tool's Metaphor.

Thus a good C++ programmer doesn't simply know C++. He is a C++ coder in the same was as he might be an American, a Baptist, or a black man. You aren't one of these because of where you were born, where you went to church or the color of your skin. You are this way because of your culture, which you carry deep in your heart.

Thus, no matter how masterful you may be with C++, if Java is the right tool for the job, and you are not already a masterful Java programmer, then you must either undertake to become one, or step aside that your company may hire someone who is. You do a disservice to write Java when you don't feel Java in your bones.

The Most Dangerous Weapon Known To Man

[Top]

While the hydrogen bomb has the potential to be worse, it hasn't been dropped yet, and I assert it won't ever be lest some metaphor send the missiles flying.

I will end tonight's service by naming a few metaphors to help you understand my claim that metaphors control our hearts and minds:

Lord Have Mercy, it never ceases to amaze me that we have not already all of us perished from the Earth.

Let us pray.

Next Up:

[Top]

Come back soon to Brother Mike's Skid Row Soup Kitchen for a free, nourishing hot supper and a sermon: "The Path of Righteousness": on automated testing and the smart pointers Boost forgot.

For my father, Lieutenant Charles Russell Crawford MSEE, United States Navy (Retired), 1934-2003.

May He Rest In Peace.

[Home | Contact | What's New? | Products | Services | Tips | Mike]