Está en la página 1de 9

Post invitado: "Refactoring" por Quique Martnez - MSDN Espaa - Si...

http://blogs.msdn.com/b/esmsdn/archive/2013/08/06/post-invitado-quo...

Post invitado: "Refactoring" por Quique Martnez


esmsdn 6 Aug 2013 2:54 AM

Qu es el refactoring?
La refactorizacin (refactoring) es una tcnica de ingeniera de software para la restructuracin del cdigo fuente. Esto nos permite dejarlo ms claro y fcil de mantener. Bsicamente se puede decir que se trata de modificar la estructura interna del cdigo sin modificar el comportamiento. El proceso de la refactorizacin pasa por pequeos cambios como renombrar variables, simplificar el cdigo ms complicado o borrar lgica duplicada. Se tiene que tener cuidado porque despus de realizar una refactorizacin es posible que alguna parte del cdigo deje de funcionar como lo haca. Es por ello muy recomendable tener una buena cobertura de test, que nos asegurarn que todo sigue funcionando correctamente. Este proceso nos puede llevar desde minutos a meses. Ya que no solo se trata de borrar cdigo duplicado o renombrar variables, tambin se puede hacer una refactorizacin de toda la arquitectura (si es necesario) con lo que implicara realizar cambios en mltiples componentes de nuestra solucin.

Por qu es importante?
Son muchos los motivos para realizar una refactorizacin de nuestro cdigo, a continuacin detallamos los ms comunes. Un cdigo ms compresible y fcil de mantener Facilidad para agregar nueva funcionalidad Mejora en la calidad del cdigo existente A nosotros o nuestros compaeros no nos gusta encontrarnos clases con cientos de lneas, lgica duplicada, cdigo que no se utiliza o variables con nombres que no sabemos a qu se refieren. Todo esto hace nuestro trabajo ms difcil y tedioso. Cuantas veces no hemos pensado en hacer vud contra algn compaero? Bromas aparte tenemos que pensar que el cdigo que estamos creando durante nuestro da a da y que entendemos a la perfeccin en ese momento lo tendr que modificar alguien ms tarde (O nosotros mismos). Horas, das, meses o incluso aos despus. Y en ese momento no se lo estaremos poniendo fcil. Es por ello que es muy importante el crear un cdigo limpio, fcil de comprender y mantener. Todos hemos programado con prisa, durante la noche y con mucha presin y hemos generado lneas y lneas de cdigo. O simplemente estamos en un proyecto que lleva mucho tiempo desarrollndose y la lgica ha crecido tanto que es necesario simplificarla. Ya que cada nueva funcionalidad nos est costando implementarla cada vez ms. Por ello la refactorizacin nos va ayudar en nuestro da a da y va aumentar nuestro rendimiento y el del resto del equipo. Adems de todas estas ventajas, podremos ir viendo como la calidad del cdigo de nuestro desarrollo ha ido mejorando. Ya que al realizar las refactorizaciones vamos a ir encontrado diferentes Code smellsy los iremos corrigiendo, dejando as un cdigo de mayor calidad.

Refactorizando nuestros problemas en nuestro da a da


Algunos de los problemas ms comunes que nos encontramos en nuestro da a da suelen ser los siguientes:

Variables con nombres genricos o imposibles de saber a qu hacen referencia


Muchas veces nos encontramos variables del estilo: MyProperty o simplemente m la primera haciendo referencia a

1 de 9

13/08/2013 04:08 p.m.

Post invitado: "Refactoring" por Quique Martnez - MSDN Espaa - Si...

http://blogs.msdn.com/b/esmsdn/archive/2013/08/06/post-invitado-quo...

una propiedad pero con un nombre muy genrico y la segunda a priori no sabemos para que la utilizamos. Una posible refactorizacin que nos va a ayudar a entender ms el cdigo va a ser renombrarlas. Vamos a intentar que el nombre de las propiedades y variables sean lo ms ajustadas a lo que van guardar. Es decir si queremos guardar los minutos de una hora en una variable no utilicemos m sino minutos. De esta forma a primera vista vamos a poder saber para que la usamos. Ya tenemos la teora veamos ahora la prctica. Si trabajis como nosotros con Visual Studio tenis una serie de herramientas que nos ayudan con la refactorizacin diaria. Veamos como renombrar el nombre de una variable, propiedad o funcin:

Nos permite hacer un renombrado seleccionando la variable en cuestin.

