The Panglossian Programmer

by Chad Finsterwald

Contents

The Panglossian Programmer Defined:

In Voltaire's novella Candide the character of Dr. Pangloss is a hopeless optimist. He is beset by syphilis, imprisoned, nearly hanged, almost dissected, and yet he continues to espouse optimism. This world, he insists, "is the best of all possible worlds." Now this is no treatise on the philosophy of Voltaire, but this character type can be found not just in the pages of Candide. In the form of the "Panglossian Programmer" it might be you, the person in the cube next to you, the last developer who worked on the application you inherited, or the outsourced developer who now has your job. (Alright, so maybe for that last group this is the best of all possible worlds...)

So what is the Panglossian Programmer? It is a programmer that in spite of experience to the contrary assumes that everything in their application will work out. As Candide says to Pangloss: "Well, my dear Pangloss when you were hanged, dissected, whipped, and tugging at the oar, did you continue to think that everything in this world happens for the best?" But of course! Clutching at optimism in the face of contradictory experience --from the databases being down, to uncaught exceptions beinging thrown, to files not be found, to permissions not granted-- is what defines a Panglossian Programmer.

Surely you know the type. If not by their philosophy then by their actions. You can spot their code almost immediately as it looks something like this:

string[] text = File.ReadAllLines("c:/Log/log-file.txt"); foreach (string s in text) { Response.Write(s); }

Or the slightly less glarring, but more dangerous:

string action = Request.QueryString["action"]; if (action == "load") { User user = new User(); user.Load(); } else { User user = new User(); user.Delete(); }

The problem with the first example ought to be obvious. Our Pangloss just assumes that the file will be there, that it can be opened, etc. There is no try/catch, no assert statement, no nothing. Just a belief that this is the best of all possible worlds!

In the second example, things are slightly less glaring and so all the more dangerous. Here it is assumed that there are only two options, either the value of action is load or it is not --which to the Panglossian Developer means it must be the assumed value of delete. But of course the user could have passed in asdfsdaf as the value of action and still have their record deleted. The If/else construct, despite its appearance, does not capture the developer's assumption that there are only two legitimate values. And it is this assumption --that either the value of action is load or it is delete-- which must be expressed.

string action = Request.QueryString["action"]; if (action == "load") { User user = new User(); user.Load(); } else if (action == "delete" ) { User user = new User(); user.Delete(); } else { throw new ApplicationException("I am sorry, that action is not recognized."); }

This is what developer meant to say. Now if the world turns out not to be so rosy things will still turn out as expected.

The Check List:

The Best of All Possible Worlds I know that this lesson may seem basic, but the fact is I've seen even the most seasoned developer write code that would make Pangloss blush. At the risk of being too philosophical or pedantic: knowing the Good is not sufficient for doing the Good. Most Panglossian Developers I know would agree that the world of software development does not support such optimism, but when you look at their code they develop as if it did!

So as to not to belabor the point, I've put together a quick list of reminders to keep your coding pessimistic, defensive, and gloomy. Please note that these are heuristics and slavishly following them can result in code that is overly complex. As always, use your judgment and be aware of the various trade-offs in your approach.

  • Distrust everything and everyone. Most of all distrust yourself. (This can be taken too far and result in mental paralysis. So distrust even the degree to which you ought to distrust yourself. If paralysis ensues, suspend distrust until equilibrium returns.)
  • Be explicit. If you think the value of a variable should be either X or Y then say so. Don't just say that if it not X then it must be Y. There is always a Z out there! Always remember that your code not only tells the application what to do, it also expresses your understanding of what the application should do. Code is your best documentation and as such it should reflect your complete understanding of the problem and its parameters.
  • Assert yourself. Never rely on comments to prevent anything. If you don't want something to happen, e.g., if you wanted the value of int account to be less than or equal to 100 then assert that fact in the code. E.g., Debug.Assert(account <= 100, "Account should be less than 100");
  • Defense in Depth. This is not just a good practice for security, but a good programming practice in general. Check values and assumptions at each layer of the application. Don't just assume that if an input has been validated at the presentation layer that you can safely consume it in your business logic layer.
  • If it can fail, code as if it will fail. If you are trying to open a file, code as if you cannot open the file. If you need to write to a database, code as if you cannot write to the database.
  • Log Prolifically. If it seems like it should be logged, log it. Log as if it will be your only evidence against criminal charges. Log as if you think War and Peace is a short story. If you go log-crazy you can always selectively turn off some of the logging later. (If you need some help setting a logging utility, read my article "Log4Net: The Definitive(?) How-To for Those Who Have Already Experienced Some Degree of Frustration Trying to Set It Up the First-Time Around")
  • Try/Catch. I hesitated on including this one as I have seen Try/Catch used and abused. This is a relatively expensive operation so use judiously. That being said, for most applications if a Try/Catch is warranted use it and if it turns out to unacceptably impact performance, refactor.
  • Try/Catch Again. Don't just catch ApplicationException and then go off on your merry way. And don't let all exceptions bubble up to the Global.asax Application_Error event. If you think it is a SqlException, then catch it as a SqlException and log the specific information that exception contains.
  • Think: Actually say to yourself, "Hmmm... I wonder if this code takes account of all the possibilities. What if [fill in blank]?" Not to seem trite, but thinking is hard work so give yourself the time to think the issue through.
  • Last bit: The last item could be expanded to book length so I will just speak its name and say one or two words, namely: TEST. Test, test, and more test. If you think you are done testing, test some more. It is only by actually trying to break your code that you'll discover how easy it is to break.

Conclusion:

Since we started with Candide, we will end with that most fateful and oft quoted line: "I’m through, I must give up [Pangloss’] optimism after all... It is a mania for saying things are well when one is in hell." Let us all recognize the same!

Comments

Subject Name Date Submitted
Well written, very funny
Nick Duggan8/25/2006 12:53:31 AM
Great Article
Alexander Delafield8/25/2006 10:42:58 AM
Hmmm.....
William Ramirez8/25/2006 4:08:42 PM
re: Hmmm.....
Chad Finsterwald8/25/2006 4:31:20 PM
Nicely expressed
Chuck Miller4/27/2007 9:48:57 PM
New Comment
(Your email address will not be displayed or shared.)
Please enter the code shown below. If you cannot read it, press "reset image" to generate a new one.