DaedTech

Stories about Software

By

Leading Software Teams of Humans

I’ve been working lately on a project where I handle the build and deployment processes, as well as supply code reviews and sort of serve as the steward of the code base and the person most responsible for it. Not too long ago, a junior developer delivered some changes to the code right before I had to roll out a deployment. I didn’t have time to review the changes or manually regression test with them in place (code behind and GUI, so the unit tests were of no use), so I rolled them back and did the deployment.

That night, I logged back on and reviewed the code that I had deleted prior to the build. I read through it carefully and made notes, and then I went back to the version currently checked in and implemented a simpler version of the fix checked in by the junior developer. That done, I drafted an email explaining why I had reverted the changes. I also included in it some praise for getting the defect fix right, my own solution requiring less code, and a few pointers as to what made my solution, in my opinion, preferable.

By the time I finished this and saved a draft to send out the next day, it was pretty late at night and I was tired. As I got ready for bed, I contemplated what had motivated me along this course of action when none the extra work I did was really required. Clearly I thought this course of action was important, but my motivations were mainly subconscious. I wanted to understand what guiding principles of leadership I might be abiding by here and hammer them out a bit. And I think I got it figured out.

  1. Justify and explain your decisions.
  2. Prove the merits of your approach–show, don’t tell.
  3. Let members of your team take risks, using you as a safety net.

Explain Yourself

As I discussed in a previous post, a leader/manager issuing orders “because I say so” is incrementally losing the respect of subordinates/team members. And that’s exactly what’s going on if you simply make decisions without getting input or explaining the reasoning after the fact–as would have been the case in my situation had I not sent the email. What you’re saying to people when you unilaterally take action isn’t really clear because it’s cryptic and terse. So they’re left to interpret for themselves. And interpret they will.

They’ll wonder if maybe you’re just a jerk or paranoid. They’ll assume that you think they’re not important enough to bother with an explanation. Perhaps they’ll surmise that you think they’re too stupid to understand the explanation. They’ll wonder if they did something wrong or if they could improve somehow.

And really, that last one is the biggest bummer of all. If you’re a team lead and you need to overturn a decision or go in a different direction for a valid reason, that’s a very teachable moment. If you sit with them and help them understand the rationale for your decision, you’re empowering them to mimic your decision-making next time around and improve. If you just undo all their work with no fanfare, they learn nothing except that fate (and the team lead) is cruel. Seriously–that’s the message. And there are few things more demoralizing to an engineer than feeling as though the feedback mechanism is capricious, unpredictable, and arbitrary.

Show, Don’t Tell

“Because I said so” costs you respect in another important way on a technical team, as well. Specifically, it threatens to undermine your techie cred. You may think you’re Guru and you may even be Guru, but if you don’t occasionally offer demonstrations, the team members will start to think that you’re just a loud-mouthed armchair quarterback suited only for criticism, yelling, and second-guessing.

ArmchairQuarterback

If you lead a team and you don’t know what you’re doing technically, you’ll obviously lose them. But if you’re leading a team and you have a cloud architecture “do as I say” approach at all times, the outcome will differ only in that you’ll lose them more slowly. You should do something to demonstrate your technical chops to them. This will go a long way. Rands does an excellent job of explaining this (and I pay a subtle homage to his ideas with my post’s title). You have to build something. You have to show them that you’re the leader for a reason other than because you’ve hung around the company for a while or you have friends in high places. Developers usually crave meritocracy, and flashing some chops is very likely to make them feel better about following your lead. And you get bonus points if the flashing of said chops saves them work/teaches them something/shows them something cool.

You Are the Safety Net

I worked in a group once that was permeated by fear. It was a cultural thing born out of the fact that the loudest group members were the most paranoid and their skepticism flirted dangerously with cynicism. Nobody could be trusted with changing the code base, so code reviews were mandatory, often angry affairs that treated would-be committers as dastardly saboteurs out to commit acts of digital terrorism. The result of this Orwellian vibe was that progress and change happened inordinately slowly. Group members were much more terrified of doing the wrong thing than of missing deadlines or failing to implement features, so progress crawled.

