1. Refactoring by Martin Fowler
As a big fan of Martin Fowler, I'm impressed by the term 'Refactoring'. Refactoring is a disciplined technique for
restructuring an existing body of code, altering its internal structure without changing its external behavior. Its heart is a
series of small behavior preserving transformations. Each transformation (called a 'refactoring') does little, but a sequence of
transformations can produce a significant restructuring.
Since each refactoring is small, it's less likely to go wrong. The system
is also kept fully working after each small refactoring, reducing the chances that a system can get seriously broken during the restructuring.
There is a cyclic process in refactoring, which is self explained in the attached diagram

2. Rewrite vs Refactor
Refactoring takes less overall time to release later, but has less chaos. But is it true? Firstly we're assuming chaos is bad.
Also what signifies chaos? Does adding new features count as chaos? Does an adding features badly therefore? To refactor legacy code to
write a new feature, we're going to first have to write tests around the existing legacy code. Assume that the tests don't currently exist and
there is a final release and a stabilization period. There will be bugs that's inevitable. We'll end up fixing the same bugs in the re-write as
were fixed in the legacy system. Maybe true some of the time, but hopefully this will be captured by the unit tests. If we indeed know what bugs were
previously found in the legacy system, it might be prudent to build these into the test cases of the new system.

Often when we talk about re-writes, we mention chaos and often depict it in graphs like the above one.
3. Use Case
We are taking Singleton creational design pattern as the use case for our refactoring process.
Singleton Pattern
Ensure a class has only one instance, and provide a global point of access to it. Encapsulated "just-in-time initialization" or "initialization on first use".
The Singleton pattern ensures that a class has only one instance and provides a global point of access to that instance. It is named after the singleton set, which is defined to be a set containing one element.
The office of the President of the United States is a Singleton. The United States Constitution specifies the means by which a president is elected, limits the term of office, and defines the order of succession. As a result, there can be at most one active president at any given time. Regardless of the personal identity of the active president, the title, "The President of the United States" is a global point of access that identifies the person in the office.
Class definition is represented in the below diagram as:

