Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Confessions of a terrible programmer (kickin-the-darkness.com)
66 points by albertcardona on March 14, 2009 | hide | past | favorite | 41 comments


Humility is certainly something to strive for, however I disagree that you should envision yourself as a "terrible" programmer.

One thing I've learned the hard way is that self-deprecation only works in British comedy. In the USA most people don't get it and it not only damages your career but your dating and social life, too.


One thing I've learned the hard way is that self-deprecation only works in British comedy. In the USA most people don't get it and it not only damages your career but your dating and social life, too.

The greatest (or second greatest, depending on your opinion of "The Honeymooners") and most popular sitcom in American television history was almost entirely based on self-deprecation (Seinfeld).


Self-deprecation is a survival mechanism in Australia, what with the tall-poppy syndrome. But you're right -- very different in the US.


This is an interesting and apparently culture-dependent difference. Can you elaborate a bit on this, please?

How it works, and why is it like that? What's the mentality behind people's minds there? Does it hold for everyone, just geeks or everyone but geeks?

What do you have to say in order to look good? How truthful -- I mostly agree with the article -- can you stay while still keeping other people thinking you're good?


Think of it as analogous to bling. If you wear lots of gold, drive a sports car, etc, you're showing you've got enough cash to blow it on non-essentials. If you're self-deprecating, you show that you have enough status to waste it by downplaying your achievements.


Sorry, I should have been more explicit; I meant the other way around.

The self-deprecating dynamics I get, the U.S. version I don't -- probably just because of that :-) I would still appreciate thoughts on why and how?


I enjoyed this article. Humility is certainly something to strive for, however I disagree that you should envision yourself as a "terrible" programmer. Just approach each problem as a student, not an expert.

I doubt Wayne Gretzky skated down the ice thinking "I'm a terrible hockey player", but I do know that he was a student of the game and as a result, one of the hardest working players both on and off the ice - with the results to prove it.


I believe that there is value in humility as a programmer. I can't speak to hockey.

I don't view myself as a student, that leaves the door open to hubris, and hubris is the primarily failing of programmers. Accept that you are a terrible programmer and that you will fail, you will make the wrong decisions, and you will design poorly. Plan accordingly, and you'll be more successful than all the other terrible programmers.

I am a very successful programmer because I do not trust myself to write great code. I leverage the type system, the compiler, and many other points he discussed in his article. By leveraging these tools, I prevent myself from failing as often or as severely.

I have rarely seen programmers fail so profoundly as those who hold the belief that they are too smart -- too good of a programmer -- to fuck up.


"I have rarely seen programmers fail so profoundly as those who hold the belief that they are too smart -- too good of a programmer -- to fuck up."

Well put.


Your post reminded of Gladwell's piece on "Physical Genius"

http://www.gladwell.com/1999/1999_08_02_a_genius.htm

From the article:

What sets physical geniuses apart from other people, then, is not merely being able to do something but knowing what to do--their capacity to pick up on subtle patterns that others generally miss. This is what we mean when we say that great athletes have a "feel" for the game, or that they "see" the court or the field or the ice in a special way. Wayne Gretzky, in a 1981 game against the St. Louis Blues, stood behind the St. Louis goal, laid the puck across the blade of his stick, then bounced it off the back of the goalie in front of him and into the net. Gretzky's genius at that moment lay in seeing a scoring possibility where no one had seen one before. "People talk about skating, puck-handling, and shooting," Gretzky told an interviewer some years later, "but the whole sport is angles and caroms, forgetting the straight direction the puck is going, calculating where it will be diverted, factoring in all the interruptions."


Not just humility: the author goes on to explain all his practices to defend himself from himself. These attracted my attention, for no programmer I know enjoys them:

3) Be a testing masochist, i.e., I ruthlessly try to break my own code.

4) Have other programmers inspect my code.

The author goes on to explain how he approached fixing a broken program: to stop catching errors and letting it crash. Which meant getting stack traces and fixing them on the spot. Combined with his aggressive use of assertions, no wonder he fixed it.


These attracted my attention, for no programmer I know enjoys them...

Really?

Maybe I have competitive split personalties, but testing my code is a lot of times more fun than writing it. And at least for junior developers, getting feedback from those with more experience is probably the most valuable part of a job.

It kind of blows my mind to hear that some programmers commit code they haven't thoroughly tested, or avoid showing their code to other people...


> 3) Be a testing masochist, i.e., I ruthlessly try to break my own code.

'Hap' means luck. Therefore, the happy path is the lucky path. Being a natural pessimist, I can't help picturing unlucky paths and believing they will be followed. So I enjoy trying to break my code. Not trying to sound arrogant here, I also think of end users and client coders as "idiots." I find joy in trying to make stuff "idiot-proof." A humbler term would be "bullet-proof," but I picked up "idiot-proof" almost thirty years ago, and I'm stuck with it.