I could also tell that there were intense feelings of stress for some people working this way. The feeling that you have to constantly avoid making mistakes is crippling. It is the province of a culture of learned helplessness–get yelled at enough for making code changes that aren’t good enough and you’ll just resort to asking the yellers to sit with you and show you exactly what to do every time. You’ll take no risks, run no experiments, and come to grips with no failures. You won’t improve–you’ll operate as a grunt and collect a paycheck.

As a team leader, this is a toxic environment if performance is important to you (and it might not be–some people just like being boss and having the luxury of not being judged on lack of performance). A stagnant, timid team isn’t going to have the autonomy necessary to handle the unexpected and to dream up new and innovative ways of doing things. In order for those things to happen, your team has to be comfortable and confident that mistakes and failed experiments will be viewed as valuable lessons learned rather than staging points for demerits, blame, and loss of political capital.

SafetyNet

So if someone on your team checks in code that breaks the build or slips into QA with problems or what-have-you, resist at all costs the impulse to get worked up, fire off angry emails, publicly shame them, or anything else like that. If you’re angry or annoyed, take some deep breaths and settle down. Now, go fix what they did. Shield them from consequences of their good-faith actions that might make them gun-shy in the future. Oh, don’t get me wrong–you should certainly sit them down later and explain to them what they did, what the problem was, and what fixing it involved. But whatever you do, don’t do it in such a way that makes them scared of coding, changing things, and tinkering.

Will this approach mean some late nights for you? Yep. Does it suck to have to stay late cleaning up someone else’s mess? Sure it does. But you’re the lead. Good leaders work hard and make the people around them better. They offer enthusiasm and encouragement and a pleasant environment in which people can learn and grow. They don’t punch out at five like clockwork and throw anyone that threatens their departure time under the bus. Leadership isn’t a matter of entitlement–it’s a position of responsibility.

By

Flyweight

Quick Information/Overview

Pattern Type Structural
Applicable Language/Framework Agnostic OOP
Pattern Source Gang of Four
Difficulty Easy

Image courtesy of dofactory

Up Front Definitions

  1. Client: Code that uses the flyweight implementation
  2. Concrete Flyweight: A class that actually implements the abstract class/interface flyweight.
  3. Extrinsic State: State that is not common to the flyweights and varies per instance.
  4. Flyweight: An interface that defines and exposes the extrinsic state.
  5. Flyweight Factory: Class used by clients to retrieve instances of the flyweights.
  6. Intrinsic State: State that is common across all flyweights of the same type.

The Problem

Most of these design patterns posts deal with compile-time problems brought about by painting oneself into a corner with design decisions. In other words, if you make certain missteps when designing a system, it becomes rigid and difficult to change in the future. Patterns such as the Factories, Composite, Decorator, etc., all address prevention of such missteps by isolating responsibilities and making change management simple. Today, the problem we’re going to look at is a runtime problem rather than a compile-time problem.

Let’s say that you’re asked to create a model that simulates the distribution of mail in the USA for a given day. You start by establishing some pretty reasonable business objects to represent the domain concepts in question: letters and postcards. Each of these things has certain properties you’re going to need to keep track of, such as dimensions and postage, so that you can report in aggregate on paper usage, revenues, etc. Here is your first crack at business objects:

public abstract class MailPiece
{
    public abstract decimal Postage { get; set; }
    public abstract decimal Width { get; set; }
    public abstract decimal Height { get; set; }
    public abstract decimal Thickness { get; set; }
 
    public int DestinationZip { get; set; }
}
public class Letter : MailPiece 
{
    public override decimal Postage { get; set; }
    public override decimal Width { get; set; }
    public override decimal Height { get; set; }
    public override decimal Thickness { get; set; }
 
    public Letter()
    {
        Postage = 0.46M;
        Width = 11.5M;
        Height = 6.125M;
        Thickness = 0.25M;
    }
}
public class Postcard : MailPiece
{
    public override decimal Postage { get; set; }
    public override decimal Width { get; set; }
    public override decimal Height { get; set; }
    public override decimal Thickness { get; set; }
 
