11/22/2011

11-22-11 - The Mature Programmer

1. The Mature Programmer

The mature programmer manages their own time and productivity well. The MP knows that maintenance is as much work as the initial writing
and code always takes longer than you think. The MP knows that any changes to code can introduce bugs, no matter how seemingly trivial.
The MP knows that premature optimization is foolish and dangerous. The MP knows that sexy coding like writing big complex systems from
scratch is rarely the best way to go. The MP does not get into ego competitions about who has the prettiest code. The MP acheives the
best final result in the minimum amount of time.

When I started at Oddworld, I was watching lots of game companies get into dick-waving contests about who had the greatest home-rolled
graphics engine, and I was also watching lots of indie developers spend massive amounts of time on their "one true" product and never
actually ship it. I resolved that we would not fall into those traps - we would be humble and not reach too far, we would not let our
egos stop us from licensing code or using old fashioned solutions to problems, we would stay focused on the end product - any sexy code
that didn't produce a visible benefit in the actual shipping game was nixed. For the most part I think we succeeded in that (there were
a few digressions that were mainly due to me).

But the way of the Mature Programmer can be a trap which comes back to bite you.

The problem is that writing code in this way is not very much fun. Sure there's the fun of making the product - and if you're working on
a game and believe in the game and the team, then just seeing the good product come out can give you motivation. But if you don't have
that, it can be a real slog.

Most of us got into programming not for the end products that we create, but because the programming itself is a joy. Code can be beautiful.
Code can be a clever, artistic, exciting creation, like a good mathematical proof. The Mature Programmer would say that "clever code is
almost always dangerous code". But fuck him. The problem is that when you get carried away with being "mature" you suck the joy right out
coding.

You need to allow yourself a certain amount of indescretions to keep yourself happy with your code. Sure those templates might not actually
be a good idea, but you enjoy writing the code that way - fine, do it. Yes, you are optimizing early and it just makes the code harder to
maintain and harder to read and more buggy - but you love to do that, fine, do it.

Obviously you can't go overboard with this, but I think that I (and many others) have gone overboard with being mature. Basically in the last
ten years of my evolution as a coder I have become less of a wild card "hot shot" and more of a productivity manager, an efficient task
analyzer and proactive coordinater of code-actualizing solutions. It's like a management beaurocracy of one inside my head. It's horrible.

I think there are two factors to consider : first is that being "mature" and productive can cause burnout which winds up hurting your productivity,
or it can just make coding unpleasant so you spend fewer hours at it. Most "mature" coders brag about the fact that they can get as much
done in 6 hours as they used to do in 14. But those 14 hours were FUN, you coded that long because you loved it, you couldn't get to sleep
at night because you wanted to code more; now the 6 hours is all sort of unpleasant because instead of rolling your own solution you're just
tying together some java and perl packages. Second is that being productive is not the only goal. We are coding to get some task done and to
make money, but we're also coding because we enjoy it, and actually being less productive but enjoying your coding more may be a net +EV.

2. The healthy opposition of a producer

Many programmers in normal coding jobs hate having the interference of a producer (or corporate management, or the publisher, or whatever).
This person enforces stupid schedules and won't let us do the features we want, and urrgh we hate them! These coders long to be able to
make their own schedules and choose their own tasks and be free.

It's actually a very healthy and much more relaxing in many ways to have that opposition. When you have to schedule yourself or make your
own decisions about tasks, you become responsible for both the creative "reach for the sky" side and the responsible "stay in budget"
side. It's almost impossible to do a good job of both sides. This can happen if you are an indie or even if you are a powerful lead with
a weak producer.

Most creative industries know that there is a healthy opposition in having the unconscrained creative dreamer vs. the budget-enforcing
producer. You don't want the dreamer to be too worried about thinking about schedules or what's possible - you just want them to make
ideas and push hard to get more.

When you have to cut features or crunch or whatever, it's nice to have that come from outside - some other force makes you do it and you
can hate them and get on with it. It's nice to have that external force to blame that's not on your team; it gives you a target of your
frustration, helps bonding, and also gives you an excuse to get the job done (because they told you to).

When you have to balance dreams vs schedules on your own, it adds an intellectual burden to every task - as you do each task you have to
consider "is this worth the time? is this the right task to do now? should I do a simpler version of this?" which greatly reduces your
ability to focus just on the task itself.

3. Coding standards

It's kind of amazing to me how many experienced programmers still just don't understand programming.
The big difficulty in programming is that the space of the ways to write something are too large. We can get lost in that space.

One of the problems is simply the intellectual overload. Smart coders can mistakenly believe that they can handle it, but it is a
burden on everyone. Every time you write a line of code, if you have to think "should I use lower case or mixed caps?" , or
"should I make this a function or just write it in line?" , your brain is spending masses of energy on syntactic decisions and doesn't
have its full power for the functionality. Strict coding standards are actually an intellectual relief because they remove all
those decisions and give you a specific way to do the syntax.
(The same of course goes for reading other people's code - your eyes can immediately start looking at the functionality, not try to
figure out the current syntax)

The other big benefit of coding standards is creating a "meta language" which is smaller than the parent language and enforces
certain invariants. By doing that you again reduce the space that the brain has to consider. For example you might require that
all C macros behave like functions (eg. don't eat scopes and don't declare variables). Now when I see one I know I don't have to
worry about those things. Or you might require that globals are never externed and only get accessed through functions called
"GetGlobal_blah". It doesn't really matter what they are as long as they are simple, clear, uniform, and strictly enforced,
because only if they are totally reliable can you stop thinking about them.

