Ekinoderm
 

Going for the Easy Win

A big part of software development is making hard problems into easy problems, but sometimes it’s essential for your sanity to work on easy problems that you know how to solve.  I call this “going for the easy win” or sometimes “picking the low-hanging fruit.”  While it might give you a lot of bragging rights to solve a tough synchronization bug that’s existed in your system for years, it might do a lot more for your sanity (and self-esteem) to fix an easier bug with output formatting that looks a bit more manageable.

Mmm...low-hanging fruit...

Mmm...low-hanging fruit...

The way I try to manage this in my own workflow is to designate a specific day and time (I use Monday mornings) to try to fix as many simple bugs as I can in a row.  I find that this practice has a few definite benefits:

  • It fixes bugs which might otherwise not be given the proper attention, since they are “easy” or not as critical as other fixes.
  • It provides a good ramp-up to other development tasks for the week.  It’s kind of like stretching your brain out for the real exercises to come.
  • Because I do it on Monday morning, it doesn’t interrupt me from anything else I was working on.  I tend to leave one obvious task unfinished at the end of each weekday so I have a good place to jump back in the next morning.  However, over the weekend, I find that I tend to forget where I was anyways, so my continuity isn’t broken by fixing bugs on Monday morning.
  • It makes me feel like super-developer to knock out a bunch of bugs quickly, which helps keep me from burning out (along with my side projects), and provides a positive start to the week.

There are a few things to keep in mind when going for the easy wins, most of which are fairly obvious, but I’ll list them anyway so you don’t think I’m a complete idiot:

  • Don’t ignore high-priority issues.  Duh.
  • Don’t substitute lots of bad fixes done quickly for a few good fixes done slowly. Duh.
  • Don’t miss deadlines and screw over your teammates to do this.  Duh.

Finally, don’t think of this as a form of structured procrastination.  Think of this as an important part of the maintenance process that can actually benefit you a lot, in addition to getting a bunch of bugs fixed.

It’s OK to be Ignorant

Programmers have big egos.  It’s not like it’s a big secret or something; we’re used to being right, and it can be very difficult for us to admit when we’re wrong.  And, God help you if you ever have to say:

I don’t know.

If you say that, no one will ever respect you again, and you’ll never get a job offer or a promotion, right?

Sarcasm aside, I think, on some level, a lot of programmers may really believe that not knowing something is an unforgivable sin.  But, in reality, uttering these three words should be a call to action.  If you don’t know something, then you should find it out, right?  Sounds simple.  But we’ve been conditioned (by crappy teachers or well-meaning, but misguided, interviewers) to believe that we are supposed to be able to recall everything we’ve ever learned, even though this is clearly impossible.

When you’re working on a project, sure, you can remember a lot of details about the various classes and modules that your project uses, but these are things that are passively memorized through repeated use.  And when you see something novel that you don’t recognize, you look it up. I hope you’ll forgive me if I’m over-generalizing, but I think this is frankly obvious to anyone whose ever held a programming job for more than a few months.

And yet, as programmers, we’re bombarded with offers to be “certified,” by Microsoft or Sun or whoever else.  A large portion of a certification exam consists of memorizing the names of framework classes and methods or memorizing the location of configuration options in your web server or other software.  I honestly can’t think of anything less indicative of actual programming and development skill, except maybe having a lot of experience playing video games (something that I seem to see rather frequently on resumes, actually).

On the other hand, I will say that certification is a good alternative to a college education if you just need you get your foot in the door somewhere, though it’s certainly no substitute for real experience.  The college-educated shouldn’t think that a diploma is an alternative to real experience either, because it’s not.

But what’s the problem with rote memorization?  It probably won’t hurt you, and it might even help you, right?

Bloom's Cognitive Domain

Bloom's Cognitive Domain

You might recall from your primary education something about Bloom’s Taxonomy of Educational Objectives; I can remember a poster of the skills in his “cognitive domain” hanging in my elementary school English classroom.  The whole idea behind his taxonomy is that there’s a hierarchy of reasoning skills.  At the lowest level is “remember,” i.e. the ability to recall specific facts.  For example, perhaps you recall that the Magna Carta was issued in the year 12151.  Moving up the tree, we have “understand” and “apply.”  These levels might lead us to ask, “What did the Magna Carta say?” and “How did it change life in England?”  At the top of the tree, we have “analyze,” “evaluate” and “create.” Here the questions could be very open-ended: “What are some problems with the Magna Carta?”  or “How would you write your own version of the Magna Carta?”