    public Postcard()
    {
        Postage = 0.33M;
        Width = 6.0M;
        Height = 4.25M;
        Thickness = 0.016M;
    }
}

Alright, awesome. Now, according to the USPS, there are 563 million mail pieces processed in the USA each day (as of 2011). So, let’s just use that as our loop counter, and off we’ll go:

static void Main(string[] args)
{
    var pieces = new List();
    for (long index = 0; index < 563000000; index++)
    {
        pieces.Add(new Letter() { DestinationZip = (int)(index % 100000) });
    }
 
    Console.ReadLine();
}

Satisfied, you fire up the program to make sure everything here is in good working order--although, really, why bother? I mean, what could possibly go wrong? The program chugs along for a bit, and it strikes you that it's taking a while and your desktop is starting to crawl. You fire up the process manager and see this:

Danger, Will Robinson

Yikes! That's... troubling. You start to wonder if maybe you should intervene and stop the program, but Visual Studio isn't being very responsive and you can't even seem to get it to hit a breakpoint. Just as you're contemplating drastic action, Visual Studio mercifully puts an end to things:

OutOfMemory

You're not very close to getting all of the records in, so you decide to divide the original 563 million by 24 in order to model the mail being processed on an hourly basis, but that's really all the more granular that you can do. You fire up the program again to run with 23,458,333 and hit out of memory once again.

So, What to Do?

If you look at your creation of letters (and presumably later, postcards) you should notice that there's a fair bit of waste here. For every letter you create, you're creating four decimals that are exactly the same for every letter, which means that you're storing four unnecessary decimals for all but one of the letters you create, which in turn means that you're storing somewhere in the neighborhood of two billion unnecessary decimal instances in memory. Whoah.

Let's try a different approach. What we really seem to want here is 23 and a half million zip codes and a single letter. So let's start off simply by building a list of that many zip codes and seeing what happens:

static void Main(string[] args)
{
    var pieces = new List();
    for (long index = 0; index < 23458333; index++)
    {
        pieces.Add(new Letter() { DestinationZip = (int)(index % 100000) });
    }
 
    Console.ReadLine();
}

Woohoo! That runs, and for the first time we have something that doesn't crash. But what we're really looking to do is cycle through all of those mail pieces, printing out their zip, postage, and dimensions. Let's start off by cheating:

static void Main(string[] args)
{
    var zipCodes = new List();
    var letter = new Letter();
    for (int index = 0; index < 23458333; index++)
    {
        zipCodes.Add(index % 100000);
        Console.Write(string.Format("Zip code is {0}, postage is {1} and height is {2}",
            zipCodes[index], letter.Postage, letter.Height));
    }
 
    Console.ReadLine();
}

That gets us what we want, but there's a lot of ugliness. The client class has to know about the exact mechanics of the mail piece's printing details, which is a no-no. It also has the responsibility for keeping track of the flyweight letter class. There are better candidates for both of these responsibilities. First of all, let's move the mechanism for printing information into the mail piece class itself.

public abstract class MailPiece
{
    public abstract decimal Postage { get; set; }
    public abstract decimal Width { get; set; }
    public abstract decimal Height { get; set; }
    public abstract decimal Thickness { get; set; }
 
    public string GetStatistics(int zipCode)
    {
        return string.Format("Zip code is {0}, postage is {1} and height is {2}",
            zipCode, Postage, Height);
    }
}

Notice that we've removed the settable "DestinationZip" and added a method that prints piece statistics, given a zip code. That allows us to simplify the client code:

static void Main(string[] args)
{
    var zipCodes = new List();
    var letter = new Letter();
    for (int index = 0; index < 23458333; index++)
    {
        zipCodes.Add(index % 100000);
        string pieceStatistics = letter.GetStatistics(zipCodes[index]);
        Console.Write(pieceStatistics);
    }
 
    Console.ReadLine();
}