4. The trap of "post-Mature Programmer" ism.

Many great coders of my generation have gone through the strict clean rules-following coder phase and have moved onto the
"post" phase. The "post-mature programmer" knows the importance of following strict coding style rules or not indulging themselves
too much, but also sees the benefit of bending those rules and believes that they can be a bit more free about deciding on
what to do for each situation.

I believe that they/we mostly get this wrong.

The best analogy I can think of is poker. Most successful poker players go through several phases. First you think you're ever so
clever and you can bluff and trap people and play all sorts of weird lines. Once you move up levels and start playing serious poker
this delusion is quickly wiped out and you realize you need to go back to fundemantals. So then most people will go through the
TAG "standard line" phase where they learn the right thing to do in each situation and the standard way to analyze hands, and they
will be quite successful with this. (note that "standard line" doesn't mean nitty, it involves things like squeeze plays and even
check-shove river bluffs, but it's based on playing a balanced range and studying EV). But then they are so successful with their solid play
that they start to think they can get away with "mixing it up", playing hands that are almost certainly not profitable because they
think they are good enough post-flop to make up for it (eg. Durrr style), or imagining that by playing some minus EV hands it helps their image and pays off
later.

This is almost always wrong. Limping AA is almost always wrong, opening 72o UTG is almost always wrong - maybe you've done some analysis
and you've decided it's the right thing at this table at this moment (for example limping AA because the people behind you attack limpers way too much
and they think you would never limp AA so they will get stuck easily). It's wrong.

(telling yourself that your current bad play is made up for with
later "image value" is one of the great rationalizations that poker players use an excuse to justify their bad play.
programmers due to same with a set of excuses like "performance" that are really just rationalizing justifications
for their bad practices; with poker, EV in the hand is worth more than EV in the bush; that is, the later image value
you might win is so small and dubious and depends on various things working out just right that it's almost never
correct to give up known current value for possible future value. (a particularly simple case of this is "implied odds"
which bad players use an excuse to chase hands they shouldn't))

The problem is that when you open yourself up to making any possible move at any moment, there is simply too much to consider. You can't
possibly go through all those decisions from first principles and make the right choice. Even if you could, there's no way you can sustain
it for thousands of hands. You're going to make mistakes.

The same is true in coding; the post-MP knows the value of encapsulating a bit of functionality into a struct + helpers (or a class), but they
think I'm smart enough I can decide not to do that in this particular case. No! You are wrong. I mean, maybe you are in fact right in this
particular case, but it's not a good use of your brain energy to make that decision, and you will make it wrong some times.

There is a great value in having simple rules. Like "any time I enter a pot preflop, I come in for a raise". It may not always be the best
thing to do, but it's not bad, and it saves you from making possibly big mistakes, and most importantly it frees up your brain for other things.

The same thing happens with life decision making. There's a standard set of cliches :

Don't marry the first person you sleep with
Don't get in a serious relationship off a rebound
Don't buy anything if the salesman is pushing it really hard
Take a day to sleep on any big decision
Don't lend money to poor friends
etc.

you may think "I'm smart, I'm mature, I don't need these rules, I can make my own decision correctly based on
the specifics of the current situation". But you are wrong. Sure, following
the rules you might miss out on the truly optimum decision once in a while. But it's foolish arrogance to think that
your mind is so strong that you don't need the protection and simplicity that the rules provide.

In poker the correct post-solid-player adjustment is very very small. You don't go off making wild plays all the time, that's over-confidence in
your abilities and just "spew". A correctly evolved player basically sticks to the solid line and the standard way of evaluating, but knows
how to indentify situations where a very small correction is correct. Maybe the table is playing too tight preflop, so in the hijack
position you start opening the top 35% of hands instead of the top 25% of hands. You don't just start opening every hand. You stay within
the scope of the good play that you understand and can do without rethinking your whole approach.

The same is true in programming I believe; the correct adjustment for post-mature coding is very small; you don't
have to be totally dogmatic about making every member variable private, but you also don't just stop encapsulating
classes at all.

I liked this post and it was well written. I suspect it missed one thing which is rather important though. Your model of mature programmer rapidly leads to post-career-programmer. Those very rules which make one's code safer also ossify your technique. The world moves on and you do not. One day you find yourself on legacy maintenance and then the job queue.

1) So - learn new rules.

But that will not get you to the next stage. Now you will not get out of date but your rules will prevent you from creating something new. The very best programmers create something new every so often. But it is important to keep the new stuff out of the main code stream until you are sure about it.

Really well written, a lot of things I can self-reflect upon. I also love the poker analogies, since next to programming I have been an avid poker player for 4 years (unti it burned me out, for like a lot of the reasons programming sometimes burns me out...but atleast that DOES give me a stable paycheck :) )

I started my career believing strongly in coding standards. But I have discovered it's impossible to get people to agree on standards, and they need to be able to read code posted online from outside our standards anyway. Then you change jobs and they use different standards. So you just have to get used to reading anything, that's the mature way.

Now I believe more in TDD. I don't care if one of my peeps uses Member, member, or _member as long as there's tests for that class, and they've applied an appropriate pattern for the problem.