So, here’s the problem with rote memorization as it pertains to software development (sadly, we don’t have time to discuss rote memorization as it pertains to medieval English legal documents).  Rote memorization is at the very bottom of the cognitive tree, and nearly all of software development is done at the higher levels. The kinds of skills that can be assessed by testing if someone knows the name of .Net’s buffered string class2 are absolutely the most basic programming skills you could assess.  You’d be just as well asking someone what the syntax is for an if statement.  Moreover, the context-aware tab-completion in most IDEs has pretty much eliminated the need to recall exact class or method names while you’re writing code.

Unfortunately for the certification exam writers, the higher cognitive levels are very subjective.  We’re talking here about asking questions like, “Is this function good?” or “What are some problems with this code?”  In trivial cases, there may be “correct” answers to these questions, but most of the time, there’s room for differences of opinion and discussion.  And, a lot of times, it’s more important that you approach the problem in an intelligent way than that you get the “right” answer.  I know there’s a (deserved) backlash against the whole Interview 2.0 thing, but I do think that the idea of asking questions with no clear answer during interviews definitely has merit.

I guess the bottom line is that we are all ignorant of a great many things and it’s OK to be ignorant, because ignorance is an easily correctable condition.  When you think about it, ignorance is the default state for everyone.  Perhaps you know nothing about functional programming.  Perhaps you never learned assembly language.  In my case, I’m a total noob at networking; I understand the basics, but that’s about it.  But you don’t remedy ignorance with memorization, you remedy it with clear understanding and application of concepts.

Unless you specifically go out of your way to correct your ignorance, you’ll always stay that way.  And the only kind of ignorance that’s unforgivable is willful ignorance, actively refusing to find out things you don’t know.



  1. I had to look that up, actually []
  2. it’s called StringBuilder, and I didn’t have to look that one up.  See?  Passive memorization! []

Magical Thinking, Magical Code

Natives who beat drums to drive off evil spirits are objects of scorn to smart Americans who blow horns to break up traffic jams. — Mary Ellen Kelly

Wikipedia briefly defines “magical thinking” as “nonscientific causal reasoning,” and it can be broadly applied to all kinds of superstitious behavior.  We all know someone who believes that they have a good luck charm.  There are two basic rules that most kinds of magical thinking have: the law of similarity (an effect resembles its cause), and the law of contagion (things which were once in physical contact maintain a connection even after physical contact has been broken).

While magical thinking can be understood academically as a prescientific way of reasoning about cause and effect, it’s remarkable how prevalent forms of magical thought are in software development.

First, here’s an example from my own experience.  In .Net 1.1 there was an object called DataGrid (it’s still around, but it has been supplanted by DataGridView).  Every so often, we’d be doing development on a windows application and we couldn’t get updated rows from the grid to store back in the database, or process, or whatever.  The rows would appear in the grid, but the code couldn’t see them.  At some point, someone tried the following call:

DataSet.AcceptChanges();

on the underlying data set.  And it fixed the bug. Nobody really knew why.  To be perfectly honest, the documetation for the call didn’t really seem like it applied to our problem at all.  However, adding this code fixed our bug, so, as a result, AcceptChanges became the first thing that anyone would try when they were having trouble with a DataSet and the solution wasn’t obvious.  A lot of times, the call didn’t fix the problem, but it didn’t do anything bad, so it would stay in the code, even after the real bug had been fixed.

Automatically trying the code that fixed the last similar bug leads to a phenomenon that I call magical code (sometimes called “cargo-cult programming“).  Code structures and function calls are repeated all over the place, not because their effect is well-understood and required in that instance, but because of a random guess at what might fix a problem (based on experience with past fixes), along with a sort of prayer to the compiler that the change will fix the problem.  Despite being sloppy as hell, I’m fairly sure most developers do this at one time or another (I know I have).

A Cargo Cult in the South Pacific

A Cargo Cult in the South Pacific

Logically, there are two problems here:

  1. Not understanding real causes. Just as the cargo cults in the South Pacific thought that building landing strips and control towers would cause planes to land with cargo, the developer who inserts code without a specific reason is expecting a certain effect without truly knowing the thing that will cause it.  Just because a piece of code appears in working code and is missing in broken code does not mean that the code should be copied from the good code to the broken code to try to fix it.  It sounds silly that anyone would do this, but this is exactly what people are doing when they add magical code.
  2. Not noticing the real effects. Every piece of code does something.  Even a NOP instruction has an effect (the processor does nothing for a few clock cycles).  Even code optimized out by the compiler may cause compilation to take longer.  By inserting code without understanding what it does, you’re potentially introducing hard-to-find bugs into the system.  These kinds of problems are even worse in an unmanaged language like C++, where magical code can introduce undetected memory leaks.

Obviously, it’s best to understand exactly what is going on in every piece of code that we work on.  Some would go so far as to say that if you don’t understand why your bug fix works, then it’s not really a fix at all and the bug is still open.

Unfortunately, in the real world, everyone has to work on stuff that they don’t fully understand.  The bigger your system is, the more likely that you’ll find yourself completely in the dark about certain parts of it.  However, there are some ways to mitigate the “magical code” effect in your system:

  • Code reviews. This is mainly to get rid of code that doesn’t do anything.  If 3 or 4 people can sit down and independently verify that a piece of code has no useful effect, then you should probably get rid of it.  If you ever need it back, hey, it’s in source control, right?  Regardless of the magical nature  of the code, just having code around that has no effect is pretty bad by itself, nearly as bad as incorrect comments.
  • Review bug fixes. The person who is most experienced with a module should review all the fixes that are made inside that module.  In a perfect world, this person would do all the fixes as well, but, generally, the most experienced people are the ones who have the most demand on their time and they often don’t have time to debug and fix problems.
  • Get educated. Spend some time learning about the way the built-in pieces of your framework function.  In larger systems, the same problem can occur with some of your own internal classes.  For example, developers may call your in-house Reset() or Clear() methods much more frequently than they need to, in an attempt to exorcise demons from their code.  Or, in a multi-threaded app, they may use locks much more frequently than required.  Develop little test programs or unit tests to prove to yourself (and others) that certain classes behave in a certain way.

I’m not saying that everyone needs to understand the whole application stack from top to bottom to be able to modify code.  In fact, one of the whole points of abstraction and encapsulation is to hide how things work.  The black-box presentation of many system calls encourages developers to view them as being “magic” in the sense that they do what you want them to do, even if you have no clue how they actually accomplish that effect.

The kind of magical code I’m talking about is about not even knowing what certain methods do, but just superstitiously adding them to try to make things work.

Don’t Take Me Too Seriously

Sarcasm is a powerful tool that any good developer should know how to wield effectively.  I just spent the last hour or so watching a rather amusing presentation by Cal Henderson at DjangoCon08:

While I found the talk to actually be both informative and entertaining, what I mainly noted was the pure sarcasm dripping from the description of what his company (Flickr) does (indexes pictures of kittens) and the difference between “serious” and “non-serious” frameworks.  Also note that he claims the main problem with Django is that the core team isn’t smug enough.

We often can fall into the trap of taking our work a bit too seriously. To quote Bertrand Russell:

One of the symptoms of an approaching nervous breakdown is the belief that one’s work is terribly important.

The way to defuse this is to have a sense of humor about your own shortcomings and fallibility.  A lot of people go for self-deprecating humor, and I count myself among them.  Being self-deprecating about the code you’ve written is a good way to make yourself a bit more tolerable to your co-workers.  Everyone writes crap code from time to time, and we don’t always have time to clean up our mess before we move on to the next thing.

If you’ve ever seen the new Battlestar Galactica, there’s a tradition on the ship where (one evening a month, or something) anyone can challenge anyone else on the crew to a boxing match, regardless of rank.  Some development teams could benefit from a similar style “equalizer” between the old guys and the newer guys (or the smug guys and the meek guys).  I think it might be kind of fun to have an anti-code-review, where the goal is just to produce horrible code from the code base and force everyone (myself included, of course) to wear the idiot hat for a few moments.  Although, there ought to be some ground rules for these kinds of code-bashing sessions:

  1. Everyone is fair game. If the boss wrote an if statement with 10 sub clauses, he should be called out for it.  If your company politics don’t allow for this kind of honesty…well…that sucks.
  2. No code is sacred. Even if the routine is rock-solid and has been running correctly in production for 10 years, it can still be a total bastard to maintain.  Actually, if it’s been running unchanged for 10 years, it’s extremely likely that it’s terribly written.
  3. Include everyone. Every team has differing skill and experience levels.  The point of this exercise could be to show the young’uns that the old folks still make stupid mistakes all the time.  Adjust the tone appropriately for your environment.
  4. Don’t worry about fixing the code. Fix it later.
  5. Sense of humor required. I guess that’s the whole point of the exercise, but if people are going to take things personally…make sure it’s well understood that this isn’t about making people look bad; it’s about realizing that individuals will always make mistakes.  That’s one of the main reasons why nearly all good projects are completed by a team of people who can support each other.

