Los Techies : Blogs about software and anything tech!

Refactoring Day 27 : Remove God Classes


Often with legacy code bases I will often come across classes that are clear SRP violations. Often these classes will be suffixed with either “Utils” or “Manager”. Sometimes they don’t have this indication and are just classes with multiple grouped pieces of functionality. Another good indicator of a God class is methods grouped together with using statements or comments into seperate roles that this one class is performing.

Over time, these classes become a dumping ground for a method that someone doesn’t have time/want to put in the proper class. The refactoring for situations like these is to break apart the methods into distinct classes that are responsible for specific roles.

   1: public class CustomerService
   2: {
   3:     public decimal CalculateOrderDiscount(IEnumerable<Product> products, Customer customer)
   4:     {
   5:         // do work
   6:     }
   7:  
   8:     public bool CustomerIsValid(Customer customer, Order order)
   9:     {
  10:         // do work
  11:     }
  12:  
  13:     public IEnumerable<string> GatherOrderErrors(IEnumerable<Product> products, Customer customer)
  14:     {
  15:         // do work
  16:     }
  17:  
  18:     public void Register(Customer customer)
  19:     {
  20:         // do work
  21:     }
  22:  
  23:     public void ForgotPassword(Customer customer)
  24:     {
  25:         // do work
  26:     }
  27: }

The refactoring for this is very straight forward. Simply take the related methods and place them in specific classes that match their responsibility. This makes them much finer grained and defined in what they do and make future maintenance much easier. Here is the end result of splitting up the methods above into two distinct classes.

   1: public class CustomerOrderService
   2: {
   3:     public decimal CalculateOrderDiscount(IEnumerable<Product> products, Customer customer)
   4:     {
   5:         // do work
   6:     }
   7:  
   8:     public bool CustomerIsValid(Customer customer, Order order)
   9:     {
  10:         // do work
  11:     }
  12:  
  13:     public IEnumerable<string> GatherOrderErrors(IEnumerable<Product> products, Customer customer)
  14:     {
  15:         // do work
  16:     }
  17: }
  18:  
  19: public class CustomerRegistrationService
  20: {
  21:  
  22:     public void Register(Customer customer)
  23:     {
  24:         // do work
  25:     }
  26:  
  27:     public void ForgotPassword(Customer customer)
  28:     {
  29:         // do work
  30:     }
  31: }

This is part of the 31 Days of Refactoring series. For a full list of Refactorings please see the original introductory post.

Kick It on DotNetKicks.com
Posted Aug 27 2009, 08:17 AM by schambers

Comments

Roxin wrote re: Refactoring Day 27 : Remove God Classes
on 08-27-2009 1:14 PM

Would you also split CustomerOrderService into another 2 classes ? OrderCalculators , CustomerOrderValidation (for the first 2 methods ) - would this be overkill ?

Dave the Ninja wrote re: Refactoring Day 27 : Remove God Classes
on 08-27-2009 8:34 PM

@Roxin

I would split it down further as you mentioned as the calculator and validation IMO have completely separate responsibilities.

David

Lyronne wrote re: Refactoring Day 27 : Remove God Classes
on 08-28-2009 6:29 AM

In this example the refactoring results look similar to a Service Layer (Fowler, POEAA, Service Layer). The difference between this and Service Layer is that service layer delegates to a domain model. I know this example is really about SRP, but can we afford to ignore the possibility of these classes not existing at all. The opportunity exists to connect these operations to the objects they operate on, by enriching Customer, Order, Product etc. with the appropriate operations in these classes, the classes become closely mapped to the domain language and IMO these classes are ambassadors for SRP.

Dave Two wrote re: Refactoring Day 27 : Remove God Classes
on 08-28-2009 9:47 AM

I'm more interested in findging out what calls these service classes.  If this is a "controller" type class, do we now need to maintain two references, or pass two references around instead of one?  Or do we bundle this under a "ServiceManager" that maintains references to all of these sub-services?

Havadis – 1 | Bulutlararas?? wrote Havadis &#8211; 1 | Bulutlararas??
on 08-29-2009 8:49 PM

Pingback from  Havadis – 1 | Bulutlararas??

on 08-31-2009 11:56 AM

Agile/ALT.NET/Software Design A guide into OR/M implementation challenges: The Session Level Cache Build Your Own Data Access Layer: Lazy Loading A guide into OR/M implementation challenges: Laxy Loading Building Your Own Data Access Layer: Executing

张荣华 wrote 31天重构指南之二十七:去除上帝类
on 10-19-2009 4:56 AM

我经常可以在一些遗留代码中见到一些类明确的违反了SRP(Single Responsibility Principle)原则,这些类通常以“Utils”或“Manager”后缀结尾,但有时这些类也没有...

31 Days of Refactoring « Vincent Leung's .NET Tech Clips wrote 31 Days of Refactoring &laquo; Vincent Leung&#039;s .NET Tech Clips
on 10-28-2009 9:28 AM

Pingback from  31 Days of Refactoring « Vincent Leung's .NET Tech Clips

PetterLiu wrote 31 Days of Refactoring
on 11-27-2009 4:02 AM

Refactoring Day 1 : Encapsulate Collection Refactoring Day 2 : Move Method Refactoring Day 3 : Pull ...

PetterLiu wrote 31 Days of Refactoring
on 11-27-2009 4:04 AM

Refactoring Day 1 : Encapsulate Collection Refactoring Day 2 : Move Method Refactoring Day 3 : Pull ...

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

Enter the numbers above:
Copyright Los Techies 2008, 2009. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems