Refactoring Codigo Fuente
Refactoring Codigo Fuente
Refactoring Codigo Fuente
http://blogs.msdn.com/b/esmsdn/archive/2013/08/06/post-invitado-quo...
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.
1 de 9
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:
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.
2 de 9
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
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.
4 de 9
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
http://blogs.msdn.com/b/esmsdn/archive/2013/08/06/post-invitado-quo...
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.
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
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
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; } } }
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
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