Refactoring Complicated, Bad Code

RefactoringOne of the most difficult challenges in programming is fixing someone else’s bad code. This situation can often happen when taking over maintenance of existing software from a different company with inexperienced developers. While writing good code by itself is difficult enough, fixing previously written bad code requires first wading through the code in every execution scenario, and then writing replacement code that accomplishes the same results. Although this process often takes several times as long as initially writing a good version of the program, refactoring a key function or form can reap significant return on investment throughout the course of system support.

The process of fixing previously written code, called refactoring, is often done in small steps. The developer will take a few lines of code at a time and rewrite them to be more efficient, readable, or scalable. This process is then done iteratively until the code is transformed into a well-written program.

The challenge to refactoring comes in dependencies and complex relationships. Dependencies exist in function calls and looped execution paths. Undeveloped programmers often introduce extraneous dependencies or create problems by not separating the program into logically isolated sections. By not isolating code into smaller building blocks, complex relationships form within the code base that are difficult to untangle later. In these cases, small steps will not work. Similar to a very tangled knot, a holistic approach is necessary in this situation.

Although it can be difficult to get started, housekeeping should be the first step: tidying the code with variable renaming and function extraction. By implementing a consistent variable, function, and object naming scheme, the rest of the program will be easier to read. Similarly, extracting repetitive lines of code into functions will further help simplify the program.

With these initial steps out of the way, the next step is to analyze the code for dependencies. Resolving dependencies often requires creating a thorough execution map or process diagram. Microsoft Visio is an excellent tool for this, enabling creation of a full diagram of every possible execution path in the system and the expected responses to user inputs. This diagram should be verified with system stakeholders upon creation, to make sure that no critical paths are missed.

Next, the developer will need to apply critical analysis to find possible relationships or groups of operations that can be separated and isolated. This may require introduction of additional variables, conditions, and functions, however these will often reduce overhead in the final product. For instance, in form processing, the validation logic should be separated from the database code execution. Similarly, database access should often be separated from results processing and formatting.

While refactoring is not always necessary, a good developer will have a sense for when a program is poorly written and needs to be fixed. In complex refactoring projects, it can be challenging to conceptually “grok” the entire workflow at one time. Once the top-level relationships and key optimizations have been discovered, however, there will usually be an “aha” moment where the rest of the system organization elegantly falls into place. While refactoring can be a tedious and time-consuming process, it will often pay for itself many times over throughout the lifecycle of the software product.

Written by Andrew Palczewski

About the Author
Andrew Palczewski is CEO of apHarmony, a Chicago software development company. He holds a Master's degree in Computer Engineering from the University of Illinois at Urbana-Champaign and has over ten years' experience in managing development of software projects.
Google+

RSS Twitter LinkedIn Facebook Email

Leave a Reply

Your email address will not be published. Required fields are marked *