Certification? Please, no.

I want to respond to this post over at Raganwald. Rather than trying to fit some overarching scheme together, it’s just going to be a collection of random vignettes and rants. Much easier to write.

First- if you have twenty years of experience, heck, if you have five years of experience, and a prospective employer is wondering where you got your degree, flee in terror. That is not a place you want to work- unless you’re applying for a job in HR. Five years of experience in the industry is a much better judge of what you are or are not capable of than the fanciest- or plainest, or even lack of- degree. Some of the best programmers I know have never quite managed to finish that bachelor’s yet. And some of the worst programmers I know have PhDs in Comp Sci. I should also mention that some of the other best programmers I know have PhDs in Comp Sci, and some of the other worst programmers I know don’t have bachelor’s yet either. In fact, my experience has been that advanced degrees have little correlation, positive or negative, on quality of the programmer.

The other correlation I have noticed is that the “commercial” certifications do have a strong correlation with competence- a negative one. “MCSE” stands for “Must Consult Someone Experienced”.

The problem, I think, is one of culture. Go back in time to, say, the 50’s or 60’s. Back then you had two clear social tiers. You had the white collar workers- who wore suits and ties and shined shoes, drank wine or martinis, worked in nice, clean, airconditioned offices and made a lot of money and managed people. And you had blue collar workers, who wore jeans and tshirts and boots, drank beer, worked in ugly, uncomfortable factories or outside, made less money, and generally managed (moved, manipulated) things. Even the socialization with coworkers rules were different- blue collar social structures were generally much flatter, and after-work socialization was common (“the whole line, even the line foreman, would go out for a beer after work”). White collar society had a much stricter social heirarchy.

And the nice thing about blue collar workers, from the point of view of white collar workers, was that they were interchangeable and expendable. They were generally very easy to fire and replace. Don’t like the way the guy on line 3 is looking at you? He’s gone, bring in the next guy. This was even more pronounced back in the late 19th, early 20th century when these castes were developing, before Unions got going in a major way. Back when Henry Ford was a model of sensitive, caring management, because his hired goons only beat up union organizers and rabble rousers, instead of killing them.

Now we have this weird third class- the informational technical class. In many ways they have the social markers of being blue collar- they wear jeans and tshirts and boots (“just in case a mountain should crop up in the middle of the server room”), drink beer, and generally socialize like blue collar folks. On the other hand, they work in clean, comfortable offices and make a lot of money, like the white collar people. This new class is neither fish nor fowl, and I think there is a definate pushback. In the 80’s, there was an attempt to make this new class true white collar. Starting with you need to wear a suit and a tie to work, like a good little white collar drone. That didn’t last long.

So now I think there is a push in the other direction. Fine, if you won’t be forced to be white collar, you get to be forced to be blue collar. Starting with being replaceable. This, I think, is the great attraction certifications like MCSE has to those of a certain mindset- it brings with it an illusion of replaceability. Don’t like the way that programmer is looking at you? He’s gone. Bring in the next certified developer.

It doesn’t actually work that way, for reasons that are obvious to anyone who has been in the industry for more than about two weeks. But there is still the attraction there. And I don’t think any serious discussion of certification can be done without dealing with this issue- any movement to certify developers will be co-opted by the “old gaurd white collar” people and turned into a means to reinforce the desired social order.

That said, I think the beer and popcorn discussion of “if I were to design a programmer certification test” is still interesting (especially if it doesn’t lead to actually trying to implement the certification)- as what the topic really is, is “this is what I think is central to programming.”

Which allows me to segue back into discussing the meat of Raganwald’s post.

His certification test would cover (generalizing a little bit here):


  • testing

  • testing

  • testing

  • design for testing

  • testing

  • testing tools

  • testing metrics

  • testing methodologies

Um, OK. If you’re certifing a QA expert. But I thought we were certifing software developers.

Or, let me rephrase the question. What makes a good software developer? Testing? No.

