The Seven Code Virtues

Authors: Tim Ottinger and Jeff Langr
Font: Burst My Bubble

Programming pundits often decry the dismal state of code in the world. We hear speakers demand professionalism or a more craftsmanlike value system, rigorous certification, etc. In response to these very demands we find contradiction of these very concepts. The argument is frequently made that whether code is "good" or "bad" is subjective and situational. We beg to differ.

To promote a shared set of programming values, we propose these seven virtues of code:
  • Working, as opposed to incomplete
    A program that works is simply superior to one that doesn't work. We contend that a working program now is of higher value than one that might work some day. To this end, incremental and iterative methods (such as agile methods) push us to complete small features as soon as possible, with improvements and expansions to follow.
    We ensure code is working by writing tests before and after writing code as we consider more success and failure modes. We can tell code is working by running the tests and by using the software.
  • Unique, as opposed to duplicated
    The worst thing we can do to working code is to duplicate it. Copies and near-copies scattered willy-nilly across the code base makes code difficult to maintain. We struggle to eliminate duplication each time we refactor in our red, green, refactor cycle.
    A dirty software industry secret: Many "stepback" or "regression" errors are not really re-broken code, but are instead examples of fixes to duplicated code.
    We can tell that code is duplicated visually (common paragraph structures) or by the use of duplicate detecting tools like Simian.
  • Simple, as opposed to complex
    Simplicity here refers to the number of entities, operations, and relationships present in any particular routine/function, and not to the readability of that module (which we call "clarity").
    The best way to increase simplicity is to use simpler structures and algorithms. Reducing complexity in this way often translates to improved runtimes, smaller code size, and easier optimization.
    We can also improve simplicity of one routine by extracting methods so that a series of manipulations becomes a single step as far as all of its callers are concerned. By moving the extracted methods to the appropriate classes, we also further develop the type system. After extraction, the code still takes all of the same steps, but those steps are evident in far fewer places in the code. The extracted methods are also simpler because they are unencumbered by their original context, a fact which aids us in finding yet simpler algorithms and structures.
    Such simplifying code migration is at the heart of object-oriented design.
  • Clear, as opposed to puzzling
    The meaning and intent of code must be obvious to the reader. Code misunderstandings generate errors. Confusion over code creates delays.
    While high-level languages make it easy to see what code is doing, there is still an art to producing code which communicates its goal and intent. The consensus of multiple readers is nonetheless a reasonably consistent measure of clarity. Therefore, the most reliable way to make code clear is to have multiple colleagues reading it.
    When one sees an improvement in readability from merely renaming variables, classes, or functions it is because one has improved clarity without changing any of the other virtues of the code. Clarity is further amplified by other virtues such as simplicity and brevity.
  • Easy, as opposed to difficult
    Adding and modifying code should not be an arduous process. Ease is largely a matter of how much code must be typed in how many places, and how much configuration must change. In a particularly ugly code base, the easiest way to get code working is to implement a hack in an inappropriate place. In a truly clean and simple code base, putting a correct design into place is often as easy as a hack. Uncle Bob Martin has stated that design has degraded when the doing "the right thing" is significantly harder than making "an ugly hack."
  • Developed, as opposed to primitive
    A primitive system is not necessarily simpler (fewer parts), nor easier (less thinking and typing), nor more clear than a developed system. Primitive code tends to be characterized by Duplication, Feature Envy, and Primitive Obsession code smells. These make a primitive solution more complex, more difficult, and less clear than one built with a well-developed type system.
    In an object-oriented system, the developed type system of an application provides well-thought-out classes whose methods make continued development easy.
    A system is well-developed when functionality appears to be just where one might expect it. String methods on strings, account methods on accounts, and button activations and the like merely make calls on "business objects."
  • Brief, as opposed to chatty
    It is valuable for code to be as brief as possible without sacrificing other virtues. This is part of the reason that language tools like LINQ and list comprehensions and closures have become so popular of late. All programmers, including the one who writes it, benefit from writing and reading less code (as long as this smaller amount of code is otherwise clean).
    Code that is long and chatty is much more likely to contain hidden errors. An overly cryptic method is likely to be misunderstood. Either one is hard to take in at a glance and understand.
    Playing "programming golf" is actually a meaningful activity. If one can make the solution to a problem smaller without sacrificing clarity (or indeed may improve clarity by reducing the solution to a smaller form), then one is reaching a more brief form. The distance from an ideally brief, clear form is unwanted verbosity (chattiness).

Personal Objections To Agile Process

By Tim Ottinger and Jeff Langr
Font is Kristen ITC

We have already discussed organizational objections to adopting Agile work methods. Here we discuss the personal objections.Agile development has never claimed to be an easy fit for all organizations.