To me, the author is like someone who will never really learn to swim well because he can't let go of swimming aids. Dependence on crutches like compile time checking and programming assertions might let you fake it, but there are more productive ways (and languages) to write working code.

1. Compile time checking can't catch most non-trivial bugs. Even if you swear by it, given the advances in Java IDEs, I would have to be quite lazy (or careless) to write Java code that doesn't compile.

2. Programming assertions - really? That's what unit testing is for. I like his point about being a testing masochist, but it doesn't sound like he's going about it the right way.

3. Having other programmers inspect your code can be helpful, but to me it's a luxury that you often can't afford.

"If I could bring this kind of a system to fruition, meeting all its requirements and budget and schedule constraints, just by conscientiously applying a slew of techniques for uncovering my programming failings before they got into the final product, then I knew that I would be able to fake it for the rest of my career."

The author claims his techniques have allowed him to create a good end-product, but at what cost? I could 'fake it' for the rest of my career, or I could invest more effort in learning how to write better code faster in the first place.


"Compile time checking can't catch most non-trivial bugs. Even if you swear by it, given the advances in Java IDEs, I would have to be quite lazy (or careless) to write Java code that doesn't compile."

You should not underestimate the power of leveraging the type system to prevent programmer error.

Do not think of the type system as a nanny. Instead, think of it as an integral language tool designed for your use. Use this tool -- the type system -- to convince the compiler enforce code correctness. Using the type system in this way will allow you to spend less time writing tests, as compilation can validate correctness.

If this seems unlikely, spend time with a language with a powerful type system -- such as OCaml, Haskell, Scala or F#. You will find that it is possible to implement equally succinct and considerably more correct code through leveraging language features -- including the type system.

Additionally, this exercise is fundamentally applicable with the real world. Should you use F# or Scala, you will find a vast trove of existing libraries, and high-quality, high-performance VM implementations at your fingertips. Your correct code, written faster, will run faster.


"I could 'fake it' for the rest of my career, or I could invest more effort in learning how to write better code faster in the first place."

Uh, the techniques he describes are how you write better code faster in the first place.

There's no magic "better code" fairy that comes along and instantly makes you a master programmer. You get better by deliberately seeking out ways in which you're failing, and then correcting them. And you use the techniques the article describes - code reviews, assertion, unit tests, and static typing - to do that.

Eventually, those techniques become internalized, so that you still do them even when you take away the crutch of language and programming environment.

Notice how studies of master Smalltalk and Erlang programmers found that they just don't make type errors, and that when you add a static type checker to those languages, existing programs pass unmodified? A lot of people have taken this as evidence that static typing isn't necessary. But there's another interpretation: master programmers write their programs as if they were statically-typed, even if the language itself does not require or enforce this. The reason they can get away with fast-and-loose programming languages is because they've already disciplined themselves into automatically doing what the strict programming languages enforce.

And anecdotally, the vast body of crappy PHP and JavaScript code seems to support this interpretation.


That's what unit testing is for? True, and do you understand the trade-offs? Unit testing is far more time consuming than assertions. Moreover, you're forced to write artificially short routines, routines of a length that research has shown to have a higher defect ratio. For myself, I've not yet been convinced that the costs/benefits of unit testing surpass the costs/benefits of assertions, at least when you're a small team working on end user software.


"Moreover, you're forced to write artificially short routines, routines of a length that research has shown to have a higher defect ratio" [citation needed] So far I've only seen advice to write shorter routines.


Indeed, I don't see how smaller, more manageable pieces would be more likely to be defective.


Somebody posted a study which showed, IIRC, that ~150 lines was the optimum length for subroutines. I really should bookmark these things...

EDIT: Hooray for searchyc:

http://news.ycombinator.com/item?id=509978


If you upmodded it, it's bookmarked under the "saved" section of your profile.


I don't care how much coverage your unit tests have, basic sanity-check assertions are the foundation of defensive coding.


If I can’t use Ada, well, then Java is the next best choice, since it’s got a lot of the same built-in bug detection capabilities.

Seriously? Java has less runtime checking than Perl, and its compile-time type checking prevents only the most trivial errors. If you want to talk about bad type systems, look no further than Java. (Of course, the same could be said about C++ and C too. There is even less of a type system there.)


The same could be said about C++. C is a weakly typed language and was designed to be so, so it's type system cannot really be said to be 'bad'.


Yes, good point. But a lot of people cite C as "the" strongly and statically typed language, and that's just wrong. ("But omg, you have to say 'int i' instead of 'var i'. Clearly this is strong typing!")


