C#, Refactoring

Refactoring Is the Key Step in Writing Business Software

I recently found a Reddit post from a sysadmin who had just finished their first C# app for work. They were ecstatic, happily telling their CTO about the daily work they had automated for the multiple technicians working under the sysadmin.

Then the CTO happily replied with a few words that ruined the sysadmin’s day.

“Great! Put it in SVN.”

(SVN – Subversion, the company’s developer source control repository)

The sysadmin knew their first project wasn’t done “the right way”. No examples they’d seen outside of purely academic “Hello World” code looked like theirs. There were many full time C# developers at their company, who would be judging the quality of the sysadmin’s work and might be called on to maintain their code in the future. If they left the company, someone else would inherit the mess they had made. Reputation and karma were on the line.

After deciding against asking the very busy developers at their company, and a crazy ex-employee buddy who wrote bad code, they turned with low expectations to Reddit in a desperate plea of a post.

The problem this sysadmin had is one that is not unique. I’ve frequently been asked by college students what is the difference between academic example code and good production ready business software. In business writing, it would be editing. In programming?

Refactoring is the key step in writing business software.

Refactoring is extracting, renaming, reorganizing, and generally rewriting software until it is able to be easily understood, maintained, extended, and adapted. The sysadmin knew this and the students I’ve talked to already have some idea of it, but they don’t know how. The sysadmin had already discovered that their code needed to be refactored, but just didn’t know how. They couldn’t unthink they way the thought about how to structure a program. Luckily our sysadmin’s post was not unanswered.

When reading their code, it looked like a recipe out of a cookbook.

Get plates

Get ingredient 1
Get ingredient 2
Get ingredient 3

Prepare ingredient 1
Prepare ingredient 2
Prepare ingredient 3

Plate
Cleanup
Serve

This is a common way software programs look when written by novice developers. It is logical and structured and… off. Writing or reading code in this formulaic way doesn’t scale beyond the simplest problems. Many senior developers would claim this program has “code smells”. It doesn’t fit their rubric of good business software.

There were 3 techniques that many of the posters applied to refactoring the sysadmin’s code: Creating a table of contents, removing duplicated instructions, and never remembering more than required for the current task. I would agree that these techniques are the perfect place to start refactoring for beginning programmers.

Here’s how the first, creating a table of contents, changes the appearance of the program:

Get plates
GetIngredients()
PrepareIngredients()
Finish()

GetIngredients(){
 Get ingredient 1
 Get ingredient 2
 Get ingredient 3
}

These sections are very easy to see in many junior developer’s code, because they’ve already used comments and line spacing to separate blocks of related code. They just haven’t broken them out into functions. In Visual Studio however there is no reason not to. The process is usually easily automated via the “Extract Method” tool.

Second, removing duplicated instructions, (also know as Don’t Repeat Yourself or DRY) takes the last step just a bit further:

GetIngredients(){
  ingredients = [1,2,3]
  foreach( var ingredient in ingredients )
    GetIngredient(ingredient)
}

GetIngredient(i){
  Get ingredient i
}

Once again junior developers commonly do the same thing to multiple items in single discrete program statements. The fail to use loops (or use lower level loops like ‘for’ instead of foreach or a LINQ statement) when those would DRY up their code. If you see multiple statements right after each other doing the same thing, or could copy paste lines changing only a couple of characters, a loop is probably called for.

But the third step, never remembering more than is required, can flip step one on its head:

ingredients = [1,2,3]
WorkIngredients(ingredients)
Finish()

WorkIngredients(ingredients){
  for(var ingredient in ingredients){
   GetIngredient(ingredient)
   PrepareIngredient(ingredient)
  }
}

Finish(){
  Get plates
  Plate
  Cleanup
  Serve
}

This needs a bit more explaining. Here we don’t need to remember a specific ingredient after it has been gotten and prepared. So our code shouldn’t loop over the ingredients again to pull up the same ingredient twice. While it may look like we wasted time with step one, in many cases it is necessary to see the shape of the program. Only then can we identify the dependency, the specific ingredient, that any section of logic needs to know about. More simply, we also shouldn’t be pulling out the plates until we are ready to use them, unless we have a very good reason to do so. In real life we only have so much counter space to juggle our plates and ingredients, in programming we only have so much mental space to juggle digital references. We should keep our work space orderly and only use what we need, when we need it.

The trick of all these steps is to make our code more declarative and less procedural, i.e. it tells us what it does first, and de-emphasizes how it does it. Together, these three steps leave us with a program that quickly tell us what it does, leaves the how in small, easy to grasp functions that we can further refactor into their own separate objects if desired. This doesn’t make your code perfect, but leads you down the path to understanding and “smelling” the other problems in your code’s readability and maintainability.

When writing this, I struggled to know if I included enough detail to explain these concepts. I also worried if I focused on the right concepts. As someone who often has to teach these ideas I’m very open to advice on how I could improve this lesson. Please, leave a comment below with your thoughts.

If you are a new or junior developer, and are looking for more help writing good professional business software, please enter your email to sign up for my newsletter here. I’m very interested in connecting with you and helping you further your career with future lessons.

Original Reddit Post