Stories about Software


Why You Should Do Periodic Reviews of Legacy Code

Editorial Note: I originally wrote this post for the SmartBear blog.  Go take a look at the original here, at their site.  If you like posts about collaboration, code review, and other topics, take a look around while you’re there.

Legacy code is sort of like your house’s storage crawlspace.  It tends to be a repository for things that mattered to you in days past or on special occasions.  The code sits there, largely unnoticed, until such time as an odd change or a production bug causes you to dig it up, dust it off, and revisit it.  Barring extraordinary circumstances, it tends to sit, largely forgotten, and possibly rotting or getting riddled with moth holes.

By and large, this considered an acceptable and even desirable state of affairs in our industry.  A lot of folks that manage software development efforts and hold the purse strings think of software construction the way they think of building construction.  Once you’ve built a house, it’s done.  Why would you go back and revisit it unless there was some kind of problem that had cropped up?  The problem with this well-intentioned, bottom-line thinking is that building software isn’t much like building houses.

When you build software, you stack the new atop the old and everything comes along for the ride.  Sure, there may be the occasional new module that stands all by itself or plugs in with the rest, but that’s the exception.  The new code interacts with the old stuff, calling into it, relying on it, and running beside it in production.  If housing construction worked this way, a short circuit in the house across the street might cause your shower to stop working.

The result is that, however well-intentioned someone encouraging you not to focus on legacy code might be, the edict is often misguided.  If the short circuit across the street meant you couldn’t shower, would you listen to someone who told you their wiring was none of your business?  Clearly, you wouldn’t go storming over there out of nowhere, remodeling that house, but you wouldn’t just ignore it either.


This is the approach required with legacy code in your code base.  The fact that someone typed it out years ago doesn’t mean that it doesn’t have a very real, current impact on your team every time you deploy your code.  Because of this, it behooves you to review it occasionally, when time permits.

Let’s examine some specifics as to why it makes sense to audit your legacy code from time to time.  Having your finger on the pulse of everything going into production is a compelling but abstract argument.  So, let’s get more concrete.

Read More


Code Review Through the Years

What does a code review workflow look like, in your mind? Naturally, when I ask this question, you’re picturing life in 2015 with current tooling, work arrangements, and productivity tools. So when I say, “code review” you probably picture a whole lot more than peering at source code in some kind of file editor.

Maybe you’re imagining a multi-national, distributed, agile team working at different times of day. The team communicates using tools like Slack and various flavors of instant messenger (and, of course, the ubiquitous email). They no doubt use a sophisticated source control option, augmented with a variety of application management tools. Github comes to mind. And, that’s really just the start. Piggybacking on these capabilities for version controlling and communicating, the team probably employs relatively sophisticated heuristics for making sure all committed code gets a look from one or more other people, and they manage this complex communication with an equally sophisticated mechanism for allowing reviewers to zero in on exactly what has changed.

But perhaps the most beautiful thing about being a programmer in this day and age is that these impressive capabilities are pretty seamlessly managed. You can be sitting in London, where you make a series of simple, but cross-cutting, changes to a number of different source files. Then you can leave for the day, at which point a colleague in New York is notified that you have some changes to review. She can take a quick look, realize that the changes in which you’ve renamed a series of methods are extensive but low risk, and give you a thumbs up. She then kicks it over to another colleague in Los Angeles just for a quick second opinion, and delegates to him to make the final call. Once he takes a look and approves, there’s a mechanism to promote the code to a continuous integration environment, build it, run tests on it, and deploy it to production. Your changes are live the next morning when you come in.

We take this for granted, but, really, we’ve come a long way. Imagine what code reviews might have looked like in past eras of programming.


Read More


How Do You Know When to Touch Legacy Code?

Editorial Note: I originally wrote this post for the SmartBear blog.  Head over there and check out the original if you like it.  There’s a lot of good stuff over there worth a look.

Many situations in life seem to create no-win scenarios for you as you innocently go about your business. Here’s one that’s probably familiar to developers for whom pairing or code review is a standard part of the workflow.

You’re tasked with adding a bit of functionality to a long-lived, well-established code base. It’s your hope that new functionality means that you’re going to be writing purely new code, but, as you dig in, you realize you’re not that lucky. You need to open some Death Star of a method and make some edits.


The first thing that occurs to you while you’re in there is that the method is as messy as it is massive. So, you do a bit of cleanup, compacting some code, extracting some methods and generally abiding by the “Boy Scout Rule.” But when you submit for code review, a scandalized and outraged senior developer rushes over to your desk and demands to know if you’re insane. “Do you know how critical that method is!? One wrong move in there and you’ll take down the whole system!”

Yikes! Lesson learned. The next time you find yourself confronted by an ugly juggernaut, you’re careful to be downright surgical, only touching what is absolutely necessary. Of course, this time during code review, the senior developer takes you to task for not going the extra mile. “You know, that’s some pretty nasty code in there. Why didn’t you clean up a little as long as you were already in there?”

