How The Game Is Played

http://blogs.sun.com/gameguy/date/20060111 Wednesday January 11, 2006

Why I don't believe in Code Review

Why I don't believe in code review.

Note: A good observation came back from comments. I should make clear that I am talking in this piece about the way I have seen code review implemented-- as a blanket requirement that every line of code must be reviewed. As a point technique I am quite sure it can be quite valuable. I've just never had the privilege of seeing it used that way. -- jk

Anyone who knows me knows that I consider questioning orthodoxies the duty of every thinking member of any organization. In my book the question "why" is never well answered with "that's the way we do things here." It is far too easy to fall into wasteful or even counter-productive habits by accepting such a reason. Often behaviors persist as "standard practice" far after the reasons they were originally put into place have changed. Sometimes, standard practices just arise out of a prejudice or an idea that was never more then half-baked to start with.

Today I want to address a standard Sun practice and why I feel it may in fact be counter-productive. That practice is "code-review". Code review is the rule that at least one other person must look over any code you write for any errors they can spot or things they can improve. It is a form of peer-review and peer-review, under some circumstances, can be very valuable. I personally don't believe software development to be one of those circumstances, at least in the general case.

To understand my perspective you need to understand that most of my programming career has been spent in an industry where efficiency is king-- the game industry. Efficiency of your code is important because well tuned game code provides a better user experience. Efficiency of the coding process is also important because you are developing on a fixed time and budget and the more programming work you can accomplish in that time, the more fully featured and exciting your product will be. The keys to being a successful game programmer are producing working, efficient code as quickly as possible.

Code review is virtually unheard of in the game industry.

Why is this? Well, I believe there are two good arguments why general code review is antithetical to the game programming process. The first is a logical argument and the second is a philosophical one.

In order to logically analyze the value of code review we need to make a clear assessment of its costs and returns. Anyone I have ever talked to who does really thorough code reviews has told me that it takes them more time and energy to review someone else's code then it would take to write that code themselves.

This is not surprising. Coding is a complex process and the competent engineer is juggling and evolving a highly complex model of the code-flow in their head as they code. For someone else to read that code and grok that bigger picture is a major bit of work.

My first 3 jobs in the industry all started by having someone else's code dropped on my desk and being told "Here. We need someone to understand and maintain this." To do this right, I had to spend a lot of time reading and analyzing the code, until I could "get into the original coder's head" and understand what they were thinking when they wrote it. It a lot of work and you never succeed 100%.

But think about that first statement. What it says really is this: Code review more then doubles the man-power cost of writing that piece of code. Thats an awfully big "nut to crack" as we say in the entertainment industry in terms of value code review must return for it to be a net gain.