I used to have a compsci teacher (I think it was compsci AP back in high school), who, whenever I was wrestling with some particularly hard bug, would ask me “if you didn’t mean the program to do that, why did you program it to do that?” At the time, I mainly wanted to beat him over the head with a chair when he said that, but with several decades of experience behind me, I now understand what he was trying to say- that the best way to prevent bugs is to don’t create them in the first place. And that testing is generally not the way you do this. To use Raganwald’s own analogy, an emphasis on testing for software developers is like an emphasis on cooks being able to recognize and treat anaphylactic shock. Professional QA people are not unlike the food tasters the kings of old days used to hire. While accidentally poisoning the king’s food taster was less of a big deal than accidentally poisoning the king, it was still a big deal.

By the time a bug hits testing, it’s a big deal- and the later in the testing cycle it is, the bigger the deal it is. I notice that all the developers who are all about waterfall design being a bad idea are all in favor of waterfall testing. With the exception of unit testing in test-infected cultures, testing is something that happens after the software is more or less “done”. Because the more extensive the testing is, the more expensive it is.

And you can’t make the argument that testing makes for better programmers. Programmers know that their code will be tested at some point or another- as the true final level of testing takes place when people use your program. And most programmers do not really want to write broken code- they just don’t know how not to. So they adopt a dangerous fatalism- bugs are going to happen anyways, testing (either unit testing, QA testing, or user “testing”) will discover them anyways, so why fight fate? Or as the old lady said, if it’s going to happen anyways, lie back and enjoy it.

Which brings up another point. Everything I learned in college, I needed to know in the real world. But not everything I needed to know in the real world I learned in college. And all the best programmers I know of have at least most of a bachelor’s degree. A compsci degree is not the worthless thing most people seem to assume it is. Heck, most of the theory I’ve learned, I’ve learned post-college. The problem, I think, is one of time. At least back in the 80’s, CS departments had to assume people entering the college had never used a computer before, let alone programmed anything before. So first they had to teach you how to long on, move around, edit files, etc. And then teach you introductory to programming, and basic theory and practice. Very basic, because there is only so much time.

Imagine, if you will, if the English department had to assume that students entering the program had never seen a book before, and did not know how to read. And that they had to first spend three years teaching the students to read and write, and basic grammar, before in their last year they could read “Hamlet” and “Moby Dick”.

The reason I bring this rant up is that he’s missed the whole point of static typing. Especially in the context of producing working, usefull code. But this isn’t surprising, given Raganwald’s “fair and balanced” look at static vr.s dynamic typing. And, just like that “fair and balanced” cable channel, the participants of the debate are carefully choosen to create an predetermined winner. I know this because the debate was between C/C++/Pascal (implicitly)/Java/C# on one side, and the dynamic languages like Ruby and Python on the other. Which makes the debate about as legitimate as the Hannity and Colmes show. Weirdos from Air America need not apply.

You probably have guessed (if you know me and/or if you’ve read this blog) that I’m going to bring up Ocaml here, and I am. Because static typing slots right into the code correctness argument. It wasn’t until OO programming became popular and heavily used that gang-of-four design patterns came to be understood- and it wasn’t until I started working in an environment of professional Ocaml programmers that I really started to understand the design patterns that real static typing allows/encourages you to use.

For example, which of the following program constraints can be enforced by Ocaml’s static type system:


  • That a given variable or parameter must be an int, and not a char or string or something

  • That all code paths of a function must return the same type.

  • That all possible variants of a type must be dealt with- for example, that a list has no elements or at least one element must both be handled.

  • That the read_async function only takes file handles opened with the async flag set, while the close function can take file handles with the async flag set or not set.

  • That the buffer returned from read_async can not be accessed until the asynchronous read is completed.

  • That a Postgresql cursor can only be created and accessed with a transaction.


This is, of course, a trick question- the right answer is “all of them” (the third from the last- read_async vr.s close- is handled by phantom types, the last two by monads. I’ll cover this in a later post).

The mantra here at Jane Street is “make illegal states impossible to represent”. Or, to quote my old CS teacher, “if you don’t mean it do that, don’t make it possible to do that!” And more so than any testing, even unit testing, static types are on the front line for doing that.

So what do I think makes a great software developer? I’m still not sure- I’m still answering that question myself. One thing I have realized recently. And that is that our job is not to produce working code. It’s a heretical idea, but it really isn’t. Our job, as software developers, is to solve problems. One (admittedly common) way of doing that is writting some code. But an equally valid way would be to buy a software package which already solves the problem, or figuring out some way for the company to just avoid the problem in the first place. Testing, and static typing, are about producing working code. But a focus on that level misses the wider context the truely great programmers work in- and the problems and aspects of that wider context.

