Saturday, October 15, 2011

The Trouble With Lint

You all know what lint is; those little bits of white fuzz that stick to your clothes. Lint isn't exactly dirt. It mostly just makes your clothes look untidy. Mostly.

Software has lint too; those compiler warnings you see every time you do a clean build. You've seen them a thousand times before. You know they're harmless. If they're in your code, maybe you think, "I need to fix that someday. But not now."

This posting is about why it is important to remove lint from your software sooner rather than later.

You see, lint has a dark side. Enough lint in the same place is flammable; sometimes even explosive. Houses burn down each year from fires that start in the clothes dryer.

Software lint has the same nature. Too much lint; too many warning messages; and you stop paying attention. Then when an important warning appears, you don't notice. At a previous employer, a team of half a dozen engineers spent four 16-hour days (including Saturday and Sunday) hunting a bug that held up an urgently needed release, when the problem they were hunting was printing a visible compiler warning. It was one of 200 such warnings, so nobody paid any attention.

I was going through some code today, removing lint. I came across this warning.
Foo_UnitTest.h:178: warning: right-hand operand of comma has no effect
Anyone know what this means? Here's a hint; the code at line 178 read
delete [] buf1, buf2;
Still confused? Here's an explanation. C and C++ share a little-known feature called the comma operator. The expression <expr1> , <expr2> evaluates <expr1>, then throws the result away (except for side effects), then evaluates <expr2>.

I imagine the person who wrote this line of code intended to delete the storage pointed to by both buf1 and buf2, but that's not what happened. Instead, the expression delete [] buf1 was evaluated, then discarded (except for the side effect of deleting buf1), and then the expression buf2 was evaluated. So buf2 didn't get deleted.