So what are the values of code review? Lets go down what I understand the claimed values to be and examine them in order.

  • Code review improves code quality.

    This is a pretty general glittering-generality, but lets see if we can't make it more specific. The idea here is that each coder has individual tricks and techniques they have developed on the micro-level that improve the reliability and/or performance of their code. By looking over each other's code they share the value of these things.

    Thats all well and good, but what is the real value? I contend that any competent coder above entry level should already know how to write reliable code and that they should be expected to write reliable code. If this is the expected case, is it really worth doubling the cost of code creation just to find the rare case when it is not? I don't tend to think so. Furthermore, I fundamentally believe that it is a waste of human brains to make them do work that a computer can do just as well as fast or faster.

    In the case of code correctness, I think that less effort can be spent more productively by defining the code contracts clearly and then writing complete tests to test code against those contracts. Josh Bloch sums the first part of this up well in his book Effective Java when he says "always design with interfaces first." Engineers that write sloppy code,in my experience, make themselves well known through the results of their coding and corrective measures can then be taken once there is a known problem.

    Similarly, there is an important rule in performance tuning. What doesn't matter, doesn't matter. Anyone who does serious performance coding, and all game programmers do, knows that striving for maximal efficiency across all your code is not just wasteful but often counter productive. The most efficient code is not necessarily the cleanest, clearest or most maintainable. But efficiency in the right places can be critical to over-all program performance. The general rule is called the "90/10" rule. In general 10% of your code does 90% of the work and it is that 10% that needs to be tuned for efficiency. The rest should be designed for readability and maintainability.

    The problem with a code review as a mechanism to attain this proper balance is that it is impossible for a human being to correctly statically analyze the performance characteristics of any significantly complex program. There is simply too much happening on the fly inside of such a program for you to be able to approximate its behavior correctly enough in your head.

    Something I have lectured on time and again in my role as a Java performance guru is that all performance tuning work begins with measurement. That is why a Profiler is your one absolutely critical tools in tuning code performance. Once you have determined what 10% of your code contains your bottlenecks, then and only then can you properly tune it.

    You might be noticing a pattern here. I contend that to create truly high code quality takes active test, measurement and management of your code base. The problem with code review is that it is passive, treating all code as equally important. In the forest of code it is way too easy to thus spend inordinate amounts of time on things that don't really matter and miss things that do. This is not to say that peer opinions aren't valuable, but in my opinion they aught to be confined to code that really matters, and the best way to do that is to allow the engineer to profile and test his or her code and then ask peers for help where it is needed.

  • Code review improves code maintainability

    Maintainability is a funny concept in coding. We generally think of it as the ability to upgrade and improve code, but more code is ruined by "maintainence" that pushes it beyond its originally designed in limits then any thing else in computer science. The newsletter of the Society of Computer Professionals for Social responsibility summed it up this way many years ago: "Elevators break down if they aren't maintained. Code breaks down if it is!"

    Nonetheless there are some desired and desirable characteristics of maintainable code. Having been in the code maintainence business my first 3 years in the industry I can say that naming conventions are a Good Thing(tm). Having said that, uniform naming conventions I honestly think are over-rated. In each of the cases I mentioned above I had C code dropped on me written by different people in different settings and thus with different naming conventions. I would say it took me maybe 3 hours in each case to get used to the coder's conventions-- an almost insignificant amount of time in the total scheme of the work.

    More importantly though, as I've already said, I don't believe that you should make people do things that computers can do just as well and faster. Java has standard naming conventions which is great. Why we don't have a lint-like tool to check them though is frankly beyond me. This is the sort of job a compiler or compiler-like program can do over hundreds of thousands of lines of code without breaking a sweat. So let the compiler do it, and don't load humans with the responsibility to review code for it.

    Something that, for similar reasons, I think is even sillier are formatting conventions. The fact of the matter is that readability of formatting conventions is highly subjective. There is no one right answer. The tools exist to reformat code however you like to read it completely on the fly. So rather then trying to push everyone into coding in the same format, just let everyone format the code they want to read however they are most comfortable reading it. One could easily imagine an editor that could show you your preferred "view" of code while maintaining the existing structure in the actual data. All in all, this is another thing computers do better then humans and humans should not be bothered with.

    Adequate commenting can be a big help in later reading of code. However IMO adequate commenting should be the duty and responsibility of any trained engineer the same way correctness is a duty. I am a big believer in empowerment and responsibility of working engineers. I am also a believer in alibi books. Any project should define clear standards for how much of what kind of documentation is required along with any other project standards for work. Any engineer on that project should either live up to that contract or, where they break it, explain the reasons in an alibi-book. This should be the responsibility of the engineer and something on which their performance is reviewed at the appropriate review times.

Thats my summation of the logical costs/benefits as I see them. But I said there was a philosophical component to my belief as well. To understand that, you need to understand how I view coding. Fundamentally, I don't believe software engineers are engineers at all. I believe software engineers are artists. We just call ourselves engineers because artists get paid crap. At the end of the day, I believe that our job has much more in common with writing or painting then calculating the stress forces on a house. I think we give this away in the way we talk about our work. The highest compliment one can give a piece of code is that it is "elegant." Elegance is not a measurable quantity, rather it is an aesthetic judgment. An artistic judgment.

I do not believe that artists do their best work when their brush-strokes are micro-managed and that is what I see code review as doing. Van Gogh's hand likely slipped in a number of places when painting Starry Night. In fact, having studied the painting, I strongly suspect he was using techniques that were not considered "proper brush strokes" at all at the time he painted it. Do you care? Of course not, because the result of his entire work is successful at its goal and is a magnificent success.