Asking the letter object for its statistics definitely feels like a better approach. It's nice to get that bit out of the client implementation, particularly because it will now work for postcards as well and any future mail pieces that we decide to implement. But we're still worrying about instance management of the flyweights in the client class, which really doesn't care about them. Let's introduce a new class:

public class MailPieceFactory
{
    private readonly Dictionary _mailPieces = new Dictionary();
 
    public MailPiece GetPiece(char key)
    {
        if (!_mailPieces.ContainsKey(key))
            _mailPieces[key] = BuildPiece(key);
 
        return _mailPieces[key];            
    }
 
    private static MailPiece BuildPiece(char key)
    {
        switch (key)
        {
            case 'P': return new Postcard();
            default: return new Letter();
        }
    }
}

Here we have a public method called "GetPiece" to which we pass a key indicating what sort of piece we want. As far as client code goes, that's all that matters. Under the hood, we're managing the actual flyweights. If the dictionary doesn't have key we're interested in, we build a piece for that key. If it does, we simply return the flyweight from the hash. (Note that the scheme of indexing them by characters will scale, but isn't really optimal at the moment--you could use an enumeration here, restrict the set of allowed keys with preconditions, or have a special default scheme.)

Let's see what the client code looks like.

static void Main(string[] args)
{
    var factory = new MailPieceFactory();
    var zipCodes = new List();
 
    for (int index = 0; index < 23458333; index++)
    {
        zipCodes.Add(index % 100000);
        var randomPiece = factory.GetPiece(GetRandomKey());
        string pieceStatistics = randomPiece.GetStatistics(zipCodes[index]);
        Console.Write(pieceStatistics);
    }
 
    Console.ReadLine();
}
 
private static char GetRandomKey()
{
    return new Random().Next() % 2 == 0 ? 'P' : 'L';
}

There. Now the client code doesn't worry at all about keeping track of the flyweights or about how to format the statistics of the mail piece. It simply goes through a bunch of zip codes, creating random pieces for them, and printing out their details. (It could actually dispense with the list of zip codes, as implemented, but leaving them in at this point underscores the memory benefit of the flyweight pattern.)

There's now some nice extensibility here as well. If we implemented flats or parcels, it'd be pretty easy to accommodate. You'd just add the appropriate class and then amend the factory, and you'd be off and running. When dealing with scales of this magnitude, memory management is always going to be a challenge, so using a pattern up front that reuses and consolidates common information will be a big help.

A More Official Explanation

According to dofactory, the purpose of the Flyweight pattern is:

Use sharing to support large numbers of fine-grained objects efficiently.

The Flyweight pattern requires that you take the objects whose information you want to share for scaling purposes and divide their state into two categories: intrinsic and extrinsic. Intrinsic state is the state that will be shared across all instances of the same type of object, and extrinsic state is the state that will be stored outside of the instance containing common information. The reason for this division is to allow as much commonality as possible to be stored in a single object. In a way, it is reminiscent of simple class inheritance where as much common functionality as possible is abstracted to the base class. The difference here is that a single instance stores common information and an external interest holds the differences.

To make the most of the pattern, flyweight creation and management is abstracted into one class (the factory), intrinsic state to another set of classes (the concrete flyweights), and extrinsic state management to a third class (the client). Separating these concerns allows the client to incur only the memory overhead of the part of an object that varies while still reaping all of the benefits of OOP and polymorphism. This is a powerful optimization.

Other Quick Examples

  1. The iconic example of the Flyweight pattern is to have flyweights represent characters in a word processing document, with the extrinsic state of position in the document.
  2. Another use is rendering in graphical applications with many similar shapes or patterns on the screen in configurable locations.
  3. It can also be used to represent some fungible commodity of which there are many in a video game, such as enemies, soldiers, scenery elements, etc.
  4. One of the more interesting and practical examples is string "interning" in C#

A Good Fit – When to Use

As the cost of memory and disk space continues to plummet, emphasis on this pattern is seeming to wane a bit. However, there will always be occasions in which resource management and optimization are crucial, and bottlenecks will always exist where even liberally purchased resources need to be used wisely. The flyweight pattern is a good fit any time you have redundant, common state in many objects that you're creating. If you find yourself in this position, the pattern is really a no-brainer since it's simple and costs very little to implement in terms of code complexity.

Square Peg, Round Hole – When Not to Use

This isn't the kind of pattern where you're likely to go out looking for excuses to try it out since it solves a very specific problem that is different from a lot of other patterns. I would exercise caution more when choosing extrinsic and intrinsic state in that you're going to experience downstream pain if you label things "intrinsic" that actually can vary. Doing this threatens to break the pattern and the abstraction that you've created since modifying state that's categorized as intrinsic will mean that your flyweights are no longer interchangeable and you're going to start getting stuff wrong.

So this isn't a good fit if you don't have a good grasp yet on what should be extrinsic and what should be intrinsic. It's also a bad fit if all state is extrinsic, as then there is no gain from the pattern. Another potential misuse that's always worth mentioning with an optimization strategy is premature optimization. While I personally consider the elimination of duplication at runtime simply to be good design, I'd say that you might want to consider not bothering with the additional compile-time complexity if you're not going to have very many objects. If, for instance, you were simulating twenty pieces of mail instead of tens of millions, it might not be worth the additional complexity.

So What? Why is this Better?

This one pretty much sells itself. In the example above, you can run the code without crashing or altering your data structures. Generally speaking, this is a pattern that helps you reduce your application's memory footprint simply by creating a clever abstraction and shuffling the internal representation. If you can identify when there will be common information in volume, you can separate it from the unique information and make sure you're being as efficient as possible.

By

New Theme for DaedTech

As you may have noticed, if you’re not reading this via RSS, I’ve changed the look and feel of the site a bit. I wanted to keep the overall theme of the site while getting a little more modern with the UX, and this is the result. The content portion doesn’t expand to the full width of your screen on higher resolution, things are a little more tiled, and the blog home no longer displays all text, pictures, etc.

I accomplished this by installing the catch box theme and then modifying the CSS to get it to look mostly similar to daedtech as it existed before. I also made modifications to some of the theme’s PHP pages. I looked at a pretty good cross-section of posts and pages to make sure I ironed out all of the kinks, but no doubt some of you will find ones I missed in the first 45 minutes the theme is live, so please feel free to let me know if anything looks weird or wrong to you, either via email or comments.

My hope is that the theme choice and modifications help to improve the site’s performance. I’m also planning to make some additional modifications along those lines to speed things up in the next few weeks as well, time allowing.

Cheers!

By

Introduction to Web API: Yes, It’s That Easy

REST Web Services Are Fundamental

In my career, I’ve sort of drifted like a wraith among various technology stacks and platforms, working on web sites, desktop apps, drivers, or even OS/kernel level stuff. Anything that you might work on has its enthusiasts, its peculiar culture, and its best practices and habits. It’s interesting to bop around a little and get some cross-pollination so that you can see concepts that are truly transcendent and worth knowing. In this list of concepts, I might include Boolean logic, the DRY principle, a knowledge of data structures, the publish/subscribe pattern, resource contention, etc. I think that no matter what sort of programmer you are, you should be at least aware of these things as they’re table stakes for reasoning well about computer automation at any level.

Add REST services to that list. That may seem weird when compared with the fundamental concepts I’ve described above, but I think it’s just as fundamental. At its core, REST embodies a universal way of saying, “here’s a thing, and here’s what you can do to that thing.” When considered this way, it’s not so different from “DRY,” or “data structures,” or “publish/subscribe” (“only define something once,” “here are different ways to organize things,” and, “here’s how things can do one way communication,” respectively). REST is a powerful reasoning concept that’s likely to be at the core of our increasing connectedness and our growing “internet of things.”

So even if you write kernel code or Winforms desktop apps or COBOL or something, I think it’s worth pausing, digressing a little, and understanding a very shallow-dive into how this thing works. It’s worth doing once, quickly, so you at least understand what’s possible. Seriously. Spend three minutes doing this right now. If you stumbled across this on google while looking for an introduction to Web API, skim no further, because here’s how you can create your very own REST endpoint with almost no work.

Getting Started with Web API

Prerequisites for this exercise are as follows:

  1. Visual Studio (I’m using 2012 Professional)
  2. Fiddler

With just these two tools, you’re going to create a REST web service, run it in a server, make a valid request, and receive a valid response. This is going to be possible and stupid-easy by virtue of a framework called Web API.

  1. Fire up Visual Studio and click “New->Project”.
  2. Select “Web” under Visual C# and then Choose “ASP.NET MVC 4 Web Application”
    MVC Project
  3. Now, choose “Web API” as the template and click “OK” to create the project.
    WebApi
  4. You will see a default controller file created containing this class:
    [gist id=”5167466″]
  5. Hit F5 to start IIS express and your web service. It will launch a browser window that takes you to the default page and explains a few things to you about REST. Copy the URL, which will be http://localhost:12345, where 12345 is your local port number that the server is running on.
  6. Now launch fiddler and paste the copied URL into the URL bar next to the dropdown showing “GET” and add api/values after it. Go to the request header section and add “Content-Type: application-json” and press Execute (near top right)
    FiddlerRequest
    (Note — I corrected the typo in the screenshots after I had already taken and uploaded them)
  7. A 200 result will appear in the results panel at the left. Double click it and you’ll see a little tree view with a JSON and “value1” and “value2” under it as children. Click on the “Raw” view to see the actual text of the response.
    FiddlerResponse
  8. What you’re looking at is the data returned by the “Get()” method in your controller as a raw HTTP response. If you switch to “TextView”, you’ll see just the JSON [“value1″,”value2”] which is what this thing will look like to most JSON-savvy parsing tools.

So what’s all of the fuss about? Why am I so enamored with this concept?

Well, think about what you’ve done here without actually touching a line of code. Imagine that I deployed this thing to https://daedtech.com/api/values. If you want to know what values I had available for you, all you’d need to do is send a GET request to that URL, and you’d get a bare-bones response that you could easily parse. It wouldn’t be too much of a stretch for me to get rid of those hard-coded values and read them from a file, or from a database, or the National Weather Service, or from Twitter hashtag “HowToGetOutOfAConversation,” or anything at all. Without writing any code at all, I’ve defined a universally accessible “what”–a thing–that you can access.

We generally think of URLs in the context of places where we go to get HTML, but they’re rapidly evolving into more than that. They’re where we go to get a thing. And increasingly, the thing that they get is dictated by the parameters of the request and the HTTP verb supplied (GET, POST, etc.–I won’t get too detailed here). This is incredibly powerful because we’re eliminating the question “where” and decoupling “how” from “what” on a global scale. There’s only one possible place on earth you can go to get the Daedtech values collection, and it’s obviously at daedtech.com/api/values. You want a particular value with id 12? Well, clearly that’s at daedtech.com/api/values/12–just send over a GET if you want it. (I should note you’ll just 404 if you actually try these URLs.)

So take Web API for a test drive and kick the tires. Let the powerful simplicity of it wash over you a bit, and then let your mind run wild with the architectural possibilities of building endpoints that can talk to each other without caring about web server, OS, programming language, platform, device-type, protocol setup and handshaking, or really anything but the simple, stateless HTTP protocol. No matter what kind of programming you do at what level, I imagine that you’re going to need information from the internet at some point in the next ten years–you ought to learn the basic mechanics of getting it.

By the way, if you liked this post and you're new here, check out this page as a good place to start for more content that you might enjoy.

By

Characterization Tests

The Origins of Legacy Code

I’ve been reading the Michael Feathers book, Working Effectively with Legacy Code and enjoying it immensely. It’s pushing ten years old, but it stands the test of time quite well–probably much better than some of the systems it uses as examples. And there is a lot of wisdom to take from it.

When Michael describes “legacy code,” he isn’t using the definition as you’re probably accustomed to seeing. I’d hazard a guess that your definition would be something along the lines of “code written by departed developers” or maybe just “old, bad code.” But Michael defines legacy code as any code that isn’t covered by automated regression tests (read: unit tests). So it’s entirely possible and common for developers to be writing code that’s legacy code as soon as it’s checked in.

HouseOfCardsI like this definition a lot, and not, as some might suspect, out of any purism. I’m not equating “legacy” with “bad,” embracing the definition as a backhanded way to say that people who don’t develop the way that I do write bad code. The reason I like the “test-less” definition of “legacy code” is that it brings to the fore the largest association that I have with legacy code, which is fear of changing it.

Think about what runs through your head when you’re tasked with making changes to some densely-packed, crusty old system. It’s probably a sense of honest to goodness unease or demotivation as you realize the odds of getting things right are low and the odds of headaches and blame are high. The code is rat’s nest of dependencies and weird work-arounds, and you know that touching it will be painful.

Now consider another situation that’s different but with similar results. You have some assignment that you’ve worked on for weeks or months. It’s complicated, the customer isn’t sure what he wants, there have been lots of hiccups and setbacks, and there’s budget and deadline pressure. At the bitter end, after a few all-nighters, a bit of scope reduction, and some concessions, you somehow finally get all of the key features working for the most part. You check in the code for shipping, thinking, “I have no idea how this is working, but thank God it is, and I am never touching that again!” You’ve written code that was legacy code from the get-go.

Legacy code isn’t just the bad code that the team before you wrote, or some crusty old stuff from three language versions ago, or some internal homegrown VBA and Excel written by Steve, who’s actually an accountant. Legacy code is any code that you don’t want to touch because it’s fragile.

Getting Things Under Control

In his book, Michael Feathers lays out a lot of excellent strategies for taming out-of-control legacy code. I highly recommend giving it a read. But he coins a term and technique that I’d like to mention today. It’s something that I think programmers should be aware of because it helps lower the barriers to getting started with unit testing. And that term is “characterization tests.”

Characterization tests are the “I’m Okay, You’re Okay,” Rorschach approach to documenting code. There are no wrong answers–just documenting the way things exist. So if you have a method called AddTwoNumbers(int, int) and it returns 12 when you feed it 1 and 1, you don’t say “that’s wrong.” Instead you write a test that documents that return value and you move on, seeing and documenting what it does with other inputs.

Sound crazy? Well, it’s really not. It’s not crazy because things like this actually happen in real life. When code goes live, people work their processes around it, however much its behavior may be goofy or unintended. Once code is in the wild, “right” and “wrong” cease to matter, and the requirements as they existed some time in the past are forgotten. There only is “what is.” Sounds very zen, and perhaps it is.

One of the most common objections when it comes to unit testing is from developers that work on legacy systems where code is hard to test and no tests exist. They’ll say that they’d do things differently if starting from scratch (which usually turns out not to be true), but that there’s just no tackling it now. And this is a valid objection–it can be very hard to get anything under test. But characterization tests at least remove one barrier to testing, which is having extensive experience writing proper unit tests.

With characterization tests, it’s really easy. Just write a unit test that gets in the vicinity of what you want to document, finagle it until it doesn’t throw runtime exceptions, assert something–anything–and watch the test fail. When it fails, make note of what the expected and actual were, and just change the expected to the actual. The test will now pass, and you can move on. Change some method parameters or variables in other classes or even globals–whatever you have access to and can change without collapsing the system.

Through this poking, prodding, and documenting, you’ll start getting a rudimentary picture of what the system does. You’ll also start getting the hang of the characterization test approach (and perhaps unit testing for real as an added bonus). But most importantly, you’ll finally have the beginnings of an automated safety net. There’s no right and wrong per se, but you will start to be able to see when your changes to the system are making it behave differently in ways you didn’t expect. In legacy, different is dangerous, so it’s invaluable to have this notification system in place.

Characterization tests aren’t going to save the day, and they probably aren’t going to be especially easy to write. At times (global state, external dependencies, etc.) they may even be impossible. But if you can get some in place here and there, you can start taking the fear out of interacting with legacy code.

By the way, if you liked this post and you're new here, check out this page as a good place to start for more content that you might enjoy.