nicamente tenemos que escribir el nuevo nombre y el solo har el renombrado, ahorrando nos un valioso tiempo De esta forma podemos ir dejando ms claro nuestro cdigo ya que si vamos renombrando las variables, funciones y propiedades por nombres que a simple vista nos den ms pistas lo entenderemos mejor nosotros y el resto del equipo.

Cdigo Zombie o que no se utiliza


Otro de los problemas ms comunes que nos encontramos es cdigo comentado o que directamente no se utiliza. Esto hace que tengamos clases con cientos de lneas de cdigo y se nos haga muy pesado el trabajar con ellas. En este caso lo que tenemos que hacer es directamente eliminar todo el cdigo comentado y que no se usa. No

2 de 9

13/08/2013 04:08 p.m.

Post invitado: "Refactoring" por Quique Martnez - MSDN Espaa - Si...

http://blogs.msdn.com/b/esmsdn/archive/2013/08/06/post-invitado-quo...

tengamos miedo, ya que tenemos un repositorio de cdigo fuente. En caso de que no dispongis de uno, recordad que tenis Team Foundation Service, que entre otras muchas funciones tiene la de repositorio de cdigo fuente. Adems tiene una versin gratuita. Ahora ya sabemos que tenemos que borrar todo este cdigo, en el caso del cdigo comentado es sencillo. Veamos como eliminar el cdigo que no se utiliza y solo nos ocupa espacio. En Visual Studio lo tenemos muy sencillo, mirar una clase de ejemplo:

A simple vista y gracias al IDE, s que el mtodo Subtraction no se utiliza ya que tiene 0 referencias y s que el mtodo Sum se utiliza en una ocasin. (Aqu lo vemos a simple vista pero lo normal sera que Sum estuviera en otra clase.) Si pulsamos en esa referencia:

3 de 9

13/08/2013 04:08 p.m.

Post invitado: "Refactoring" por Quique Martnez - MSDN Espaa - Si...

http://blogs.msdn.com/b/esmsdn/archive/2013/08/06/post-invitado-quo...

Podemos ver exactamente donde se est utilizando. Esta herramienta nos va a permitir el poder borrar cdigo que no utilizamos y tener as una clase ms limpia. Tambin nos servir con la propiedades, muchas veces declaramos propiedades que no acabamos utilizando, gracias a esto las podremos detectar a simple vista.

Refactoring to Patterns (patrones de refactorizacin)


Existen muchos patrones que nos ayudan en nuestras refactorizaciones, algunos de ellos los utilizamos a diario sin saber que son patrones como tal. A continuacin veremos un par de ejemplos

Chain Constructors (Constructores encadenados)


Escenario:
Muchas veces al hacer sobrecarga en los constructores de una clase acabamos duplicando cdigo dentro de ellos. Un ejemplo es en la asignacin de variables, al hacer la sobrecarga los constructores no reciben los mismos parmetros pero si hacemos las mismas asignaciones dentro de ellos. Otro ejemplo podra ser cuando llamamos a funciones dentro del constructor para calcular algn dato. Si el clculo lo tenemos que hacer siempre, nos vamos a encontrar esa lgica tantas veces como constructores tengamos. Veamos cmo podemos refactorizar el cdigo en estos casos. Ejemplo: Vamos a utilizar una clase que llamada Book con unas cuantas propiedades.
namespace ChainConstructorsBefore.Model { using System; public class Book { public string Author { get; set; } public string CoAuthor { get; set; } public string ISBN { get; set; } public DateTime PublishDate { get; set; } public string PublishingHouse { get; set; } public double Price { get; set; } public Book(string author, string coAuthor, string isbn, DateTime publishDate, string publishingHouse, double price) { Author = author; CoAuthor = coAuthor; PublishDate = publishDate; PublishingHouse = publishingHouse; ISBN = isbn; Price = price * 1.18 * 3.2; } public Book(string isbn, DateTime publishDate, string publishingHouse, double price) { PublishDate = publishDate; PublishingHouse = publishingHouse; ISBN = isbn; Price = price * 1.18 * 3.2; } public Book(string author, string isbn, DateTime publishDate, string publishingHouse, double price) { Author = author; PublishDate = publishDate; PublishingHouse = publishingHouse; ISBN = isbn; Price = price * 1.18 * 3.2;

4 de 9

13/08/2013 04:08 p.m.

Post invitado: "Refactoring" por Quique Martnez - MSDN Espaa - Si...

http://blogs.msdn.com/b/esmsdn/archive/2013/08/06/post-invitado-quo...

} } }