C has no types, as a quick (int*)&var will show.


Unfortunately, this is not true in the case of type punning. C used to be the language you used when you wanted to access bits. Now with C99 you cannot * (int16* )((int32* )x).

NB, all compilers make exceptions for unions, but the type punning rule stands, and at work we've actually seen code like the above (for a dynamic typing system) compile to NULL instead of the appropriate reference with GCC. Grrrrrrr.


Being able to subvert the type system is different than having no type system.


This attitude just wouldn't work for me - if I didn't feel like a great programmer and I didn't enjoy coding/designing/testing/releasing so much I would change my job.

Relying on tools and techniques may help me coast through my career - but where's the fun in that? Tools and techniques are all well and good, but they can't become the crutch you lean on.

And please, please - do try more languages than just Java/C/C++/Ada.

I program in C/C++ with a team of very talented developers. None of us are humble, all of us believe we can be the best and we have a lot of fun. Plus our product is great!


Well, I view it as a little different than feeling like a bad programmer. Basically-- you get to a point when you realize "The most important trick to being an amazing developer is always sincerely doubting, checking, and double-checking that fact." I feel sorry for developers who believe they're amazing without that-- they won't truly be good until that feeling dulls somewhat and they start verifying their code by habit as if they were newbie developers.

In my case, I view it more like how Socrates does: "One thing only I know, and that is that I know nothing."

Design and implement as brilliantly as one can, but then use all the tools available to protect oneself from the possible dumbass mistakes that humans inevitably make.


It's more fundamental than that - if you don't feel like a great programmer then the techniques described (static checking, unit testing, code reviews) become what you depend upon rather than just tools of your job.

For instance, code reviews are great - but maybe you can't use them in your one-person startup. That shouldn't stop you from still writing great code! It may be harder - yes, but you have to have the confidence that you can do it.

I mean consider the author's dependence on static checking. There are a lot of wonderful dynamic languages available (and a lot of great programmers in those languages too!). The author - because of his philosophy of being a "terrible programmer" is simply going to miss out on whole genres of languages and techniques.

IMHO great programmers have confidence in themselves - just as in any other field. Tools and techniques are really secondary.

EDIT: Grammar.


Ok I admit that when I used BASIC back in 1979, I put GOTOs in my code.


So what?

GOTO isn't evil, it just has no meaningful context without a comment or convention. All the classic 'structured programming' control structures are nothing but simple conjugations of conditional GOTOs -- what they provide is idiomatic context.


E.g.:

  clisp> (macroexpand '(dotimes (i n) blah blah blah))

  (BLOCK NIL
    (LET ((I 0) (#:COUNT-2814 N))
      (TAGBODY
        #:LOOP-2815
        (IF (>= I #:COUNT-2814)
            (GO #:END-2816))
        BLAH BLAH BLAH
        (PSETQ I (1+ I))
        (GO #:LOOP-2815)
        #:END-2816
        (RETURN-FROM NIL (PROGN NIL)))))
(goto in Common Lisp is (go ...) )


Of course we all understand (or are forced to use) structures now, but back then GOTOs were evil. We did not have the structural classics we have now. We had to build them. (and use them).

Naked GOTOs were indeed evil and led to endless loops and sleepless nights. There was no structure to them.

Pascal was our savior.


I smile when I think of Ruby's throw/catch (not to be confused with raise/rescue) as labeled GOTO.


There's the thing between how good you think you are and how good you are when compared to others.

To be honest if you're any smart you will, no matter what, eventually realise that you're actually pretty bad. There's so much you don't know yet and lots and lots of things that bug you because you know you could have done better! This will keep you on toes which in turn makes you better than others. Conversely, it'll be quite a shock to a smart person to realise that others really aren't that smart, far from it.

This phenomenon has actually been studied: after doing some tests good students tend to think they did bad and assume that everyone else is at least on the same level, while bad students tend to think that they're actually pretty good and then assume that most other people must have done it worse.


As long as we're talking about programming and (teehee) ego-dissolution: "There are two major products that come out of Berkeley: LSD and UNIX. We don't believe this to be a coincidence." - Jeremy S. Anderson


I enjoy the line and, living next door to Bezerkley, I take the point, but LSD was invented in Switzerland (by Albert Hofmann) and Unix came out of New Jersey.


I didn't understand object oriented programming until I understood the limits of my brain.


I only started understanding it when I realised that it wasn't that important.

I think many young programmers are mystified by OOP because they feel as if it's a magic bullet that's supposed to solve all of their problems. When you start out trying to understand OOP you can't figure out how it's going to solve those problems...

IMHO OOP has its place, I use it daily, but it's hardly ever my first approach when trying to solve a problem.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: