Buenas,

hace unos días hubo un webcast donde los amigos de JetBrains comentaron las novedades de ReSharper 7. Son 55 minutos bastante interesantes, y entre las cosas que mostraron hoy me acordé de una que me vino al pelo. Un caso de refactoring donde te encuentras con una clase que tiene demasiado contenido y responsabilidades y te toca, empezar a separar por partes.

En un ejemplo un poco parecido al que se muestra al webcast, y bastante más parecido a lo que estuve modificando recien, partimos de una clase que de solo verla nos hace mal a los ojos.

   1: namespace ElBruno.Refactoring

   2: {

   3:     public class ComplexClass

   4:     {

   5:         public int SimpleProperty1 { get; set; }

   6:         public int SimpleProperty2 { get; set; }

   7:         public void SimpleStuff1()

   8:         {

   9:             SimpleProperty2 = 2;

  10:         }

  11:         public int SimpleStuff2()

  12:         {

  13:             return SimpleProperty1 + SimpleProperty2;

  14:         }

  15:         public int ComplexProperty1 { get; set; }

  16:         public int ComplexProperty2 { get; set; }

  17:         public void ComplexStuff1()

  18:         {

  19:             ComplexProperty2 = 2;

  20:         }

  21:         public int ComplexStuff2()

  22:         {

  23:             return ComplexProperty1 + ComplexProperty2;

  24:         }

  25:  

  26:     }

  27: }

Tip: Esto popularmente se denomina Code Smell. Dale una vuelta a la definición porque es más popular de lo que crees. Si nunca has sentido esa sensación o bien vives encerrado en una burbuja y no sé que haces leyendo este blog o tu nivel de empatia está a la altura de Frodo.

Pues bien, a simple vista vemos que tenemos mezcladas las responsabilidades de Complex y Simple en la misma clase, asi que toca “separarlas”. Sobre la clase presionamos CTRL + SHIT + R y desplegamos el menú de refactoring.

image

Seleccionamos la opción “Extract Class” y podremos ver un formulario para definir que elementos de la clase compleja queremos pasar a otra clase, en este caso a una llamada SimpleClass. Cuando vamos seleccionando los elementos que queremos mover, vemos que además nos muestra las dependencias entre ellos y nos sugiere los que también deberíamos mover a la nueva clase.

image

Una vez terminado el refactoring, nos podemos encontrar con 2 clases bastantes limpias y el código ya huele un poco mejor.

Disclaimer: he puesto todo en un único archivo para poder mostrar el ejemplo, no me maten.

   1: namespace ElBruno.Refactoring

   2: {

   3:     public class SimpleClass

   4:     {

   5:         public int SimpleProperty1 { get; set; }

   6:         public int SimpleProperty2 { get; set; }

   7:  

   8:         public void SimpleStuff1()

   9:         {

  10:             SimpleProperty2 = 2;

  11:         }

  12:  

  13:         public int SimpleStuff2()

  14:         {

  15:             return SimpleProperty1 + SimpleProperty2;

  16:         }

  17:     }

  18:  

  19:     public class ComplexClass

  20:     {

  21:         private readonly SimpleClass _simpleClass = new SimpleClass();

  22:  

  23:         public int ComplexProperty1 { get; set; }

  24:         public int ComplexProperty2 { get; set; }

  25:         public void ComplexStuff1()

  26:         {

  27:             ComplexProperty2 = 2;

  28:         }

  29:         public int ComplexStuff2()

  30:         {

  31:             return ComplexProperty1 + ComplexProperty2;

  32:         }

  33:  

  34:     }

  35: }

Pero … No siempre todo es tan simple

Ahora bien, el ejemplo anterior nos gusta y mucho, pero en la vida real no todo es tan simple. Aquellas personas que no piensan en su bienestar físico por lo general hacen crecer mucho las clases, pero además generan relaciones y dependencias entre los elementos de la misma clase de manera que pensar en cortarles los dedos suele ser lo primero que se te ocurre cuando ves algo así (También te acuerdas de sus madres, de sus padres y en casos muy extremos llegas a acordarte de su abuela. Para este último caso recomiendo tirar el código y hacerlo de nuevo desde cero).

   1: namespace ElBruno.Refactoring

   2: {

   3:     public class ComplexClass

   4:     {

   5:         public int SimpleProperty1 { get; set; }

   6:         public int SimpleProperty2 { get; set; }

   7:         public void SimpleStuff1()

   8:         {

   9:             SimpleProperty2 = 2;

  10:         }

  11:         public int SimpleStuff2()

  12:         {

  13:             return SimpleProperty1 + SimpleProperty2 + ComplexProperty1;

  14:         }

  15:         public int ComplexProperty1 { get; set; }

  16:         public int ComplexProperty2 { get; set; }

  17:         public void ComplexStuff1()

  18:         {

  19:             ComplexProperty2 = 2;

  20:         }

  21:         public int ComplexStuff2()

  22:         {

  23:             return ComplexProperty1 + ComplexProperty2 + SimpleProperty1;

  24:         }

  25:     }

  26: }

En el caso anterior, desde la función SimpleStuff2() se utilizand propiedades de Complex y algo parecido desde la función ComplexStuff2(). ¿Qué solució nos da ReSharper para estos casos? Pues lo que hace, es crear un field privado del tipo relacionado y con el mismo, se solucionan estas dependencias. Por ejemplo:

   1: namespace ElBruno.Refactoring

   2: {

   3:     public class SimpleClass

   4:     {

   5:         private ComplexClass _complexClass;

   6:  

   7:         public SimpleClass(ComplexClass complexClass)

   8:         {

   9:             _complexClass = complexClass;

  10:         }

  11:  

  12:         public int SimpleProperty1 { get; set; }

  13:         public int SimpleProperty2 { get; set; }

  14:  

  15:         public void SimpleStuff1()

  16:         {

  17:             SimpleProperty2 = 2;

  18:         }

  19:  

  20:         public int SimpleStuff2()

  21:         {

  22:             return SimpleProperty1 + SimpleProperty2 + _complexClass.ComplexProperty1;

  23:         }

  24:     }

  25:  

  26:     public class ComplexClass

  27:     {

  28:         private readonly SimpleClass _simpleClass;

  29:  

  30:         public ComplexClass()

  31:         {

  32:             _simpleClass = new SimpleClass(this);

  33:         }

  34:  

  35:         public int ComplexProperty1 { get; set; }

  36:         public int ComplexProperty2 { get; set; }

  37:         public void ComplexStuff1()

  38:         {

  39:             ComplexProperty2 = 2;

  40:         }

  41:         public int ComplexStuff2()

  42:         {

  43:             return ComplexProperty1 + ComplexProperty2 + _simpleClass.SimpleProperty1;

  44:         }

  45:     }

  46: }

Lo más probable es que en un caso como esto, haya que separar en un 3er nivel las responsabilidades de las clases. ReSharper ya nos ha dado una gran ayuda ahora toca pasar a otra herramienta que usamos poco y que se conoce como la “sesera” o la mente … Open-mouthed smile

Saludos @ La Finca

El Bruno

image image image

Leave a comment

Discover more from El Bruno

Subscribe now to keep reading and get access to the full archive.

Continue reading