Frustrating, huh?

It’s hard to know when to touch existing code. This is especially true when it’s legacy code. Legacy is a term for which you might see any number of definitions. As a TDD practitioner, I personally like Michael Feathers’ definition of legacy code (from his book, Working Effectively with Legacy Code), which is “code without unit tests.”

But for the purposes of this post, let’s go with a more broadly relatable definition: legacy code is code that you’re afraid to touch. I’m sure you can relate to this, even if you’ve never had a senior developer yell at you about how touching it is dangerous (or better yet, leaving an all caps comment in the code threatening anyone who touches it). You size up a giant method with its dozens of locals, loops nested 5 deep, and global variable access galore, and think to yourself, “I have no idea what might happen if I change something here.”

So, what do you do? Should you touch it?

Read More


That Code’s Not Dead — It Went To a Farm Upstate… And You’re Paying For It

Editorial Note: I originally wrote this post for the NDepend blog.  Head over there and check out the original, if you’re so inclined.  I encourage you to go give the NDepend blog a read, in general.

When it comes to pets, there’s a heartbreaking lie that parents often tell little children when they believe that those children are not yet ready to wrap their heads around the concept of death.  “Rex went to a nice farm in the countryside where he can run and play with all of the other animals all day!”  In this fantasy, Rex the dog isn’t dead — he lives on in perpetuity.


Memoirs of a Dead Method

In the source code of  an application, you can witness a similar lie, but in the other direction.  Code lives on indefinitely, actively participating in the fate of an application, and yet we call it “dead.”  I know this because I’ve lived it.  Let me explain.

You see, I’m a method in a codebase — probably one that would be familiar to you.  My name is GetCustomerById(int id) and I hail from a class called CustomerDaoMySqlImpl that implements the interface ICustomerDao.

I was born into this world during a time of both promise and tumult — a time when the application architects were not sure whether the application would be using SQL Server or MySQL.  To hedge their bets, they mandated data access interfaces and had developers do a bit of prototyping with both tools.  And so I came into this world, my destiny taking a single integer and using MySQL to turn that integer into a customer.

I was well suited to this task.  My code was small, focused, and compact, and I performed ably even to the point of gracefully handling exceptions in the unlikely even that such would occur.  In the early days life was good.  I fetched customers on development machines from unit tests and from application code, and I starred for a time on the staging server.

But then my life was cut tragically short — I was ‘killed.’  The application architects proclaimed that, from this day forward, SQL Server was the database of choice for the team.  Of course, neither my parent class nor any of the methods in it were actually removed from the codebase.  We were left hanging around, “just in case,” but still, we were dead.  CustomerDaoMySqlImpl was instantiated only in the unit test suite and never in the application source code.  We would never shine in staging again, let alone production.  My days of gamely turning integers into customers with the help of a MySQL driver were over.

Read More


Writing Tests Doesn’t Have to Be Extra Work

Editorial Note: I originally wrote this post for the Infragistics blog.  Check out the original here, at their site.  If you like this post, please give them some love over there and go check out the original and some of the other posts.

Writing automated tests is sort of like the kale of the software development community.  With the exception of a few outlying “get off my lawn” types, there’s near-universal agreement that it’s “the right thing.”  And that leaves a few different camps of people.

The equivalent of fast food eating carnivores say, “yeah, that’s something that we ought to do, but it’s not for me.”  The equivalent of health-conscious folks plagued by cravings say “we do our best to write tests, but sometimes we just get too busy and we can’t.”  And then, finally, the equivalent of the health nut says, “I write tests all the time and can’t imagine life any other way.”  A lot of people in the first two camps probably don’t believe this statement.  I can understand that, myself, because it’s hard to imagine passing up fried chicken for a kale salad in a universe where calories and cholesterol don’t count.


And yet, I am that ‘health nut’ when it comes to automated testing.  I practice test driven development (TDD) and find that it saves me time and makes me more productive on the projects I work.

It is because of that tendency that I’d like to address a common sentiment that I hear in the industry.  I suspect you’ve heard variants of these statements before.

  • “We started out writing some tests, but we got behind schedule and had to hurry, so we stopped.”
  • “TDD doesn’t make sense in the early phase of this project because we’re just prototyping.”
  • “We didn’t want to write any tests because there’s a chance that this code might get thrown out and we’d just be writing twice as much code.”

The common thread here is the idea that writing the automated tests is, when the rubber meets the road, a bonus.  In the world of software development, the core activity is writing the executable source code and deploying it, and anything else is, strictly speaking, expendable.  You don’t truly need to write documentation, generate automated tests, go through QA, update the project milestones in a Gantt chart, etc.  All of these things are kale in the world of food — you just need to eat any kind of food, but you’ll eat kale if you’re in the mood and have time to go to the grocery store, and… etc.

Read More