If you can’t get your team to go for this, or you don’t have the time, it can still be fun to go back and look at some cringe-worthy code that you wrote in the past.  It’s good to reflect on how you’ve improved, but at the same time, realize that right now you’re making mistakes that the future you will look back on and laugh (or cry, depending on the context).

How Much Does Experience Matter?

There’s a big difference between having experience writing code and having experience as a professional software developer in the software industry.

I don’t have that much experience as a professional software developer.  As for writing code, sure, I first learned to program on the TI-99/4A, when I was like 6 years old or something. But the “programming” consisted mostly of copying programs out of books and stuff like:

10 PRINT "NATHAN IS AWESOME!"
20 GOTO 10

In junior high and high school, I learned some C++ on my own and some in the AP curriculum.  In college, after messing around as a pre-med student and then as a cognitive science major, I finally settled on computer science and actually learned how to program.  Then I went to grad school, and didn’t learn much more about how to program, although I did get to work on some neat projects, none of which were big enough to impart any real experience about what it’s like to work on a big project in the real world.

I have 20 years of "experience" programming the TI-99/4A.

I have "20 years of experience" programming the TI-99/4A.

So, after 5 years of formal education in computer science, I was pretty decent at writing code, but I had no idea how to organize a large project or to work effectively within a team of other good coders.  However, on paper, I had 5 years of coding experience (let’s call it, “5 years of Java experience”, since that was the first language I learned in college, and I used it regularly throughout my studies).

Did all this “experience” make me a grizzled “vet” of Java, who knew all the inner workings of the JVM and had the whole library memorized?  As I’m sure you can guess, the answer is “No.”  Yet, so many programming position advertisements require “10 years of C experience” or “5 years of Java experience.”  This is, unfortunately, the wrong metric to measure professional software development experience with.

Knowing how to code well in some programming language is the most basic of prerequisites for any software development job.  It doesn’t matter if it took you 3 weeks to learn it or 3 years, you should just be able to demonstrate that, yes, you know what a loop is, yes, you’re familiar with some basic data structures, and yes, you have some clue of how pointers and references work.  If you don’t know this, you can’t write software professionally.  Just like you can’t be a professional race car driver if you don’t even know how to drive.  There are a ton of books out there that can teach you basic programming concepts; you don’t need a lot of extra money or a degree, just a library card and the spare time to learn.

Once you’ve learned one or two languages well, you should be able to ramp up on a new language fairly quickly.

There’s a vast gulf between knowing these basics and being a true master in the software development process, just like there’s a big difference between driving to the grocery store and driving in the Indy 500.  Your progression on this path from knowing the basics to becoming a master is the experience that truly matters.

Being a master isn’t about writing code that compiles and is semantically correct — most developers can do that.  It’s about grokking all the other things that go into creating a piece of software that people actually use.  This understanding cannot be found in a book or classroom, but can only be obtained through actual years of continuous experience in the software industry.

Though I have progressed only a short distance along this path, I can provide some suggestions for things I think help build this kind of experience a bit more quickly:

  • Read about software development every day (blogs, articles, books, etc.).
  • Start a side project or join an open source project.
  • Pay attention to the way people organize processes.  Look at the way a short-order cook organizes different orders.  Look at the way UPS organizes packages.  In particular, recognize that many people approach tasks in an algorithmic way, even if they don’t realize it.
  • Have conversations with your co-workers about development topics.  Don’t be afraid of having an “academic” discussion on a topic.
  • Keep a blog where you can write about new things you learn.  People who read it may disagree with you or correct you.  Don’t delete these comments — pay attention to them and see if you can learn something from them.  Only ignore comments from obvious trolls.

None of the experience gained doing these types of activities, or the experience gained from working continuously in the industry for years and paying attention while you do it is the same as the kind of experience implied by “5 years of C programming experience.”  The former is significantly much more valuable than the latter.

Search

Cool Jobs

Blogroll

Meta