We understand most of the reasons that agile transitions can be quite difficult for organizations. Likewise, individuals may be emotionally invested in certain structures and practives so that converting to an agile workstyle is perceived as threatening and undesirable. We again spent time collecting and categorizing a great many complaints, finally boiling (most) of them down to fit on our 7 +/- 2 bullet point format. We find the categorizations given here to be helpful, and hope that they will be useful to the coaches, managers, and developers who visit the Agile in a Flash blog.
  • Personal Bubble/Social Dysfunction The software development industry's long history of attracting anti-social sorts aside, there are some legitimate reasons that people retreat into a personal bubble. Some team members may have bad history together, ranging from the awkward (ill-fated past romance) to unpleasant (adversely opinionated pair) to intolerable (abusive partner). Some suffer from issues such as a simple timidity, fear of exposure for doing non-work tasks at the office, or a tendency toward introversion. There are iron-clad issues such as actual mental or emotional disabilities. Cultural issues can make understanding each other in a team more difficult.
    The personal bubble is a tough issue to overcome, but we don't work in tight teams because it is comfortable. We work in this manner because of the advantages it can bestow:
    • improved code quality
    • ongoing opportunities to learn new techniques
    • wider exposure to the code base
    • a trustworthy, open communication channel with the customer
    • process improvement based on experiential data
    • a team aligned on common goals
  • Lone Ranger Teamwork is the Agile Way, but some individuals prefer immediate gratification with immediate recognition. The fictitious Lone Ranger would ride into town, solve a mystery, rescue the innocent, restore the peace, and disappear, leaving behind a single silver bullet as a signature. This romantic vision is appealing to many programmers. Everyone dreams about being the hero.
    The downside is that a team is functional to the degree that it does not need to be rescued. The Lone Ranger may have been the hero of the day, but he did not share the knowledge and techniques that led to his success. The Lone Ranger does little to help the rescued learn how to solve similar problems in the future.
    A better role model is the Karate Kid's mentor, Mr. Miagi, who not only rescues Ralph Macchio's character, but also teaches him to fend for himself. Skilled practitioners who can teach others are superior assets to the team and the organization. Agile teams provide superior mentoring, which leads to teams developing the art of making good decisions.
  • Old Dog "Habit is habit," said Mark Twain, "and not to be flung out of the window by any man, but coaxed downstairs a step at a time." This is especially true for those productive habits which have served us in the past. Sometimes people don't want to learn any new technologies or methods, and even those who are excited about new skills will revert to old habits under pressure.
    Agile presents significant challenges to the old dog. Practices like TDD require developers to think about solving problems in a different, even inverted manner. Agile planning can invert the flow of how everyone thinks about their work--people once at the tail end of the cycle must think about how their role changes as they look to provide value earlier and more incrementally.
    It may help to realize that agile is not only a change to how the code is written, but a way to ensure that the individuals in the team can develop personally and as a team. It is a way to optimize the meaningfulness of the work that is done. It is a means to gain respect for a developer's contribution. It is likely to increase the perceived value of the Old Dog's work, rather than merely inconvenience him.
  • Zero Sum Game It is especially hard to engender cooperative behaviors when the development team (or its leaders) are competing against each other for position, respect, compensation, or autonomy. If the team thinks in terms of a zero-sum game, then they feel that they can only win if their teammates lose. In organizations with a history or risk of layoffs, developers will scramble to avoid being at the top of the pay hierarchy or at the bottom of the performance stack, knowing that those ends tend to be chopped first. In organizations that reward individual effort, one feels the need to be the last to leave and the first to arrive to beat out his so-called "colleagues."
    Agile promotes a different system. There is more than enough work to go around, and more than enough improvement possible for us all. There is plenty of credit to share. The Mr. Miagi sharing-and-mentoring model comes into play, and we can grow through our contributions to our teammates and our project. We can all have more success, and it lessens none of us.
  • Inferiority Complex The individual may fear he is less capable than his teammates, and may seek to hide his inabilities by working alone. He may be concerned about slowing down his teammates, or dreading daily humiliation at the hands of his teammates. Looking at the famous "rock star" agile developers, the insecure developer may fear that he could never measure up. The most senior persons on a team often fear displaying their few deficiencies in a pairing session.
    The nice thing about a functional agile team is that you eventually will get over that sore ego hurdle. Things like switching pairs frequently to avoid silo pairing, collaborating in an open workspace, and delivering working software every few weeks all create true transparency.
    A motivating fact is that pair programming is a path to personal improvement. Pairing with star programmers tends to make one into a star programmer. In relatively short time, any interested individual can become surprisingly competent. It is mostly a matter of seeing how it is really done, asking questions, and getting some guided practice.
  • Superiority Complex An individual who feels she has a pretty good handle on things may also believe that it is beneath her dignity to be "forced" to work with "mediocre" teammates. She may feel that she is the only one capable of working in agile, or that she is far above the use of common methods. Sometimes she even feels that she's already learned everything worth knowing about software development. To her, teamwork requires her to drag along incompetent partners, a practice that will slow her down and provide no personal upside.
    As agile coaches, we react most strongly to the intransigent, overly cocky developer--but we need to remember that a projected superiority complex can actually be a mask for inferiority complex.Pairing can let the overconfident member fail more visibly, which can allow coworkers to help correct her shortcomings.
    Some rightfully confident developers find that they also enjoy coaching and developing their coworkers. Bluster fades when developers realize that they are not competing against each other, but against errors and code faults. Finally, a developer with top chops in a pre-agile organization will usually emerge as a leader in an agile organization as well.
  • Rejection of Insufficient Miracle The individual experiences problems in the development team that are not addressed by agile methods. She realizes that it will not make all the teammates act like best friends, and won't make customer pressures or payscale changes any better. It may not make them happier in their workspace. Since the new system does not solve their individual issues, they have no reason to use it at all. It is not miracle enough for them.
    The agile focus is on unencumbered and incremental development of the product, the team, the customer relationship, and the organization. Agile is more of a system in which to identify and address problems than it is a method or methodology.
    One might choose to wait for an absolute solution to all problems, but in the meantime it might be good to invest in daily incremental improvements. Agile--in our view, the currently best bet for most software projects--will eventually fall out of favor for a better approach. We don't know what will supplant it, but we can confidently bet that the new methods won't involve eliminating incremental growth. Good things come to those who wait, but only if they work hard while waiting.