Uniformity and the drive to it is the death of art. If you don't believe me, go spend at least 3 hours straight in a Thomas Kincaide gallery. If you can do that without going insane you are either incredibly strong willed or have no artistic soul at all. As I believe the best code is art, I believe a drive to uniform form on the micro-level is also deadly to it. I believe that competent engineers should be given a clearly defined problem (often defined through a software specification and/or a set of Interfaces) and left alone to produce the best solution in their own brush-strokes. Where there are problems, be they engineering sloppiness, critical code inefficiencies, or just plain errors I believe it is the duty of the coding engineer to isolate and deal with them specifically and on an individual basis.

All in all, I honestly think general code review does far more to create and foster religious arguments over style then it actually does to improve either quality or readability of a code-base. I also think it is, at best, a major waste of very valuable engineering talent and, at worst, actually a distraction and a detriment to the creation of exceptional software products.

As usual. Your Mileage May Vary.

Comments:

I disagree with you on several points, but first let's deal with an obvious fallacy.
To understand my perspective you need to understand that most of my programming career has been spent in an industry where efficiency is king-- the game industry. Efficiency of your code is important because well tuned game code provides a better user experience.
That's called special pleading. It doesn't work unless you can show how the special circumstances make a difference to the claim(s) under debate, and in this case that's not likely. Gaming is not the only programming subdiscipline in which performance is critical, nor even the most difficult. Kernels, many types of embedded systems, and HPC all come to mind as examples of more challenging specialties that still don't succumb to that false reasoning. Even if that weren't the case, you haven't come close to showing how reasoning based on the supposed special needs of game programmers can be generalized to all of programming.
Code review improves code quality. This is a pretty general glittering-generality, but lets see if we can't make it more specific. The idea here is that each coder has individual tricks and techniques they have developed on the micro-level that improve the reliability and/or performance of their code. By looking over each other's code they share the value of these things.
That's not the only way in which code reviews improve code quality. In addition to having their own tricks and techniques, each coder also has their own blind spots. If you've ever unit-tested your code, chances are that you've seen it pass the unit tests and then fail in later tests or in the real world. How can that happen? It's easy when the person writing the test has the same blind spots as the person writing the code because they're the same. Everyone has blind spots, and there's just no substitute for a second pair of eyes to spot bugs that live there. It's similar to the "many eyes make all bugs shallow" philosophy of open source, except that in this case it actually works because it includes even the bugs that are hidden from the casual novice's view.
In the forest of code it is way too easy to thus spend inordinate amounts of time on things that don't really matter and miss things that do. This is not to say that peer opinions aren't valuable, but in my opinion they aught to be confined to code that really matters, and the best way to do that is to allow the engineer to profile and test his or her code and then ask peers for help where it is needed.
Congratulations, that's a code review. You're absolutely right that priority should be given to the most critical pieces of code, and also that reviews should be lightweight, but that's only an argument against one specific style of doing reviews. Presenting it as a general argument against all code reviews is a bit of the excluded middle.
more code is ruined by "maintainence" that pushes it beyond its originally designed in limits then any thing else in computer science
If the original author writes unnecessarily obfuscated code, or the maintainer is incapable of understanding code that's exactly as complex as it needs to be, then that's likely to remain true, but not if both are competent. You yourself point out that understanding another's code can be more difficult than rewriting it, and that's true initially until you (or your customers) start finding all of the bugs that were reintroduced in the process. In the end it's a waste, and it's a waste characteristic of novice programmers who dream up all sorts of rationalizations for not doing something that's hard or unpleasant. I believe Joel Spolsky has written quite eloquently about this phenomenon, but I'll settle for a simple question. Would you feel more comfortable shipping code to your customers that was rewritten by your laziest programmer, or that was maintained by your most diligent one? That's often the choice you'll have.
uniform naming conventions I honestly think are over-rated... ...Something that, for similar reasons, I think is even sillier are formatting conventions
Unfortunately, most people seem to be exposed to this kind of nit-picking early in their career, and it sours their attitude toward a valuable part of the development process. Bitching about naming and indentation and curly braces in a review is a waste of everyone's time, but not all code reviews are like that. I've run many that had a specific rule about needing a clear line between every comment and a present or almost-inevitable future functional flaw - and somebody to enforce that rule. Such reviews usually go quite quickly and turn out to be very productive. I've seen them yield measurable improvements in code quality, so if you're the kind of guy who believes in "active test, measurement, and management" of anyone's code base there you have it. Usually the people who hate code reviews the most are those who quite justly always feel beaten up in them. Find out how to do code reviews right, and you might find that they're not such a bad idea after all.

Posted by Platypus on January 11, 2006 at 09:15 PM EST #

Thanks for the thoughtful response. Let me comment in return, if you will.

First off, on the "special pleading" case. You are absolutely right, but all you've really done is uncover what I hoped the thoughtful reader would figure out by the end-- that although I am using a specific industry example it has much more general applicability. That the issues of time and functionality apply to most projects.

Having said that, I think it IS true that the direct link of work to money is more obvious at the trench-level in most game programming projects then many corporate projects, and for that reason game programmers are less likely to trope to any technique that does not have a practical cost/benefit trade off.

I probably should have said "why I don't believe in universal code review" and for that I apologize. I absolutely agree with you that it can be a useful point-technique in known critical places and, in fact, I believe I call for this when I suggest that engineers drive that by asking their peers for advice and assistance on identified portions of code where they face issues. More generally, it doesn't have to be formal code review IMO, it can often be of the form of "let me tell you what I'm doing here". I use that kind of give and take and peer brain-picking all the time.

What I am against is what I have seen most often called "code review" which is where someone in management or administration proclaims that every line of code must be reviewed before it can be used. I find that pointless and wasteful for all the reasons I mentioned.

On the matter of blind spots. That could simply be an argument for having others write unit tests. I also think you need to draw a distinction here between code modules of a dedicated app and library code. Code modules of an app fulfill their purpose if they correctly fulfill their contract as expected by the modules they interact with. Library code has to be proven more, generally correct in all possible use cases. In either case there are techniques for writing good unit tests having to do with analysis of the contract and testing of edge cases BUT particularly in the library case I certainly can see the value of having independent test resources. Having said that, not every project can afford that and good library developers IMHO get pretty good at testing their own code. I've seen excellent libraries developed by a single diligent library developer.

On the maintainence point, I wish I had a pointer to that old CPSR article because it had a wealth of statistics, but in summary the point was this. All code is developed with inherent limits on the domain of problems it is designed to handle. This is unavoidable as it is both too expensive and too hard to optimize a completely general approach for almost any significantly complex problem domain. Code “maintainence” generally takes the form of stretching the use of that code well past the use cases envisioned and designed for by the original engineers. Over time this makes the code more and more brittle til it inevitably breaks. Most working engineers I think instinctively know that there “always comes a point where the right answer is throw it out and re-write it.” This is just a practical acknowledgment of this phenomenon.

”Would you feel more comfortable shipping code to your customers that was rewritten by your laziest programmer, or that was maintained by your most diligent one? That's often the choice you'll have.” I'll answer you in two ways. First, we don't have lazy programmers in the game industry. We have dilligent hard working ones and we have unemployed ones. Thats the reality of the environment. Similarly I generally would rather not have a coder on my team at all then have a lazy one as he or she is far more likely to damage the work and moral of my good coders then to add any real value. Having said that, one code hits the point where you breath on it and it breaks, I'd rather have a junior re-write it then a senior try to keep it going. Sometimes the only right answer is throw it out.

As to well managed and done code reviews, I will have to take your word. My experience has pretty much been that when someone says “code review” it is accompanied by an edict that “all code must be reviewed.” Used intelligently and in the right circumstances, I'm sure its a useful technique. Used intelligently and under the right circumstances almost any technique has its place. This is just one that I have personally only seen abused.

Posted by gameguy on January 11, 2006 at 11:03 PM EST #