A Singleton is the combination of two essential properties:
- Ensure a class only has one instance
- Provide a global point of access to it
Singleton vs Global variable
Singletons are very similar to GlobalVariables. But, there are few key differences. For one thing, because singleton access is managed by a class method, you can add
additional logic to that method. More abstractly, the point of a singleton is to ensure that a class has only one instance.
SingletonPattern has to do with how to limit instances, while GlobalVariables are more related to how programmers declare instances.
Nonetheless, singletons have problems similar to globals; e.g., creating dependencies in vastly separated parts of the system, so side
effects can appear far afield from their causes. Often singletons are abused by inexperienced programmers who think that the use of the
pattern will magically solve all the problems associated with GlobalVariables.
Typical Implementation
The singleton provider classes imposes the below checks/rules on the passing singleton types.
- Must be 'sealed' class
- Make sure the type have no 'static' members
- Making sure the type have only one private / protected constructors
Class Diagram
With the above typical implementation, the class diagram is represented as below:
3. n-Refactor Process
Let us initiate our refactor methodology at '9' level with Singleton design pattern as follows.
Refactor-1 : Lazy Instantiation
With lazy initialization you crate instance only when its needed and not when the class is loaded. So you escape the unnecessary object creation.
Lazy instantiation is only useful if you are concerned that the class could be initialized but you don't want to load the singleton at that point.
using System;
public class Singleton
{
private static Singleton instance;
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
Here comes the challenge part. In multi-threaded environment, lazy instantiation poses challenges to avoid unnecessary object creation. You need to put synchronization blocks which poses unnecessary locking to be done to check for object already created. So it becomes a performance issue in this case.
Refactor-2 : Mutli User and Multi App Simulation
The previous code was working fine in a single user single app environment. No issue at all. Tried to simulate the multi user and multi app environment using the below code.
I created the singleton class as a service and wrote a console client and WPF client, with the service reference.
Console Client
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
ServiceReference1.Service1Client svcClient = new ServiceReference1.Service1Client();
Parallel.For(1,100, j =>
{
Console.WriteLine("Created Time: " + svcClient.getInstanceCreatredTime());
Console.WriteLine("Instance Time:" + DateTime.Now.ToString());
});
}
}
}
These two different client applications were executed with multiple instances. It helps us to simulate the multiple client instances hit the singleton service at the same time.
WPF Client
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnTest_Click(object sender, RoutedEventArgs e)
{
ServiceReference1.Service1Client webClient = new ServiceReference1.Service1Client();
MessageBox.Show(webClient.getMessage());
Debug.Write("----------Start-------------");
Parallel.For(1, 100, ActionDel =>
{
Thread.Sleep(1000);
Console.WriteLine("Created Time: " + webClient.getInstanceCreatredTime());
Console.WriteLine("Instance Time:" + DateTime.Now.ToString());
});
Debug.Write("--------------Finished------------");
}
}
}
Refactor-3 : Problem of Duplicate Instances
You know what happened on Refactor-2 execution. Bang!!!
As the execution result, we got 3-4 instance creation messages. Why?
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
When multiple client instances hit the singleton class creation, there are some execution clock where the above getter might be executed for 3-4 instances. It might be because of the conflict in execution time slice. How do you save it?
Refactor-4 : Thread Safe using Lock
In multi-threaded applications where multiple threads make calls to the methods of a single object, it is necessary that those calls be synchronized.
If code is not synchronized, then one thread might interrupt another thread and the object could be left in an invalid state.
A class whose members are protected from such interruptions is called thread-safe.
using System;
public class Singleton
{
private static Singleton instance;
private Singleton() {}
public static Singleton Instance
{
get
{
private static object syncRoot = new Object();
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
return instance;
}
}
}
This implementation is thread-safe. The thread takes out a lock on a shared object, and then checks whether or not the instance has been created before creating the instance.
This takes care of the memory barrier issue and ensures that only one thread will create an instance (as only one thread can be in that part of the code at a time - by the time the second thread enters it,the first thread will have created the instance, so the expression will evaluate to false).
Unfortunately, performance suffers as a lock is acquired every time the instance is requested.
Refactor-5 : Problem of duplication
Hahaaa.. Still, we got the duplication on multi-user multi-application instances hit at the same time. Why???
It is purely because of local lock instance syncRoot within getter of Singleton class. Similar issue might happen in RF-3 due to the conflict execution cycle. What is the solution?
Refactor-6 : Global lock varaible
Solution is to move the lock variables as the global variable at Singleton class level as below:
using System;
public class Singleton
{
private static Singleton instance;
private static object syncRoot = new Object();
private Singleton() {}
public static Singleton Instance
{
get
{
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
return instance;
}
}
}
Refactor-7 : Double-Check Locking
Cases do exist, however, in which you cannot rely on the common language run time to ensure thread safety, as in the Static Initialization example. In such cases, you must use specific language capabilities to ensure that only one instance of the object is created in the presence of multiple threads. One of the more common solutions is to use the Double-Check Locking [Lea99] idiom to keep separate threads from creating new instances of the singleton at the same time.
This approach ensures that only one instance is created and only when the instance is needed. Also, the variable is declared to be volatile to ensure that assignment to the instance variable completes before the instance variable can be accessed. Lastly, this approach uses a syncRoot instance to lock on, rather than locking on the type itself, to avoid deadlocks.
using System;
public sealed class Singleton
{
private static volatile Singleton instance;
private static object syncRoot = new Object();
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
This double-check locking approach solves the thread concurrency problems while avoiding an exclusive lock in every call to the Instance property method. It also allows you to delay instantiation until the object is first accessed. In practice, an application rarely requires this type of implementation. In most cases, the static initialization approach is sufficient.
Refactor-8 : Static initialization at declaration
One of the reasons Design Patterns avoided static initialization is because the C++ specification left some ambiguity around the initialization order of static variables. Fortunately, the .NET Framework resolves this ambiguity through its handling of variable initialization.
public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
private Singleton(){}
public static Singleton Instance
{
get
{
return instance;
}
}
}
In this strategy, the instance is created the first time any member of the class is referenced. The common language run time takes care of the variable initialization. The class is marked sealed to prevent derivation, which could add instances. In addition, the variable is marked read-only, which means that it can be assigned only during static initialization (which is shown here) or in a class constructor.
Refactor-9 : Solution for Thread and Lazy Init
After the nine refactoring, Singleton comes with better shape for thread safe and lazy instance constraints. Now, it is simple, clean and powerful.
public class SingletonRF9
{
private SingletonRF9() { }
private static class InnerSingletonHolder
{
public static DateTime Instance = DateTime.Now;
}
public static DateTime GetInstance()
{
return InnerSingletonHolder.Instance;
}
}
Refactoring is similar to infinity. It doesn't stop and keep improving. Continuous Improvement! So, this is not the end state. But, this case study gives the feeling of Refactoring and its power.
4. Refactoring Methodologies
Here are some examples of code refactoring; some of these may only apply to certain languages or language types. A longer list can be found in Fowler's Refactoring book and on Fowler's Refactoring Website.
- Techniques that allow for more abstraction
Encapsulate Field – force code to access the field with getter and setter methods
Generalize Type – create more general types to allow for more code sharing
Replace type - checking code with State/Strategy
Replace conditional with polymorphism
- Techniques for breaking code apart into more logical pieces
Extract Method - to turn part of a larger method into a new method. By breaking down code in smaller pieces, it is more easily understandable. This is also applicable to functions.
Extract Class - moves part of the code from an existing class into a new class.
- Techniques for improving names and location of code
Move Method or Move Field – move to a more appropriate Class or source file
Rename Method or Rename Field – changing the name into a new one that better reveals its purpose
Pull Up – in OOPS, move to a super-class
Push Down – in OOPS, move to a subclass
5. Advantages
Refactoring helps you achieve:
- Self-documenting code
For better readability and maintainability, which is pretty much the only kind of code documentation that ever seems to stay current (Extract Method and Introduce Local allow you to create function and variable names that are descriptive enough to rarely need comments). Until you experience readable, self-describing code, you don't know what you're missing
- Fine-grained encapsulation
For easier debugging and code reuse: Extract Method automatically determines the parameters needs in order to create a method from the current selection, and handles them correctly. You then know exactly what external information the selected block requires in order to operate. This can be a great aid in untangling complex code during code reviews or debugging.
- Generalization of existing code
To make it easier to apply existing code to a broader range of problems - as you Extract Method, you can easily replace things like hard-coded constants (perhaps, a connection string, or a table name) with parameters, thus allowing the application of proven code to new contexts.
6. Challenges
Refactoring has been growing in importance and it is now
recognized as a very important part of the software engineering
process. Refactoring tools are getting better.
At the same time, there are few challenges to adapt the Refactoring in project deliverable.
I put them in the below categories:
- Lack of skilled programmers
Refactoring needs the highly experienced and logical thought process for the developers to survey.
In reality, we are in the huge scarcity to have such a type of high calipered programmers in the industry.
Lack of skilled programmers is the major factor to promote the culture of refactoring in software development.
- Cost effective high competition market
In the high competition IT market, cost effectiveness is the key. Apparently, refactor process needs additional effort; but worth for quality factor.
Still, the situation demands to skip this additional process to reduce the cost.
- Missing cultural change
Formalizing and mechanically verifying a realistic refactoring tool for a real-world programming language is a formidable problem that
has not been successfully solved yet. We believe that the key to attacking this problem is modularity, not only with respect to the functional decomposition
of the refactoring engine itself, but also, even more crucially, with respect to the object language.
If the verification of refactoring is to succeed at all, we have to start from a manageable, well-understood core language; if it is to be meaningful,
we need a way to modularity extend this core implementation and its verification all the way to a realistic language
In spite of these challenges, few niche companies in the industries are quite successful in rolling out in their organisation process.
7. Points of Interest
As points of interest to the developers' community, Refactoring is a huge aid in untangling production code without breaking it, and in improving its long-term maintainability.
Given case study to build the robust singleton pattern step by step process, is the suitable example to illustrate the power of refactoring.
History
-
Version 1.0 - Initial Version.
Currently working as IT Solution Architect for Financial Services applications. Out of 18+ years, spent six career years at major IT firms in USA. Basically from C, C++, VC++, C# family, extending to the emerging Big Data and Cloud technology. Loves driving, spending time with friends&family, building my farm house.