Wednesday January 11, 2006
How The Game Is Played
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.
Posted at 08:30PM Jan 11, 2006 by gameguy in General | Comments[9]
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 #
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 #
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 #
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 #