Como podis ver tenemos propiedades y una serie de constructores sobrecargados. En ninguna ocasin reciben los mismos parmetros (aunque he de decir que me lo he encontrado alguna vez) pero si se repite en alguna ocasin el cdigo de asignacin de Author,PublishDate,ISBN, Price y PublishingHouse. Adems tenemos el clculo del precio repetido en cada constructor. Este es un ejemplo sencillo, s que de primeras podemos pensar no pasa nada por tener las asignaciones repetidas y dems. Pero imaginarlo en vuestro proyecto actual, con muchas clases, ms propiedades y dems Solucin Veamos ahora como refactorizamos este cdigo para que quede ms limpio y entendible. Lo primero que vamos a hacer es extraer el clculo del precio a una funcin, as no tendremos la misma lgica repetida en cada constructor.
private const double BenefitsFactor = 3.2; private const double Tax = 1.18; public double CalculatedPrice(double price) { return price * BenefitsFactor * Tax; }

Ahora, ya tenemos la funcin separada, como podis ver hemos quitado las dos cifras para hacer el clculo y hemos creado 2 constantes. La prctica de dejar nmeros fijados en las funciones es mala. Por eso creamos las constantes. (Magic Numbers). Segundo paso, tenemos que refactorizar la asignacin de las propiedades. Aqu es donde viene la utilizacin del patrn.
public class Book { private const double BenefitsFactor = 3.2; private const double Tax = 1.18; public public public public public public string Author { get; set; } string CoAuthor { get; set; } string ISBN { get; set; } DateTime PublishDate { get; set; } string PublishingHouse { get; set; } double Price { get; set; }

public Book(string author, string coAuthor, string isbn, DateTime publishDate, string publishingHouse, double price) { Author = author; CoAuthor = coAuthor; PublishDate = publishDate; PublishingHouse = publishingHouse; ISBN = isbn; Price = CalculatedPrice(price); } public Book(string isbn, DateTime publishDate, string publishingHouse, double price) : this(null, null, isbn, publishDate, publishingHouse, price) { } public Book(string author, string isbn, DateTime publishDate, string publishingHouse, double price) : this(author, null, isbn, publishDate, publishingHouse, price) { }

5 de 9

13/08/2013 04:08 p.m.

Post invitado: "Refactoring" por Quique Martnez - MSDN Espaa - Si...

http://blogs.msdn.com/b/esmsdn/archive/2013/08/06/post-invitado-quo...

public double CalculatedPrice(double price) { return price * BenefitsFactor * Tax; }

Como podis ver ahora nicamente tenemos las asignaciones y la llamada al clculo del precio en un constructor y seguimos teniendo todas las sobrecargas que hemos credo oportunas.

Compose Method (Crear mtodos)


El segundo patrn para realizar la refactorizacin que vamos a explicar es uno de simplificacin. Muchas veces despus la lgica de nuestro desarrollo crece tanto que cuando tenemos que agregar una nueva funcionalidad se nos hace muy complicado. Este patrn trata sobre la refactorizacin de mtodos, hacindolos ms sencillos y fciles de entender. Este patrn va muy ligado a la S de S.O.L.I.D, que en resumen nos dice que tenemos que crear mtodos que contengan solo una responsabilidad.

Escenario
Imaginaros que tenemos una aplicacin muy simple que agrega nombres a una lista de espera. Para poder agregar estos nombres, tendremos que comprobar antes si la persona ya est en dicha lista. Seguramente a bote pronto, ya lo veis muy claro. Pero pongmonos en el peor de los casos.
using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Threading.Tasks;

namespace ComposeMethodModel { public class Person { public string Name { get; set; } public DateTime Date { get; set; } public bool Add(Person person) { int i = 0; bool flag = false; while (i < SampleData.Persons.Count()) { var toLowerName = person.Name.ToLower(); if (SampleData.Persons[i].Name.ToLower() != toLowerName) { i++; } else { flag = true; i = SampleData.Persons.Count(); } } if (flag != true) { var toLowerName = person.Name.ToLower(); SampleData.Persons.Add(new Person { Name = toLowerName, Date = person.Date }); return true; } return false; } } }

6 de 9

13/08/2013 04:08 p.m.

Post invitado: "Refactoring" por Quique Martnez - MSDN Espaa - Si...

http://blogs.msdn.com/b/esmsdn/archive/2013/08/06/post-invitado-quo...

Este cdigo funciona perfectamente (y no es el ms complicado que hemos visto verdad :P) pero nos tenemos que fijar para saber qu hace. Lo primero que vemos es que realiza muchas funciones: Recorre la lista de personas Compara la persona que vamos a aadir con todas las existentes En caso de que no exista aade la persona a la lista Antes de ver como realizaramos la refactorizacin, veamos que para este proyecto tenemos un par de Test Unitarios que realizan las siguientes comprobaciones del funcionamiento. Aadir si existe: Nos tiene que devolver un false ya que el nombre ya est en la lista. Aadir si no existe: Nos tiene que devolver un true ya que hemos agregado el nombre a la lista.
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using ComposeMethodModel; namespace UnitTestComposeMethod { [TestClass] public class AddTest { [TestMethod] public void AddIfExist() { bool expectedResult = false; Person person = new Person(); var actualResult = person.Add(new Person { Name = "ExistName", Date = DateTime.Now }); Assert.AreEqual<bool>(expectedResult, actualResult); } [TestMethod] public void AddIfNotExist() { bool expectedResult = true; Person person = new Person(); var actualResult = person.Add(new Person { Name = "NotExistName", Date = DateTime.Now }); Assert.AreEqual<bool>(expectedResult, actualResult); } } }

Si ejecutamos los Test con el cdigo actual, veremos que pasan los dos.

Ahora veamos cmo podemos refactorizar la funcin Add. Lo primero que haremos ser extraer la lgica de buscar a una nueva funcin:
using System; using System.Collections.Generic; using System.Linq;

7 de 9

13/08/2013 04:08 p.m.

Post invitado: "Refactoring" por Quique Martnez - MSDN Espaa - Si...

http://blogs.msdn.com/b/esmsdn/archive/2013/08/06/post-invitado-quo...

using System.Text; using System.Threading.Tasks; namespace ComposeMethodModel { public class Person { public string Name { get; set; } public DateTime Date { get; set; } public bool Add(Person person) { int i = 0; bool flag = ExistName(person);

if (flag != true) { var toLowerName = person.Name.ToLower(); SampleData.Persons.Add(new Person { Name = toLowerName, Date = person.Date }); return true; } return false; } private bool ExistName(Person person) { int i = 0; while (i < SampleData.Persons.Count()) { var toLowerName = person.Name.ToLower(); if (SampleData.Persons[i].Name.ToLower() != toLowerName) { i++; } else { return true; } } return false; } } }

Ahora realizaremos la refactorizacin de la funcin ExistName.


private bool ExistName(string name) { return SampleData.Persons.Where(p => p.Name == name).Any(); }

Como habis visto hemos substituido la comparacin de strings dentro del bucle, ahora utilizamos LINQ; Ahora vamos a por la funcin Add.
public bool Add(Person person) { if (!ExistName(person.Name)) { SampleData.Persons.Add(person); return true; } return false; }

Como habis podido ver tambin hemos quitado la lgica de ToLowerCase, ya que no es una buena prctica hacerlo as. Ya tenemos la refactorizacin acabada. En esta ocasin era muy simple, pero quedaros con la idea de simplificar las funciones. Adems recordad, que ahora debemos volver a ejecutar los Test Unitarios y todos deberan pasar en

8 de 9

13/08/2013 04:08 p.m.

Post invitado: "Refactoring" por Quique Martnez - MSDN Espaa - Si...

http://blogs.msdn.com/b/esmsdn/archive/2013/08/06/post-invitado-quo...

verde :D

Conclusiones
Como hemos podido ver durante este artculo, la refactorizacin es muy importante ya que nos va a permitir: Un cdigo ms compresible y fcil de mantener Facilidad para agregar nueva funcionalidad Mejora en la calidad del cdigo existente Existen muchos ms patrones y os invitamos a conocerlos, al final del artculo encontrareis las referencias y la solucin que he utilizado. Son ejemplos muy sencillos para que os hagis una idea de que es la refactorizacin. Adems iris viendo que cada vez tardareis menos en realizar las refactorizaciones ms cotidianas y que el cdigo de vuestras soluciones cada vez tendr una mayor calidad. Ahora solo queda que lo probis en vuestro da a da Happy coding

Referencias
Refactoring to patterns by Joshua Kerievsky (http://www.amazon.com/Refactoring-Patterns-Joshua-Kerievsky /dp/0321213351) Refactoring by Martin Fowler (http://www.amazon.com/gp/product/0201485672?ie=UTF8&tag=martinfowlerc20&linkCode=as2&camp=1789&creative=9325&creativeASIN=0201485672)

Descarga de cdigo
Puedes descargarte el cdigo fuente usado en el post en: http://sdrv.ms/13D7xb4 Quique Martnez @quiqu3

9 de 9

13/08/2013 04:08 p.m.

También podría gustarte