While working with legacy applications and inherently dirty code you have to find creative ways to make things better. Rewriting / major re-factoring are usually not an option as team does not get enough time to do even basic housekeeping, what do you do then?
I have seen sphagetti code way too many times in my life not to call it an anti pattern. One of the main reasons for sphagetti code is allowing any object in the codebase to talk to any other object. In addition it comes hand in hand with usage of global/static scope and leaking information between application layers.
I recently realised that i have been applying the same pattern for a while now. The pattern i propose is an effort to cluster ugliness and relief rest of the code-base from exploding dependencies.
Overview of the common problem
In PHP applications you would often see things that cause in-comprehensive dependencies between components: super globals used across different layers, cookies and/or headers being set in random places, session access at will, static method calls, static variables, registry anti-pattern usage, global variables and abuse of associative arrays. In such application it is hard to introduce clean code as it may have to depend on too many "dirty" things for it to be really clean and testable.
What you would usually aim for, is to define clear responsibility of each class and try to put them together like a puzzle where every piece fits naturally in its place. You would try to define a clean and simple interfaces and a clear input/output contracts. Then your classes will become easy to unit test and understand.
But what do you do if you need to access all this dirty code? how do you access config, session, static calls and all this ugliness without polluting your nice new code-base? How do you refactor existing code to get rid of the dirty bits?
The sacrifice object A.K.A. The Christ Class
What I have been doing for a while is to decide nominate a sacrifice class and make it suffer for all the other classes to be able to live happily.
It would usually be a factory class as factory is a nice way to encapsulate complexity of creation of multiple objects and aggregation of their dependencies from all nasty corners of our app. Then instead of coupling all my new code with static methods, global scope or untestable functions i would make my sacrifice's responsibility to deal with ugliness and return an instance of a clean interface. My component classes as well as the client code of my component will not have to be coupled with dirtiness any more.
I would usually be able to make my component more user-friendly as it's clients would only need to know how to obtain instance of the factory but they would not have to be coupled with the "dirty" areas of the application any more. On the other hand i would make all my internal classes testable and clean as they would get dependencies via constructor injection. They would just get instances of some clean interfaces or some value objects as parameters and they would not have to know how these values/instances were obtained. For them its just a value not a cookie dependency which is usually much better.
Example diagram before the sacrifice
Before the sacrifice you may see code like on the diagram below. Main features are extensive coupling, no interfaces, dependencies on dirty code throughout the component and potentially through it's clients. Exposure of all the details how component is built and what has to be done to obtain an instance of it.
Example diagram after the sacrifice
After the sacrifice is made code becomes a bit more structured. Internally component classes are testable and do not depend on dirty stuff. Clients do not know any more how component is built as they obtain instances of interfaces from factory. Factory becomes a guardian of the component in a way to limit coupling.
Result of the re-factoring
There are a few benefits of this approach:
- Your code-base becomes less coupled as you begin to use interfaces and clean contracts internally within your components.
- Client code of your components becomes simpler and cleaner as it does not have to be aware of all the complexity of dependency aggregation.
- Dirty stuff gets clustered and in stead of searching across 100 classes for static calls you search only over 10 classes. The less occurances you have the higher change that one day you will be able to completely clean it up and re-factor the last dirty bit.
Abusing the sacrifice to buy your Gods' love
It is worth to mention that this can be a dangerous pattern. I have been using it for a few years now every now and then and i think it is quite successful if applied with care. Over time it helps to make code simpler and more testable but there is a risk of not cleaning things that could be cleaned. There is a risk of forgetting how things should be done in the first place.
I would not recommend this pattern as a way to go for everything you do. You want to encapsulate and clean-up your code over time. Unfortunately in difficult projects it may be your only way to create some first pockets of resistance ;-)
Leave a comment and let me know what do you think.
About the author
Hi, my name is Artur Ejsmont,
welcome to my blog. I am a passionate software engineer living in Sydney and working for Yahoo!
If you are into technology, you can order my book Web Scalability for Startup Engineers on Amazon. I would love to hear what are your thoughts so please feel free to drop me a line or leave a comment.