Imagine this...
You and five other developers have just been hired as contractors for a 4 month project at Acme Corporation. Congratulations! Going in, you've been told that there's a chance some of you could be hired at the end of these 4 months to continue working on the system, and since you all prefer the stability of full time work, you're encouraged by this. You also learn that for Acme, releasing the software in 120-days is absolutely critical, and accordingly, your manager (who, incidentally determines whether you stay or go at the end of the contract) is most concerned with whether the system works, not how you make it work. Finally, you've all been given different functional areas to work on, so you'll be working relatively independently of your fellow contractors.
Sound good? Now here's my question for you: will you comment your code?
Deep down, you know writing comments is a good thing to do, but if the situation is as I described it, I'm guessing you might not. Here's why:
Analyzing the Decision
The decision you're faced with, to comment or not comment your code, can be modeled in a simple two-by-two matrix, where rows represent your decision, columns represent the other contractors' decision, and the cells represent the unique possible outcomes (i.e. the intersection of your decision and the other contractors' decision). For each outcome, there are two numbers: one which represents the benefit (or "utility) that you would receive for that outcome, and the other representing the benefit everyone else individually receives.
Everyone Comments | Everyone Doesn't Comment | |
---|---|---|
You Comment | You: 8, Everyone: 8 | You: -2, Everyone: 2 |
You Don't Comment | You: 10, Everyone: 6 | You: 0, Everyone: 0 |
The utility payouts for the four possible outcomes are derived as follows:
1. Everyone Comments (upper-left): If you comment your code and so do the other contractors, everyone does equally well. Though you all had to expend a little effort to write good comments, the upside is that you're left with a well documented system at the end of four months, and so if you do indeed get extended, your life will be much easier in the long run for maintenance and enhancements. Assuming a +2 utility for each person (other than yourself) whose comments you get to read and -2 utility for the time expenditure of having to write comments, each person receives an 8.
|
Given these payouts, how do you decide what to do?
Well, assuming you are rational (that is to say, you're interested in maximizing your own utility) then you subtract away everyone else's payouts, and look at the decision matrix like this:
Everyone Comments | Everyone Doesn't Comment | |
---|---|---|
You Comment | You: 8 | You: -2 |
You Don't Comment | You: 10 | You: 0 |
What you realize, then, is that no matter what everyone else does, you're always better off not commenting your code! For example, if you think everyone else will comment their code, you're still better off not commenting, because you can get all the benefit of reading their comments with none of the cost of writing them yourself .
Everyone Comments | |
---|---|
You Comment | You: 8 |
You Don't Comment | You: 10 |
If, however, you think none of your colleagues will comment their code, again, you're better off not commenting - if you're not going to get any benefit of reading other people's comments, you mine as well not exert the effort yourself!
Everyone Doesn't Comment | |
---|---|
You Comment | You: -2 |
You Don't Comment | You: 0 |
You begin to understand, sadly, that it just isn't in your best interests to comment your code, and so you end up not doing it. The unfortunate crux of this situation, however, is that your fellow contractors use similar logic and decide not to comment as well. In the end, you're all stuck with a utility of zero - a completely uncommented system.
Everyone Comments | Everyone Doesn't Comment | |
---|---|---|
You Comment | You: 8, Everyone: 8 | You: -2, Everyone: 2 |
You Don't Comment | You: 10, Everyone: 6 | You: 0, Everyone: 0 |
"But wait a minute", you think, "it didn't have to be this way"! If you all had just ignored your self-interest and written comments, you all would have been much better off with a utility of 8, instead of the 0 that you actually received.
Everyone Comments | Everyone Doesn't Comment | |
---|---|---|
You Comment | You: 8, Everyone: 8 | You: -2, Everyone: 2 |
You Don't Comment | You: 10, Everyone: 6 | You: 0, Everyone: 0 |
In other words, the group as a whole was made worse off because each person followed their own individual best interests!
Prisoner's Dilemma
In the language of game theory, this situation is called a "Prisoner's Dilemma", and refers to any two player, two decision game with the following payout structure:
Cooperate | Defect | |
---|---|---|
Cooperate | win, win | lose much, win much |
Defect | win much, lose much | lose |
The essential element of the game is that the Nash equilibrium (i.e. the outcome that rational agents are driven to - in our case, don't comment/don't comment) is Pareto inefficient, which just means that there is another outcome in which all players would be better off (e.g. comment/comment). In Prisoner's Dilemma terminology, doing the rational thing to the detriment of the group (in our case, not commenting your code) is called "defecting". Conversely, ignoring your own rational self interest to the benefit of the group (e.g. commenting your code) is called "cooperating".
So what does this all mean for code comments in software systems? Would we really be irrational to comment our code? From a rational choice perspective , the answer is "it depends". If the situation was similar to Acme's 4-month long project, then yes, it would be irrational for developers to comment their code - it's just not in their best interests. Not all companies, however, operate like Acme. In many cases, specific environmental, organizational, or cultural factors can work to augment the incentives in the decision such that a developer's self interest can align with the team's best interest. The question is, then, what are these factors that contribute to win-win outcomes? How can a software development organization encourage cooperative software development behavior, whether it's commenting code, writing unit tests, refactoring, or writing design documentation?
1. Evaluate Internal Quality
Acme's first mistake was focusing solely on external behavior, to the neglect of internal quality. Had Acme manangers evaluated developers not just on functional, but on extra-functional concerns (like maintainability, extensibility, etc.) as well, then each developer's incentive structure would have been rebalanced to the extent that commenting would be in their obvious best interest - not commenting would be risking their future at Acme. To this end, managers who are interested in the long-term viability of a system must find some way to measure internal quality (whether by attending code reviews or analyzing reports from static source code analysis tools like PMD, CheckStyle, or FindBugz) and then tie incentives to it.
2. Harness the Power of Reputation
Even if Acme's managers didn't evaluate internal quality, had their developers been working collaboratively and reviewing each others code, then reputation alone could have been a strong enough force to compel them to write good code. For most developers, their reputation is their most valuable asset - more important than any credential or experience on a resume when finding future work. Software organizations need to use the power of reputation to incent good coding practices, and they can do this by promoting collaboration, enforcing design and code reviews, or publishing code quality metrics per component or developer to a Wiki. When a developer knows others will see his code, he will naturally do his best. If, on the other had, a developer is disconnected from his colleagues, the temptation to take short-cuts may be too great.
3. Encourage Reciprocation through Long Term Relationships
Players in a Prisoner's Dilemma intuitively understand that when playing many games instead of just one, cooperating in the short-term will yield benefits in the long- in other words, if I scratch your back now, you may scratch mine later. Acme, however, hired short-term contractors who had no guarantee of a long-standing relationship with Acme, and so reciprocation wasn't much of a factor in their individual comment-or-not-comment decision calculus. Had they known they'd be working with their colleagues in the future, then even if they were working on isolated features, they'd know that down the road one of their colleagues might need to debug their code (or vice-versa) and comments would help. By writing clean, commented code for others, others might write clean, commented code for them. Companies, therefore, when possible, should try to foster long-term relationships with their developers and by so doing will increase the likelihood of cooperation.
4. Start out on the Right Foot
When determining whether to defect or cooperate, a player of an iterated Prisoner's Dilemma game looks to his opponents' past actions. If he finds himself in a situation where everyone consistently defects, then he'll defect too, so not to be the "sucker". The same holds for developers when presented with a system of poor internal quality - "if no one else takes the time to write good code", they think, "why should I"? For this reason, setting an early precedent of good development practices is key. A project that gets off on the wrong footing will have great difficulty regaining its balance.
Conclusion
Each of these four principles is important for encouraging good development practices - though no single principle alone is imperative. For example, a company that hires short-term contractors can still create high quality software if they set an early precedent of good coding, increase visibility of developer's work through code reviews or static code analysis tools, and tie incentives to internal quality. An organization, however, that neglects each of these principles - hires short-term developers, evaluates only whether the system works and not how, allows developers to work in isolation, and starts out with a poorly coded system - will be doomed to buggy software at best, and failed projects at worst.
Resources
-
In 1979, Robert Axelrod held his now famous computing tournament, which pitted different Prisoner's Dilemma playing agents against each other to see which strategy would yield the greatest utility. Does it really pay to defect? To everyone's surprise, the agent that won was coded with the most straightforward strategy: tit-for-tat. In Evolution of Cooperation
, Axelord tells the story of this tournament and explains what it means for cooperation at all levels (animals, people, countries).
-
Apparently, Bill Clinton made each person in his cabinet read
Nonzero
- for whatever that's worth;). A feel-good pop-science book that asserts that evolution naturally tends toward greater cooperation.
-
The Origins of Virtue
explains that morality (i.e. cooperation) is neither some rational construction of ours nor is it merely a divine mandate, but rather it's hard-coded into our fundamental design because it gives us the best chance for survival.
-
Hume
disagrees that we are naturally cooperative, and instead argues that it is government's role to encourage cooperation amongst its citizenry.