If you say, "Well, it doesn't really matter because it's just a unit test." then you are entirely missing the point. Removing lint is a discipline that results in clean code that runs the way you expect. If buf2 has a non-trivial destructor, there's no telling how much code isn't getting run (and therefore isn't getting tested) because buf2 isn't getting deleted. You wouldn't know that without investigating what the type of buf2 was.

Even lint that doesn't affect the generated code, like unused variables, can be a problem if these unused variables confuse a future reader of the code. It's easy to comment out this code if you want it to stay in the listing. Easier yet to delete it.

C++ provides syntax for defining functions that don't use all their arguments.
void classname::func ( int parm1, int /*parm2*/ ) {...}
defines a method that takes two int arguments, but only uses the first one. Sometimes you need this for defining base-class methods meant to be overridden in derived classes. Commenting out the argument name turns off the compiler warning, and clearly expresses your intent.

Sometimes your compiler insists on issuing a warning for code that you know is ok. If you can't fix the code with an explicit cast or something, the language implementation probably provides a #pragma for temporarily turning off the warning. You can go even further, running a static checker like lint(1) or cppcheck and fixing the code to remove the warnings it produces. There's just no reason not to have a clean build, and every reason to have one.

Sunday, August 28, 2011

Learning About Robustness

Something I think about from time to time is, "What do Old Hands think about code, that is different from what rookies think?" Here are some examples.
  • When I was a rookie, I believed programs should be precise. If the program parsed some input, that input should conform. I believed that a program was robust if it printed a detailed error message and halted, so I could quickly fix the input.

    As an experienced developer, I realized that processing the input was far more important than ensuring that every comma was in the right place. I came to believe that a program was robust if it accepted a generous superset of the expected input syntax. I remember hearing this advice as a rookie and snorting with derision at the thought of anything so sloppy. This is another difference between Old Hands and rookies.

    When I became an Old Hand, I realized that any program you run frequently provids a service. Any time the program halts prematurely, it fails in its reason for being, which is to provide the service. I discovered that even a program that is not working correctly may be more useful than a program that won't run. I learned that a program is robust if it provides its service, all the time, under the widest range of conditions. A robust program should not fail, and if it does fail it should recover, and if it cannot recover, it should restart, and if it can't restart, another program should restart it. The code to provide all this robustness amounted to as much as 50% of the total, but I no longer viewed that as wasteful excess.
  • When I was a student, I never checked return codes. "How could a system function possibly fail?", I thought. I was naive enough to assume that the people who write system functions never made mistakes, and hardware never failed.

    When I was a rookie, I discovered that even if a function failed only once in a million calls, I would see it fail. A million calls just doesn't take that long when a program is running flat out all day. Such a program would terminate unexpectedly, usually saying no more than "segmentation fault".

    As an experienced developer, I learned that functions fail all the time, but I hadn't known it, because I wasn't checking the return codes! Usually functions failed because the argument values were illegal. I remembered spending hours looking for why my program wasn't working, when the functions were telling me exactly what was wrong. I meticulously checked every error return, and reported failure up to higher levels of the code. I also began writing functions that did more checking and logging, because when these functions failed, they told me what I was doing wrong.

    Once when I was old enough to know better, I wrote a library of meticulous functions tthat checked every return code, to check out some functionality in Windows. It took days. A colleague who was an Old Hand bodged together an informal but usable tool in a couple of hours because he didn't check return codes. I learned something that day.

Wednesday, August 3, 2011

Why I Took Computer Science

I went to college to get educated, back when people thought they could be successful even if they didn't go to college. (Taking manufacturing jobs. Wonder how that worked out for them?) I took this two credit class called Math 111A, which featured programming the pdp-8, and CDC Cyber 6600. And programming the pdp-8 emulator on the CDC 6600.

Of course this course was taught by a grad student. And it was arguably the worst instruction I received in college. Someone asked how to name variables. The teacher said, "Name them anything you like. Call them Kirk, Spock, and McCoy." So my first program had variables called Kirk, Spock, and McCoy. I didn't understand the difference between symbolic constants that named memory locations (variables) and symbolic constants that named constant values. It was amazing I ever got my programs to run.

There was an actual pdp-8, a filing-cabinet-sized microcomputer with almost 8,000 gates(!) and actual magnetic core memory. You fed it programs using the paper tape reader on an ASR-33 Teletype. First you toggled in a simple loader on the front panel switches. Then you used that loader to load the RIM loader off paper tape. Then you used the RIM loader to load your program. The machine was so mechanically flakey that it was even money it would stay up this long.

On the strength of this vast experience, I applied for a programming job, which ended up making me spending money the rest of the way through school.

My college GPA intersected with the Department of Computer Science's requirements during exactly one academic quarter, which coincidentally turned out to be the quarter I applied. After that the decision seemed to have been made.

The summer between my Junior and Senior year was The Energy Crisis; the first time energy stopped being ridiculously cheap and infinitely available. Campus authorities went around turning off the A/C to all the buildings on campus. The only exception was the Hospital. And the Academic Computer Center. Seems the mainframes like it cool. This cemented my already firm intention to go into software.

After school, I took my first full-time software job at Fluke in Everett WA. Of course by then I had a lot invested in being a software engineer, but there were two more events that confirmed my decision. I watched a summer EE intern destroy an irreplaceable prototype display tube. He powered it up. There was too much current in one column driver, and the column wire burned up, making this sad little "tink" noise as it died. This increased the current in all the other columns. You could hear it die, "Tink. Tink. Tink, tink, tink, tink-tink-tink-tink-tink." It was totally not his fault. The driver chips for this display weren't available yet, and we were were overdriving chips for a lower voltage display. But he felt so bad. I liked the notion (not completely correct) that when software crashes all you lose is time.

I had an EE colleague at Fluke named Jim Lenker. Jim was a thrill-seeker. He drove too fast. He went scuba-diving alone. He was missing a finger on one hand that he had cut off in an accident. But I noticed that when he worked with high-voltage circuits, he put his left hand in his back pocket to prevent making a circuit across his heart. Computers were all 5 Volts at the time. You can scarcely feel 5 Volts on your tongue. I liked that.

Why I Went to College

This is the story I always tell when somebody asks me why I went to college. One reason the story is interesting is that it isn't even my story. It belongs to my wife's brother Dan, who is a construction welder. Here's the story.
A ditch box is two steel plates held about 3 feet apart by braces. You put a ditch box in the ground when you have to work in a ditch because ditches tend to collapse in wet weather, and this is Seattle we're talking about.

So, my brother-in-law Dan is working outdoors, six feet below grade, in a ditch. It's the fifteenth of December. It't 35 degrees F and drizzling rain. Dan is soaking wet and standing in ice-cold water up to his knees. He is welding an additional cross brace into the ditch box, presumably to keep it from collapsing. He is using an electric arc-welder, and he can feel the current flowing over his wet body to ground.

...and that's why I went to college.
Of course that isn't really why I went to college. Well, it kinda is. I went to college because I wasn't really a grownup when I was 18 and it was go to college and get to live comfortably at home, or go to work and live on my own. Besides, there was just this background assumption in my family that everybody would go to college. But it was clear in my mind that I would rather work indoors in an air-conditioned office, and sitting down if I liked. And I would be happiest if the most dangerous thing I did on a daily basis was drive to work. And that's why I went to college.

Thursday, July 21, 2011

The Dream Team (a Management Anti-Pattern)

Senior developers are more productive than junior ones, or so I tell myself. Still, most employers like to hire devs 2-5 years out of college. Managers say, "These guys ae still fresh, with up-to-date skills, but they've learned how to work." But what managers think is, "These guys are cheap, and they do what they're told, because they don't have a lot of independent experience giving them ideas that conflict with my judgements."

But that's not what I would do. If I ran the world, I'd hire devs with 10+ years experience; devs who already knew what to do and could go do it without supervision. Some startups work like that. Yeah, an Old Hand costs more, maybe twice as much as raw rookies right out of school, but they are way more productive. They only have to be twice as productive (counting the managers you don't have to hire), to make them pay off.

I took a job at a company like that once. They bragged that they only hired senior folks. And indeed, the staff, taken as individuals, were bright and talented and very experienced. I was very excited, because this was just what I would do. I thought I was joining a dream team. Reality was quite a let-down.

The company founder was a guy who liked to code very fast. In fact, he'd hired this team to clean up after him. Over time the team became so outraged by the poor quality of the founder's work that they chased him away to "other opportunities". Problem was, people like to hire themselves, and the founder had hired a staff that liked to write code quickly, but didn't care to do that other stuff, like documentation, coordination, testing, etc.

One very senior C++ developer didn't trust objects. Their code looked like C, and had all the problems of C code. Another one had a very idiosyncratic coding style; they put all their method definitions in the header file. Partly this was a bad java habit. Partly they used a third-party tool for indexing the sources that worked better when the declarations and definitions were all in the same place (I think, sort of. I still don't understand). Another had a bunch of antiquated style habits they'd picked up in 1995, and couldn't imagine how their practice could possibly improve by changing their style to use modern features of C++. Naturally they each had their own indentation style, their own variable-naming conventions, and pretty much every other thing that they could do differently, they did.

They'd broken the code up into fiefdoms, so they weren't exposed to the silly habits of their peers. And they defended these fiefdoms fiercely. One of them checked in a change to my code because I'd started a one-line comment with "//", when they preferred "/* ... */".  Whatever, man.

Each fiefdom had their own include files, with duplicates of the same basic stuff, that had aged differently. The code base frequently produced compile warnings (on error level 3 in Visual Studio). They didn't lint the code, or use error level 4 because it produced too many error messages, and some devs would have to change their styles to make these go away. In fact, we had a critical bug delay a release, that turned out to have printed a compiler warning. Only there were so many warnings that nobody noticed this one, or bothered to follow it down into another dev's fiefdom and fix it.

They used a funky build tool written in python, rather than build inside Visual Studio or use make. Only two of the devs knew how to fiddle the build tool. They fought with each other endlessly, changing things back and forth.

They didn't really have any documentation for their creaky old code base. When I started doing docs, it started a war. One dev thought documentation should go into a wiki. Another thought it should be static HTML web pages. One thought Word was ok. Another thought we'd be more productive in FrameMaker (which is true, but FM is expensive). One wanted docs in the source code. Another argued that no documentation could be trusted because sometimes it might be out of date, so we shouldn't even comment the code.

We bickered about whether to put the docs in the source tree, or in one of two different styles of separate file tree. I tried to suggest that the first and only really important thing we should argue about was, what aspects of the project were most important to document, and worry about how to type it later. They thought that was crazy-talk. Each used the war as justification for not documenting their code.

An Old Hand reading this may have guessed by now that the problem was management. The lead was not doing anything to make the team work together as a team. By the time I got there, it was probably too late to change them anyway.

This company was a ten-year-old startup (which is an anti-pattern itself). Their product was pretty cool, but they were having trouble breaking out into the big time. The code had a million features, and a million little bugs. They knew they needed to work on improving their robustness because the next set of customers they had their sights on were big enough to demand really solid reliability. But the siren-song of each next customer was filling up the work queue with new feature requests.

I only made it six months at that company. They thought I should go, and I agreed. The feeling I had when I left must have been like viewing the Titanic from the perspective of the last lifeboat to pull away. Only the guys aboard the Titanic knew the ship was sinking.

Teams make the company. Not individual performers, no matter how experienced, talented, or bright they are. The Dream Team of individual performers is a management anti-pattern unless they are in fact managed as a team.

Thursday, June 30, 2011

Studying to Pass the Coding Interview

As I noted previously, I don't think coding tests measure the quality of a developer well. I think they discriminate against experienced developers and the self-taught, and favor recent grads because they are like CS homework exercises. But that doesn't matter. Google, Amazon, and Microsoft, among many others, give various kinds of coding tests at in-house interviews. To the extent I want to work at these firms, I must do well at coding tests.

There is generally-useful advice for anyone expecting to encounter a coding test. Some of this advice has been repeated elsewhere. Google actually sends you an email with advice prior to your in-house interview. Some of this advice I developed myself while working through many coding interview questions that I've faced recently, or that I found on the 'net.
  • Before beginning the interview process, review your undergrad Algorithms & Data Structures book if it has been awhile since you were in school. How important is this advice? As I've begun my own review, I've been shocked at how many of the questions I struggled with came right out of a book.

    Actually, this is hardly news (though it was news to me). If you look at Algorithms & Data Structures books on, "people who bought this book also bought" displays books with names like Cracking the Coding Interview. I also discovered that the book I used in college many years ago was not very rigorous. Computer Science has actually advanced during the intervening time. Who knew?

    Before my next interview season, I plan to study extensively, so that next time I don't waste time interviewing with big companies, only to be blown out at the in-house by doing poorly on a coding test.
  • Practice, practice, practice. Work through some coding problems. Time yourself. Then review what you've written and think about how you'd do better. Coding tests reward new grads having recent experience solving this kind of artificial problem. If you're a senior developer or you're self-taught, it is very likely that you need practice before going into a coding interview.

    There aren't so many popular coding test questions that you cannot possibly practice them all. I wonder how many successful candidates got the job because they memorized the test. If you've recently solved a problem posed in a coding interview, don't be the schmuck who says, “I've seen that before.” Just write it on the board and look smart. Because you are smart. You showed dilligence by preparing for the interview. Employers appreciate this quality, even if they don't realize it.
  • There are common themes among coding test questions, and they are not like your daily practice.

    Re-familiarize yourself with the string handling and array slicing functions and operators of your programming language of choice. Many coding test problems involve searching 1- and 2-dimensional integer arrays whose elements share a global property, or transforming character strings. If your workaday practice is like mine, it rarely involves arrays of integers, and rarely looks for relationships among the characters in a string beyond searching for occurrance of characters or substrings. Review coding test questions on the web involving this kind of problem, because you will see a lot of it.

    Review the hash table and heap data structures, because interviewers seem to be fascinated by them. Understand their big-O behavior. Be sure you can code heap insert using an array to hold your heap. Review tree traversal algorithms in both recursive and iterative forms.
  • Find out what the interviewer wants to see, and don't waste time showing them more. For instance, if the interviewer asks you to implement atoi(),  and all they want is to find out if you know any C, you can provide the most straightforward implementation. It's worth mentioning out loud that your simple solution is susceptible to overflow, or does not correctly convert the string representation of negative maxint, but even the simplest implementation will prove you can code. If on the other hand, you try to be fancy and capture every corner case, you may bog down and look like you don't know what you're doing.
  • Before coding, make an explicit plan for your solution. Senior developers do much programming using "muscle memory". This doesn't work for coding tests. A coding test is like a CS homework assignment. It consists of a puzzle to solve on paper, and just a few lines of actual code.

    Determine what data structures the code must manipulate. For instance, I once encountered the coding test problem, "Reverse a singly linked list." I attacked this problem confidently, and without advance planning, thinking that I'd solved many similar problems before. This was a mistake. I soon got confused about what was pointing to which. The solution was to realize explicitly that in reversing a linked list, I was working with two list data structures; the partially reversed list, to the head of which I added nodes, and the remaining unreversed list, from the head of which I removed nodes. With that thought in mind, the solution fell out as fast as I could write it down.

    Focus your attention on any relationships among data items in the problem set. Is the data ordered in some way, or are you looking for some kind of sequence? If it's a sequence, can the solution be defined recursively?
  • Abstract, abstract, abstract. Write a function to do any complex bit of code, even if you wouldn't write such a function in your workaday life because it is only called once. There are two reasons. First, clarity of thought is at a premium in a coding test. You want to get the overall logic down, then sweat the details in isolation. Second, time constraints may free you from having to code these functions once the interviewer sees you understand the solution. When this happens, it is a huge win for you.
  • Always consider error checking, but don't obsess. Always check for null pointers. It's a sign of maturity. I like to begin all my functions with a statement like

    if (p == 0) throw "error"; // error checking

    I tell the interviewer, "This is a standin for the unspecified error checking needed in a real problem.

Tuesday, June 21, 2011

Other, Younger Old Hands

I just came across this on StackExchange. Another Old Hand, this one only 32, laying down her rules of life in case they proved valuable.

The Developer's <code>

Friday, May 27, 2011

Age Discrimination in Software Development

Is there age discrimination in software development?

I think the answer has to be "yes". As an old hand, I can tell you it gets harder to find each next job. Now, I don't think (most) managers look at a candidate and say, "Forget that guy, he's too old." It's more subtle than that. I'm not sure hiring managers are even aware that they're doing it. But man, it's out there.

To start out, let me say that I don't believe the world owes every old hand a living even if they haven't kept up to date with our fast-changing industry. If there is no longer much demand for Pascal programmers, well that's just the way the world is. But lets look at some facts.
  • The great majority of practicing developers entered the field since 1995, when the software world began to really take off. That means that in 2012, the average developer has less than ten years' experience. These devs learned Java in school, and took their first jobs during the boom building web sites. Nothing wrong with that, except that the resumes of this cohort of devs all look pretty much the same. And they look different than the resumes of older devs who learned C in school and developed standalone windows apps. It is a truism that "we like to hire ourselves." The resumes of old hands just don't look like the resumes of younger devs doing the hiring.
  • The current trend in interview techniques is a coding interview. Coding tests have to be short, artificial problems. They are in this way exactly like Computer Science homework problems. Coding tests emphasize book learning and mathematical aptitude over experience and intuition. Such interview techniques reward the recent graduate, and gratify the egos of new hires with insufficient experience to program intuitively. Old hands bring many skills to the job; design experience needed to distinguish true requirements from marketing obsessions, coding experience needed to estimate schedules, process experience needed to improve practice, interpersonal experience that brings awareness of destructive team and management behaviors, and a degree of maturity about the work environment. These skills are hard to recognize if you don't possess them. I find interviewers rarely ask questions about these skills.
  • An experienced developer costs about twice what a new hire costs on an hourly basis. Good senior developers totally earn that pay through higher productivity and avoiding rookie mistakes. If the manager is not an experienced coder, they may not recognize that a senior person can really be that much more productive.
  • Fast-growing employers with positions to fill typically have young teams, obsessed with the desires of the young. Indeed, the first time I began to think of myself as old was when I signed onto a startup during the dot-com boom. I was surrounded by twenty-somethings that all seemed to desire the same three things; to get rich, not by working hard over a lifetime, but by lucking into the right dot-com; to buy a big, fancy Lexus or Infinity car; which they believed they could employ to get sex with no commitment. I found these goals incomprehensibly naive. I just wasn't the same as they were. I interviewed with one company where everybody played in the same rock band. I might have done better at that interview had I played rhythm guitar. Silly me, I talked about programming. I had another interview with a hip young new-media company terminated after 45 minutes (and before any technical questions), presumably because I wasn't hip and young enough.
There's no fighting it. I just tailor my resume so it doesn't scream "Old Guy!" I have a web site and a blog and a Facebook page, because people search the web for your name, and if you aren't out there, you aren't hip. And I hope to get in for the interview before they figure out I'm an Old Hand. Then it's up to me.

    Wednesday, May 25, 2011

    A Taxonomy of Coding Interview Questions

    As I noted previously, I think of myself as a talented developer, but I haven't done well at coding tests at recent job interviews. My ego demands I believe that doing well in coding interviews is a learnable skill. I have set out to master it.

    I'm actually developing a methodology for passing coding interviews. The first step, as in all sciences, is taxonomy. Philosophers of old sought (magical) power over a problem by saying it's true name. Today we break the problem down into classes that share common properties we can exploit. To this end, I have encountered the following types of coding tests.
    • Basic Skills Test: These questions are meant to test your familiarity with the basics of programming. Common problems in this class include reversing a string, tokenizing a string, and the recently popular fizzbuzz. I can't count the number of times I've coded atoi() or strtok() over 30 years of interviews.

      Unless you're a poser, these tests are supposed to be easy. The trick for senior devs is not to feel insulted that you are being asked to solve such a simple problem. When I was younger and less humble, I would bring a printed copy of atoi() with me to prove how smart I was. Nobody was impressed. They just asked a different question.

      I understand the need to test a candidate's ability to do basic coding. I might be a poser who cannot write any code at all. It's shocking but true that there exist people who make a living by fabricating resumes, then briefly take high-paying jobs as engineers, until somebody figures out they are frauds. However, when I get five basic-skills questions in a row at an interview, it definitely lowers my opinion of a prospective employer. Such an employer is looking for a code monkey, not a senior software engineer, or they'd ask some design or methodology questions.
    • Data Structures Test: These questions are designed to gauge the depth of your familiarity with well-known data structures. Code I've been asked to write recently includes inorder binary tree traversal (recursive and iterative), heap insert, and breadth-first tree traversal. A lot of non-coding questions also test how comprehensive your data structure knowledge is.

      Most data structure questions are not too hard if, indeed, you went to college and paid attention in Algorithms & Data Structures class. These questions pose a problem for the self-taught, no matter how gifted they are on workaday coding tasks.

      If you're applying for a senior position, the questions will be more challenging, and may involve obscure data structure tricks. Maybe these trick questions are supposed to be lateral-thinking tests; the coding test descendents of those "Why are manhole covers round?" tests for which Microsoft was once famous. My experience is if you don't know the trick, you will be frustrated and out of time before the interviewer offers a key hint.

      For instance, heap insert is simple enough to code, if you happen to know the trick of implementing the heap in an array so that there are formulas to compute the index of the parent and children of any node. You may have seen heap insert described briefly, using a tree diagram to show the state of the heap. This memory takes you down the wrong path. Try to work it out from first principles using the heap property and a linked tree-node data structure with no parent link (like I did, ouch), and you're toast; it's too hard to do in one interview session.

      Another question I was asked recently was “find the inorder successor of a node iteratively”, which can be coded in a few minutes if nodes have an extra link to the parent node. For senior developers, the more comfortable you are with tree data structures, the less likely it is that you will consider this unusual extra pointer.
    • Algorithm Test: The basic questions in this category include all manner of “iterate over an array where the entries have global property X” questions.

      The algorithm test is the most challenging class of questions for me, because these problems require the most concentration, and some original thought, not just recall. Standing at the whiteboard, solving an unfamiliar problem, trying to talk about what I'm thinking, while the interviewer watches the clock, is not my preferred way to concentrate.

      In applying for senior positions, I have been given problems of significant complexity; finding the longest palindrome, two-dimensional divide and conquer, dynamic programming chores that look like they should have a simple inductive recurrence relation but don't. indeed, I have been asked questions so difficult that the interviewer did not actually understand the problem or its solution, and offered incorrect hints. I gotta say, they could as well have not wasted their time and mine by inviting me to such an interview. It's outrageous.

    Tuesday, May 24, 2011

    Is Something Wrong With Coding Tests?

    I'm looking for work as a senior software developer these days, so I'm doing a lot of coding interviews. I am uncomfortable with coding interviews. They're stressful; get the optimal answer, quickly, to a problem often selected to be difficult or unfamiliar. They're adversarial; you are a poser unless you prove yourself worthy. They're artificial; produce correct code, but on a whiteboard, from top to bottom, without being able to go back and add a few lines, in less than 20 minutes.

    But what makes me most uncomfortable about coding interviews is that I don't see a connection to a developer's day-to-day practice. I have to develop an unfamiliar algorithm only a couple of times a year. I implement a standard data structure almost never (with the exception of linked lists). My day-to-day practice consists of decomposing hard problems into many generally-easy-to-code steps. In fact, the coding chores I perform are usually so familiar to my mind that I do them by reflex, spending most of my attention on how the piece I'm writing nibbles away at a big, hard problem. When I come to a tough bit of coding, I slow down, analyze the heck out of it, test it, and make a deliberate end of it. Concentrating on the code is a distraction that keeps me from concentrating on the problem I'm solving.

    But coding tests aren't big. You can't nibble at them. They're all hard part, compressed, like evil haiku. You can't work deliberately; there's an interviewer behind you with a stopwatch. Coding tests are in fact just like CS homework assignments, where you must solve a riddle on paper and then write 10 lines of code. They reward the new grad, who has recent practice with homework problems, and no reflexes for coding. They play to the vanity of the recent hire, very impressed with their own training; unaware of how much they don't know.

    When you apply for a senior position, interviewers ramp up the difficulty of the coding challenges. Instead of problems from an undergrad data structures class, they pose supposedly unfamiliar problems. These problems generally have a simple, inefficient solution, and perhaps one or more faster solutions that involve dynamic programming. The bar is higher for senior applicants than for new grads. This would be sensible if solving this kind of problem was something we all did every day so that experience made us better at it. The fact that we don't do CS homework problems in the working world makes this kind of interview a subtle form of age discrimination.

    I think of myself as a talented developer, but I haven't shown well on coding tests. That makes me wonder. Are there senior applicants who do really well at coding tests? When companies hire these applicants, do they demolish deadlines and eat hard problems for breakfast, leaving a trail of shredded feature story cards? Or is passing the coding test a mental trick? I've met one guy in my career (hi ~toma) who was a lightning-fast coder. He produced five times as many lines of code as any other member of our ten-person team, and the code he produced was reasonable, if not special. Other than that, I've worked with folks who wrote bad code quickly, folks who wrote decent code at a deliberate pace, and a small number of complete morons. Why haven't I met more devs who could solve any problem brilliantly in 20 minutes?

    Can I study for coding tests? Can I acquire skills that make me more capable of solving such puzzles? (The answer is yes). 

    An even more interesting question is this. If I learn to be good at coding tests, will I become faster than a speeding bullet? Will it inform my day-to-day practice of programming? Stay tuned.

    Monday, May 23, 2011

    Starting Salaries: Red Hot. Old-Hands Salaries: Not So Much

    Ed Lazowska, CS Professor at the University of Washington, claims starting salaries for new CS grads are red hot. In another recent article, the Wall Street Journal claims starting salaries are so high that startups can't compete. The claims are that top new grads are getting offers over $100k plus signing bonuses from very profitable social networking companies.

    Even if this is only half true, and starting salaries are really "way down" in the $80k range, it means something disturbing. It means that the salary premium for experience, which stood at about 2.5x starting salaries when I started working, is continuing to drop. It has reached about 1.5x in 2011 if these sources can be believed. In this way, programming is becomming like nursing; great pay fresh out of college, but not much headroom. Ten years on, there doesn't seem to be much reward for staying in the field.

    Interestingly, both software development and nursing are claimed by employers to have a serious shortage of experienced workers.

    Another thing that might be happening is that the industry is stratifying into hot, high-paying jobs that demand insane hours from superstar developers, and a long tail offering rather less spectacular wages for geeks without super-powers, and finally an army of code monkeys churning out add/change/delete screens and login pages for third-world wages, often in third world countries.

    Part of the problem is certainly that a great many people entered software development in the late '90's. These people are only arriving at the 10-year level of experience now, and cannot perceive the additional skills old hands possess, because inexperienced people don't have these skills. Part is that APIs and hot programming languages change so fast that 10-year-old skills are no longer in fashion, and not every senior developer bothers to keep up-to-date.

    None of this is good news for anyone interested in a career in Computer Science. Employers wonder why they can't find enough experienced people. They wonder why people with a choice tend to leave the field. Maybe there's a reason. Duh!

    Thursday, May 5, 2011

    Welcome to the Old Hands Blog

    My name is Kurt Guntheroth. I have been a software engineer since, well, lets just say that clock rates were lower back then. You could count the pins on your processor. You could hear the individual bits go out on the modem. If you wanted a PC, you soldered it together. I am what you might call an Old Hand.

    For years I've been thinking what I'd write if I wrote a book about software development. I know a little something about programming, about the process of developing code, about managing geeky people, about being a member of a development team, and about being an employee of a for-profit corporation. I wrote a couple of articles in print journals, but then the internet killed print (RIP C++ Users Journal, Dr Dobbs, and the rest). I've been a commenter on other people's blogs. Now it's my turn.

    An Old Hand helps the new guys "learn the ropes". Anyone know what that expression means any more? It comes from the days of wooden sailing ships, when the running rigging came down in a complex but well-ordered profusion of identical-looking ropes, and your mates depended on you to know which lines were tacks and which were sheets, and so forth. Guys found themselves on a ship at sea sometimes because they drank too much at the wrong bar. The old hands taught them which ropes were which, so nobody got killed.

    I have no pretension to have things of universal value to say. I will write things down that seem to me to be useful to know but not frequently heard. The cool thing about the web is that it knows what is useful. If my voice appears in that list, then I'm successful.

    I'm not a high-powered over-achiever, microsoft millionaire, or IBM vice president. I'm a working engineer. I like building beautiful things that nobody else can see. Good thing too, 'cause that's what it means to be a software developer most of the time.

    I'm new to social media. When my wife, who is also an Old Hand, hears I have a blog, she'll probably faint dead away. I'm not sure I'll mention it to her. I once argued that social media was all self-promotion. Then someone patiently explained to me why that wasn't (necessarily) true. It's something the new guys have to teach us Old Hands.

    Thanks for listening.