On the matter of blind spots. That could simply be an argument for having others write unit tests.
Perhaps, but to be truly useful it would have to be "white box" testing rather than "black box" and embody as thorough an understanding of the code as you'd get in a review. Not to put too fine a point on it, but people who are fluent enough with code (particularly code tied to a specific area of expertise) to do that well tend to be in development, not QA. If you have to get another developer to write the unit tests, you've just committed all the resources that a code review would require and then some. That's closely related to another code-review benefit that we've barely touched on - familiarity. Having someone else review your code is not so much a way for them to learn general "tricks and techniques" that you have used, as you suggest, but it's also a way to gain familiarity with that specific part of the product. Programmers do get hit by trucks. More often they just leave, voluntarily or otherwise, and with one customer call it can become critically important that someone else be already up to speed on that code. Maybe that's not so much a consideration with games or products targeted at fellow developers, but people who have written code for avionics or nuclear power-plant control or health care develop a very different perspective. Gaining that kind of familiarity requires at least a walkthrough, and once you're doing a walkthrough it's an extremely short step to (some kind of) code review.
it is impossible for a human being to correctly statically analyze the performance characteristics of any significantly complex program
An excellent point, but performance is not the only issue in code reviews. More generally, even if it were true for correctness as well, what conclusion should we draw from it? That we shouldn't do code reviews? Huh? Maybe we should conclude instead that code reviews shouldn't be seat-of-the-pants affairs. Most code reviews start with the assumption that the code already compiles. What if the code includes declarations (e.g. if it's written in Eiffel, SPARK, or Sing++) that allow proof of correctness? Then reviewing the code includes reviewing those declarations. Some of the organizations with the (provably) lowest defect rates use precisely this technique, and also happen to have reviews as part of their process. Praxis is only the most recent example I can think of, and they address productivity as well.

Posted by Platypus on January 12, 2006 at 06:32 AM EST #

Like you I have seen examples of 'every line of code must be reviewed', and it's not been done well. This often comes about when more experienced developers have thier code reviewed by less experienced ones. This often leads to reviews that go something like 'typo here in this comment, indentation here is wrong' and thats about it. When it's the other way round, you generally get justified comments about efficiency or flawed/missing logic that make the author of the code feel beat upon. Both of these leave people feeling either hurt, or that thier time was wasted, and then everyone hates code reviews.

I have also seen it work. Where the members of the team were either more equally matched, or where the least experienced developers had reached the point where they were finally ready to learn (I remember going through the process of feeling like I was beat upon in code reviews, and then finally realising it wasn't personal, and used it as a learning experience).

The review itself also needs to be done intelligently. 'review every line of code' is pointless unless there is some kind of caveat stating 'even if that means deciding the block it's in is not significant enough in the grand scheme of things'. Reviewing logic steps rather than code lines is the key to a good code review in my experience, and I think being a good code reviewer is hard to do. I know I'm not good at it unless I spend a large amount of time doing it.

I believe that it comes down to how critical it is get 'something' working v.s. penalty for incorrectness. If you can patch it up later with no worries, then a code review becomes much less important. If you have to get it right first time, then it's far more important.

A general rule might be, that general rules don't work :). Each case has it's own merits.

Posted by Endolf on January 12, 2006 at 08:53 AM EST #

So Endolf brings up some good points. Some comments of mine in no particular order.

Code review as an education tool is an interesting suggestion of value. My comment on that however is this: if it is for education, then the person being reeviewed should be learning. If they are learning, then the actual return from the process should be diminishing over time. at some point, the person being reviewed has enough competence that the code review no longer has enough value to be worth doing.

This thought in fact was in the back of my mind and why I limited my comments to engineers of a competant junior level or higher. My experience has been that what I consider a competant Junior is generally experienced enough to know what they know and what they need to ask about. At that point I think the educational value of reviewing all their code drops off to the point where it is no longer of significant value.

Again thats just my experience and my opinion. What I am sure of though is that there is *some* critical line of experience where the learning potential from code review drops below the work required and that there are more efficient ways for people at those levels to learn.

Endolf also brings up what I would call known critical code. Code where the cost of failure is *very* high. One good example is medical equipment. That is a place where I could see code review of critical control-code to be of utmost importance. Another might be nuclear reactor control. Interestingly enough though, last I looked the Sun Java software license explicitly declined suitability of our code and liability for the results for any such usages.

Posted by gameguy on January 12, 2006 at 11:28 AM EST #

I will not debate further the need for competent well done code reviews. But it does link to something you said that I believe is partially true. You said that Software Engineers are not engineers at all. Granted, many of us write code with little process or systematic methodology. Software is a medium that allows the well versed person to create as no other medium does. I believe though that this creativity can be very enhanced with sound, proven engineering principles. Yes they can be over done (The CMM , etc.) but a well defined process coupled with knowledgeable creativity will produce, in my opinion, sofware that can be better maintained and enhanced. It is still a young field, and again as I stated has a creative component that really no other field has. But the use of patterns, OO processes, and good sound (not over bearing) project management can and has only made the production of software better and more cost effective.

Posted by ibmengineer on January 12, 2006 at 12:29 PM EST #

"a well defined process coupled with knowledgeable creativity will produce, in my opinion, sofware that can be better maintained and enhanced"

I'd agree with you, but stress that there is not one *single* well defined process but many that can accomplish those ends. And IME they accomplish those ends with about equal success despite the attempt to totally change and reinvent them every 5 years or so.

IMO thats because the key is not a particular process, but just *having* a process. Things done willy-nilly and disorganized never come out terribly well. If there is any mistake in your comments, it is only in assuming that working artists are any less process driven. Nothing could be further from the truth. Ask any *good* artist and they will tell you that there were a whole host of theories and basic techniques they had to master and organized approaches to doing their work they routinely use.

The image of the wild-haired crazy artist is mostly the stuff of legend and myth. Well done art is as organized as any other major human endevour.

Posted by gameguy on January 12, 2006 at 02:38 PM EST #

The image of the wild-haired crazy artist is mostly the stuff of legend and myth. Well done art is as organized as any other major human endevour.
The "programmer as wild-haired crazy artist" meme has been around for a long time, to the extent that essays on the subject have become a degenerate art form unto themselves. This art form reached its nadir with Paul Graham's Hackers and Painters, which has as its sole redeeming value the fact that it provoked this brilliant response from a real artist. I suspect you've seen it before, but maybe someone else reading this hasn't and would appreciate it.

Posted by Platypus on January 12, 2006 at 03:54 PM EST #

Its an amusing piece but I can't say I agree with him a whole lot, and Im not sure how much is tounge in cheek and how much we are supposed to believe him.

I will give him that he is a painter. I don't know if he is a good one. I can speak from my own perspective as a published author (non-fiction) and serious dabbler (in fiction.) And in both those cases organization and process are absolutely paramount. Probably the most important part of any non-fiction book is its structure and organization. The writing process begins with an outline that sketches your entire argument from beginning to end, and that outline is the core of all the work that follows. Without that you get unreadable trash.

The process of writing fiction is actually even more rigorous. The great agent/author Sol Stein has published a wonderful series of tapes and computer-base course-ware on how to write fiction well. (http://www.masterfreelancer.com/wsstore/wpfm1.html). I've worked the first unit in his course and it helped my writing immensely. There is a definite, reliable process for creating the outline and then details of fiction. Its starts from defining characters and their motivation and then develops through defining their goals and the impediments to those goals. Finally the details are worked out by letting the characters' personalities drive the details. Done properly, the result is good fiction.

I'd highly recommend the WritePro series and Stein's lectures to anyone interested in writing fiction, I promise you it will improve your work (unless you already know all this and are as good at it as Stein.)

My point being that the successful writer, far from being a "crazy haired artist" is a highly disciplined professional craftsman who holds a great understanding of the tools of his craft and how to apply them. Frankly I doubt its any different for *successful* painters.

Oh, and I have to disagree with our painter's assessment of sexual odds too. Painter == poor. Lots of luck. Since college I have had NO trouble attracting women as a brilliant nerd. Or as we are called today-- techno elite. Power is an aphropdisiac and today the nerds have it both socially and economically. ;)

Posted by gameguy on January 12, 2006 at 06:05 PM EST #

Post a Comment:
Comments are closed for this entry.