I think you could make a very compelling argument that programming is simply the practice of making trade offs. Minute after minute, day after day, week after week, we're presented with these tiny little choices. The simplest choice in the life of a programmer is, of course, "on" or "off", one or zero. But few of us even need to get that close to the mind of a machine anymore. Languages like Ruby are often a joy to use because they provide such abstraction from that on or off world. By building abstraction on top of abstraction, they've given us a multitude of ways to express what it is we want those pesky machines to do.
But try as we might, we never quite get to that point where we can turn off our brains and let the machines do all the thinking – so that we simply tell them to make us breakfast (or some other absurd techno-utopianism) and have them serve up the perfect meal: exactly what we wanted, how we wanted it, efficiently delivered, and all that jazz. I mean, how would we even begin to do such a thing? First we'd have to figure out how a machine could figure out what you liked. Perhaps it could observe you and see that every morning you make yourself some toast, pour a glass of orange juice, and have a bowl of cereal (if this breakfast seems rather uninventive, it's because I hardly ever eat breakfast, which I know is very, very bad for me – but then we all do things that are bad for us, don't we?). And by observing the frequency and types of food, it could quite easily infer that a "good" breakfast to make would be one including toast, a glass of orange juice, and a bowl of cereal. But what if you were only doing that because you were a complete buffoon in the kitchen (like me)? What if you really wanted it to create exotic breakfasts from around the world for you? A new one every day! Well then, maybe we should introduce an element of randomness into this machine. Perhaps, every so often, it rolls the dice and picks a meal you haven't had before, no matter what it's observed. As a further refinement, maybe we'll let you vote after each meal whether you liked it or not, and the machine can keep a record of these and infer better random choices for future breakfasts from the data it collects... well, this is going to totally piss off the guy who just wants the machine to make him some damned toast and orange juice and cereal! It's the 21st century! Come on! This isn't too much to ask, is it? (Don't lie... you all know someone like this.)
Hopefully this gives any of you non-programmers a little more insight into how us programmers think (and to the programmers, perhaps it can give some good arguing material when your friends bug you about thinking too much about things – of course you think too much about things... thinking too much about things is your job!). As I've (hopefully) demonstrated above, we can even turn a simple breakfast into a war of algorithms. None of them is "the right way" to go. But each of them might be the best choice depending on your target user. Want to cater to grumpy old men who like their routines? In that case, the first, less complex, algorithm above is the way to go. But for the adventurous connoisseur (aka "the power user"), complexity is ideal because it means they have more switches and buttons to play with in order to tweak it into what they consider the perfect breakfast making machine.
But that's all still terribly high level for us programmers. Not even close to the necessary ones and zeros that are the only things machines will really understand (and even that, of course, is being very loose with the definition of understanding). The choices that keep us programmers awake at night are written in code.
One such typical code-based dilemma is the choice between hardcoding and making generic components. Especially with complex business logic, where it's sometimes arguable as to what constitutes the sinful act of "hardcoding" and what doesn't. After all, the ideal generic component is the computer itself. If everyone could program, we'd only really need one application, and that application would allow us to do absolutely everything given the right commands. So, at least sometimes, the more generic something is, the less user friendly it will be. And yet every programmer I know has at least in one point in their careers, striven towards this ideal generic code that will do anything and everything. It drives managers nuts. It drives us nuts (though it's an intoxicating sort of madness). And eventually, if we stay in the field, we learn to draw often arbitrary lines as to what's going to far and what's just being a lazy hack. Hard core religious folk ain't got nothin' on how heated these ideology debates can be!
Another common decision is between decoupling and duplication of effort, which is actually the thing that came up today at work that prompted this post. Here it gets to be even more fun and more difficult for your friendly neighbourhood programmer, as decoupling and the avoidance of duplication are practically stone tablet material when you're learning your trade. But it's pretty difficult to get both in ideal quantities. More often than not, you have to choose.
And at this point, you're wondering if I'll ever explain the title of this particular post. Well, here it is...
The point I'm trying to make above is that, although programming is often seen as a science where it's possible (if we're just smart enough, damn it!) to make a computer do exactly what it needs to for a particular industry or user, the real world calls on us to be artists (which is not so bad for those of us who like being artists) as well, who sometimes need to make choices they might not even be able to explain, based on time and circumstance. And yes, even very good programmers can feel very stupid trying to explain why they went one direction as opposed to another when suddenly all hell breaks loose and that other direction starts to look like the road to paradise. "Well, yes, with hindsight, that is certainly the way we should have gone! But you see, at the time, well, there were certain objectives and, well no, I can't quite remember what they were, but there was a reason we went this way in the first place, I swear!"
That's where "the confessional" comes in. If I've stolen the term from someone else, please accept my sincere apologies, but among the programmers that I know, I do believe I've at least led the charge in advocating it.
There have been several times in my career that I've faced some agonizing decision where I either wasn't sure which way was the best way to go, but had to pick one, or I simply saw the possibility of negative consequences down the road but knew there was not enough time to cover every possibility. And there were also times where I outright hacked something together because it had taken too long, I had too little understanding to make a proper solution (and no one else to ask), or the coffee wasn't strong enough to de-fuzz my brain that day. There's always a tendency to either be paralyzed by indecision or to make the choice silently and hope no one discovers your secret code-crime.
Avoid this. Write a "confessional". Every decent programming language gives you this beautiful structure called a "comment", which allows you to babble on to your heart's content about how frustrating a problem is or how you know this is an awful thing to do, but you really had no choice! Use it. Get it all out. You don't even have to make the machine understand it. You won't make the program less efficient (compilers usually strip these out, and in non compiled languages, it's easy to write something to do the same thing). And even the odd page-long confessional won't have your fellow programmers snickering behind your back about what a hack you are. Well, maybe. But you shouldn't worry about it.
No matter how long they've been (and I've had some long ones), I haven't once had a fellow programmer bring up one of my "confessionals" as criticism. On the contrary, people have actually said thanks at times, seemingly out of nowhere, long after I've forgotten writing it, because they were chasing down something to do with the problem or considering making some change that I had considered and decided against (but talked about in the "confessional") and by writing down my horrible coding transgressions and why I made them, I saved them from doing bad things they hadn't considered. Other times, I've run into my own "confessional" in trying to explain to a manager why something's the way it is and not quite being able to make a good enough argument. I suddenly hit the "confessional" and say, "Oh yeah, now I remember! It was because..." I really don't think managers care so much whether you make the odd bad decision. I think they're more interested in whether you care about what you're doing. And combining a "confessional" with something you see as a possible code-crime is a good way of showing that you care about what you're doing, even when you can't do it perfectly, for whatever reason.
Caveats. First, if you tend to write more "confessional" than code, you should perhaps consider another career. Just like swearing, a "confessional" is more effective when used sparingly. (I've always gotten a kick out of adults who desperately try to get kids not to swear, usually by admonishing them, with varying degrees of harshness, over it. I think a much better way of attacking this one is to convince them that a word like fuck is way more shocking when it comes out of nowhere... especially after 1694 much more innocent words!). The second thing is that, on longer confessionals, it's considered courteous to stick the odd joke (geeky in-jokes even better!) in there as a sort of "thank you" for someone else taking the time to slog through it all.
With those caveats in place, programmer friends, go forth and write wonderful code! Repent less, confess more, and be merry!