Such as figuring out what the real problem is in the first place. That one I’m still getting a handle on. And goes solidly into the list of things college did not teach me about. And fits on no test I can envision, except real life.

This entry was posted in To Be Categorized and tagged . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

16 Comments

  1. Posted July 6, 2007 at 3:56 AM | Permalink

    I love all of the essay except this line:

    what the topic really is, is “this is what I think is central to programming.”

    I don’t personally think safety, testing, and related topics are central to programming.

    Other than that, I liked the article. And the stuff that came after that was valuable, so even if that line kind of misrepresents what I was saying, I’m glad it lead to a good post.

  2. Posted July 6, 2007 at 5:58 AM | Permalink

    Absolutely love your analysis along the lines of white-collar/blue-collar!

    I actually agreed (http://quay.wordpress.com/2007/07/05/what-frameworks-do-you-use/) with the spirit of what Reginald was trying to say, which I think is the same thing that you’re trying to say in that you shouldn’t go around coding and connecting frameworks together for their own sake, but instead it’s toward the goal of _solving a problem_. You need to understand the problem, and how it should be solved, before doing anything. And you bring up the great point, that maybe the problem can be shifted or even made moot by determining that it’s not a problem that needs solving.

    I’m not sure that Reginald actually meant to say that testing is *itself* the most important, but rather… by being a good tester (or test writer), it requires you to have knowledge of the problem that’s being solved. It’s not about what the code *does*, but what it *should* be doing.

  3. David Mercer
    Posted July 6, 2007 at 7:57 AM | Permalink

    Heck, most of the theory I’ve learned, I’ve learned post-college.

    I agree. I think it was because in school I was simply playing the game to get my degree. A deep understanding was not necessary. The only understanding I needed was that which was required to get an A in the class. This normally involved parroting the professor.

  4. Posted July 6, 2007 at 11:22 AM | Permalink

    Sounds to me that you havent heard of guards.

    What are guards in this context?
    well assertions that must be passed or the program will throw an error.

    Static type info (as you descripe it) in procedures/methods/functions signitures can be thought of as an syntatic sugger for an guard that states: Is argument (or return value) x an instance of type int?

    But guards are more general than that.
    Say that your function only takes an int between 0 and 100, how would you check that in static type system? make a new type called IntBetween0and100? but if you only need this check for one function? would the creation of an type be worth the ‘cost’ so to speak?

    See guards in E at erights.org for more info.
    -Zarutian

  5. Posted July 6, 2007 at 2:58 PM | Permalink

    The distinction you are making between “writing working code” and “solving problems” could perhaps be embodied in the difference between a “programmer” and a “software developer”. Though these are mere words, it’s how I’ve always made the distinction in my mind.

    (Incidentally, some certifications are really geared more toward producing programmers, so I suppose it’s not a huge surprise to see such a wide variety of software workers.)

  6. Posted July 6, 2007 at 3:00 PM | Permalink

    …he’s missed the whole point of static typing….

    You are *so* spot on with this observation. I regularly read (and enjoy) Ragnawald’s writing on software development, but I definitely differ with him on his stance on static typing. And you seem to have totally nailed two of the main reasons why I like static typing – the tried and true patterns that are possible because of static typing and the reliability of knowing that a method returns an int, string, or Person object. But we could go on for days and days argunig about the static vs dynamic typing schism (which i must admit i didn’t know existed until Raganwald brought it up – I just switch between static & dynamic depending on which language I’m using and keep it moving…), but I think that the really interesting thing about this post is your analysis of the class issue. I’ve often felt that S/W developers are more blue collar than white collar, sort of like construction workers of a virtual world (this may be literal if you’re a game developer). And I think that this is why you see so many bloggers writing about what makes a *good* software developer, with the post implying that they or their shop is filled with only *good* developers, not virtual construction workers. Some of you may point to the difference between “programmers” and “developers”, but that’s exactly my point. It’s an effort to make the field feel less blue collar, by enforcing an internal hierarchy, with the developer (architects, etc.) being white collar, and the programmers (code monkeys) being blue collar. And of course everyone sees themselves as developers or architects. I coulkd go on, but I need to tend to some family business.

    Anyways, Nice post

  7. bhurt
    Posted July 8, 2007 at 2:44 PM | Permalink

    I should know better than to write diaries while Chia is hiding out in the piney woods and can’t vet comments. Our apologies that all of these posts didn’t show up until today, and welcome to the site (“and you’re welcome to it!”).

    So all my replies in one big batch:

    Reg: My apologies for misrepresenting your post.

    Josh: Good post. I agree that the main trick to programming is figuring out what the real problem is- but your post, I think, demonstrated what the problem is with understanding the problem domain by testing. So you have three inputs, A, B, and C, and produce R. How many different values can be put in for A, B, and C? If each variable can take on 2 different values, you have 8 possible cases you need to define. If each has 8 values, you have 512 different cases. If each has 256 values, you have 16,777,216 possible cases.

    As a general rule, you’re not going to sit down an enumerate all 16+ million possibilities and decide, individually, what all the outputs are. No- you’re going to start to write rules. “If A is like this, and B is in this set of values, then R is some simple function of C” or whatever. At which point you are programming, as far as I’m concerned- you are defining a computational process (probably in a high-level, ad-hoc, informal manner) by which the output can be computed from the input.

    Nor are you going to test all possible inputs to the program. Well, with only 16 million inputs I might- but if each of the three inputs have 2^32 possible values, that means I have 79,228,162,514,264,337,593,543,950,336 (2^96) possible combinations, and you’re not testing all of those possibilities. So your testing is going to be stochastic by necessity- testing some statistically meaningful subset of the possible input values- and thus, by definition, the information about the real problem domain is incomplete.

    I’d also like to point out the high probability of hidden variables. I can’t count the times when the spec said something like “When the inputs are A, B, and C, the output is R” when it really should have said “When the inputs are A, B, and C, the output is R, unless the hidden variable D, that we forgot to mention up front, has this special value, then the output should be R2.”

    Hidden variables love hiding out in unconsidered corner cases. Approaching it from a programming, or rules based, approach and these hidden variables and unconsidered corner cases are somewhat easier to spot. Of course, investigating the corner cases is what gets programmers a reputation for needing everything to be spelled out…

    More on this in a bit.

    David: I don’t think it was just “coasting through” (not that I didn’t do my share of coasting back in college). It’s that there is just so much of it, and the time allotted for college is limited. I once spelled out all the technical things I thought a professional programmer should know- ignoring testing almost completely and only lightly on requirements gathering and problem identification. I think it came out to a degree program that was 15 years long.

    When you graduate from college, your learning is not over- in fact, you learning is just beginning.

    Zarutian: Yes, I have heard of gaurds, and design by contract. There are three problems with run time checking. The first is that, for non-trivial constraints, constraint checking is expensive. Bounds checking is cheap- but checking that a tree is balanced is an expensive O(N) operation. So there is always a pressure to disable the constraint checking for performance reasons. Static typing is done once, at compile time, and has no effect on run time performance.

    Second, constraint checking at run time only guarantees that this particular execution did not violate any contracts. In which case you get into the same problem that I was talking about earlier with Josh- it’s always the unconsidered or untested or rare cases that get you into trouble. Of course, there is always the pressure to turn off the constraint checking for performance reasons (see reason #1).

    Third, runtime checks only show where the error was detected, not where the error really is. See Chia’s blog post recently about null pointer exceptions as an example of this.

    As for determining that an integer has to be in the range of 0 to 100, google “Dependent Types” sometime. Of course, the problem dependent types get into is determining what the range should be. Checking that the index is between 0 and 100 is easy- determining that the index needs to be between 0 and 100 is equivalent to the halting problem. There are some things that static types can’t check in a practical environment. Ocaml, for instance, bounds checks array accesses at run time- and this hits all three problems documented above.

  8. Posted July 8, 2007 at 7:44 PM | Permalink

    For the record, I like languages with serious type systems like Haskell and Ocaml’s.

    Such “static typing” should not be confused with what you find in popular languages these days. Please keep that in mind when reading my weblog…

  9. Posted July 9, 2007 at 6:02 AM | Permalink
  10. Joe
    Posted August 14, 2007 at 7:15 AM | Permalink

    “Static type info (as you descripe it) in procedures/methods/functions signitures can be thought of as an syntatic sugger for an guard that states: Is argument (or return value) x an instance of type int?”

    No it can’t be thought of like that at all, this is again totally missing the distinction between static and dynamic typing. Dynamic type checking is comparable to guards. Static type info is not available at run time, and cannot lead to an exception or other run time error. It checks that the types are correct while the program is being compiled, and then the generated program doesn’t have to have any type info or do any type checking. That’s what makes it so useful.

  11. Posted October 21, 2007 at 7:55 PM | Permalink

    So, three months later, what happened to “I’ll cover this in a later post”?

  12. Brian
    Posted October 22, 2007 at 4:47 PM | Permalink

    I’ve written the monad post (See “A monad tutorial for Ocaml” on this blog). The phantom types post is a little light for a whole post by itself, I’ll probably cover it when I’m talking about something else.

    Short form: you can add an unnecessary “phantom” type parameter to a type that you don’t need, for example:

    type ‘a t = int;;

    Since the type parameter (‘a) isn’t actually used in the type definition, it can be whatever, and it doesn’t change the run time representation. So now you can play games with polymorphic variants to encode various constraints. For example, say you want asynchronous and synchronous file handles. You could give the open function the following type:

    val open : [< `async | `sync ] as ‘a -> string -> ‘a t;;

    and implement it like:

    let open (flag: [< `async | `sync] as `a) name =    match flag with    | `async -> (* async open *)    | `sync ->s (* sync open *);;

    Then you can give async read the type [`async] t -> string, to limit those handles passed in to just those opened as async.

    Now, let’s see if the above code formatted correctly or not.

  13. Brian
    Posted October 22, 2007 at 4:49 PM | Permalink

    Nope. Try this again:

    let open (flag: [< `async | `sync] as `a) name =
        match flag with
        | `async -> (* async code *)
        | `sync -> (* sync code *)
    ;;
    

  14. Elias
    Posted December 13, 2009 at 2:51 AM | Permalink

    you are from jana street? there were a guy at #ocaml at freenode that was talking about how few ocaml jobs there are he thoght that your company would be a dream place to work (at least compared to those were you program in java or c++). i just hope you guys don’t go out of business and more people start using those “weird” cs languages such as ocaml or haskell.

    i also do agree about certifications, :)

    (I also think this post is too huge, maybe you had subject here for 2 or 3 posts)

    about programmers: programming is half engineering, half poetry. someone that can’t write beautiful code can’t program well; someone who have no imagination too. to write a program is really a linguistic effort, a effort of expressing with code (fundamentally, words) the internal working of an abstract mechanism.

    anything you can express in a well-defined way constitute a program (in some language); so maybe, if you want to test if someone is a good programmer, you might test if he can define things in a clear, concise, non-ambiguous way, and if he can handle with complex but clear definitions, even if they use language constructs they can’t handle very well.

    about your questions: they were tricky, I understood the “can be enforced” as meaning “is always enforced”, you got me :)

    (also, I am reading your monad tutorial. I really didn’t knew about that last questions and I never understood very well this stuff about monads too. thanks)

  15. Elias
    Posted December 13, 2009 at 2:52 AM | Permalink

    any machine or mechanism you can express, i mean.

  16. Elias
    Posted December 13, 2009 at 3:00 AM | Permalink

    (maybe, another way to test if someone is a good programmer is to show him 4 implementations for each of 10 functions of a program and ask him to select one for each function. it works for any language and you might be able to classify each response belonging to a “kind” of programmer. but if you ask him to pick the solutions that could be generally considered the fastest, or maybe more elegant, you might as well be able to select those that knows more about the language – especially tricky if you also list reasons for each selection, such as “This code is the fastest in most compilers because of such and such optimization”)

3 Trackbacks

  1. By Enfranchised Mind » Comment Vetting on July 9, 2007 at 5:59 AM

    [...] apologized for my slow comment vetting here. That was due to me being up at the lake, and having no fall-back moderator. I’ve since [...]

  2. [...] recently jumped ship on the certification debate with his Certification? Bring it On!. An excellent rebuttal over at Enfranchised Mind was quick to follow and made some excellent points as [...]

  3. [...] Certification? Please, no. [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">