[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Refactoring / Marker methods



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hola,

La aplicación de patrones de diseño sobre código preexistente conlleva la 
práctica comúnmente denominada "refactoring" [1].
Brevemente, se puede analizar como sigue:
- -Como todo cambio, puede introducir errores no presentes anteriormente en el 
código,
- -permite reestructurar la complejidad, de forma que la solución sea más 
fácilmente inteligible por parte del desarrollador (menor complejidad 
implicaría una mayor probabilidad de que una persona sea capaz de mantenerlo 
en un tiempo menor).
- -puede o puede no derivar en una mayor eficiencia del código.
- -se compone básicamente de modificaciones *internas*, es decir, no visibles 
externamente.
- -implica un análisis de las deficiencias del código preexistente y sus 
posibles mejoras.
- -puede afectar únicamente a hacer más explícita la intención de cada una de 
las partes del código.

En principio, es habitual que como consecuencia de un refactoring se realice 
una reestructuración a nivel de clase. Normalmente, la aplicación de un 
patrón de diseño se decide a un nivel de análisis más alto, ya que el propio 
diseño se ve afectado: nuevas entidades, nuevas responsabilidades, nuevas 
relaciones, roles, etc. Por ese motivo la utilización a posteriori de un 
patrón suele conllevar una serie de refactorings, dependiendo de lo fácil que 
sea adaptar el código existente.

Sobre esta premisa, quería comentar la posibilidad de que estemos pasando por 
alto algo intrínseco al desarrollo software: la evolución del código. La 
gestión de recursos de un proyecto es complicada, y da la impresión que la 
única arma para conseguir una gestión eficaz es la fuerza bruta: recopilar 
datos de tiempos, tamaños, número de clases, etc., tratar de analizar esos 
datos estadísticamente con el fin de encontrar correlaciones que permitan 
realizar estimaciones, por burdas que éstas resulten ser. A distintos 
niveles , esto es lo que propone Humphrey [2] con PSP/TSP [3].
Sin embargo, en un proceso de refactoring, motivado por la intención de 
mejorar en cierto sentido código preexistente, podría dar lugar a medidas 
confusas: podría introducir algún error, no alterar el tamaño del código, y 
obviamente lleva tiempo. Medidas como tamaño, tiempo y errores no 
proporcionan información sobre cambios debidos a refactorings ni la 
implementación de patrones. Sin embargo, si estos cambios fueran 
identificados adecuadamente, sí debería poder medirse *por qué* es 
aconsejable utilizar patrones, incluso idealmente el tiempo a partir del cual 
se recupera la inversión de realizarlos.

A grandes rasgos, un proceso más o menos habitual de refactoring, partiendo de 
código preexistente, conlleva inicialmente los siguientes pasos:

big service -> mediator + service providers
- -> mediator + (service guards + unit services)
- ->     (data provisioning + stateless mediator)
      + (service locators + (service guards + unit service providers))

Cada transformación implica un proceso de refactoring, incluyendo una división 
de responsabilidades (estilo GRASP[4]).
Como resultado global de la eliminación del anti-patrón inicial, se obtiene un 
incremento en general del número de métodos, en su mayoría sobrecargados, 
principalmente porque los refactorings suelen mantener compatibilidad hacia 
atrás para acotar los límites de los cambios, y por tanto muchos métodos 
(service guards, data provisioning, service locators) actúan de proxy de la 
lógica de negocio propiamente dicha. Dichos métodos difieren del resto en 
distintos aspectos:
- -La lógica que incluyen es muy reducida, con lo que las pruebas unitarias son 
menos relevantes (aunque por supuesto útiles si se dispone de 
implementaciones mock (*) de los unit service providers).
- -Su finalidad está encubierta, al tratarse de equivalentes proxy a nivel de 
método.
- -Mantienen una relación diferente con los unit service providers que con el 
resto, en cardinalidad (siempre 1-1) y en visibilidad. Esencialmente, los 
unit service providers deberían ser sólo visibles a sus service guards. El 
conjunto sería visible directamente o bien a través del service locator 
correspondiente (en cuyo caso tal conjunto sería una entidad nueva originada 
como consecuencia del refactoring).

Una forma declarativa de asociar semántica al código es utilizando el patrón 
Marker, que no introduce ningún contrato nuevo, y permite indicar 
connotaciones y responsabilidades asociadas a la clase.
A un nivel inferior al de clase no disponemos de esta posibilidad, y sería 
necesario un soporte mejor para resaltar más claramente la distinta 
naturaleza de los métodos.

Aunque hay propuestas interesantes a la programación orientada a objetos, como 
la orientada a aspectos, lamentablemente no parece haber avances 
significativos en lo relativo al análisis de la semántica del código asociada 
fundamentalmente a la evolución del mismo. Posiblemente se podrían utilizar 
las extensiones para soportar metadatos mediante anotaciones, aunque no he 
llegado a utilizarlas. 

La problemática expuesta es incluso más díficil de solucionar con los medios 
de los que disponemos actualmente, ya que ni siquiera la opción de urgencia 
de indicar la naturaleza del método mediante documentación es aceptable en un 
caso general. La razón es que habitualmente la documentación más fiable es la 
que está en sincronía con el código, y ésta, por su naturaleza unitaria, 
suele ceñirse en debe describir el API, su interfaz externa, y no los 
detalles de la implementación. Sin embargo, son los propios métodos proxy 
descritos los que son visibles externamente, y documentar el propósito de 
dicho método haría visibles detalles que por otro lado nos hemos molestado en 
ocultar.

Un saludo,
Jose.

(*) En este caso, serían Mock parciales, ya que sólo suplantarían determinados 
métodos, no todos.

[1] www.refactoring.com
[2] http://www.sei.cmu.edu/tsp/watts-bio.html
[3] http://www.sei.cmu.edu/tsp/. Un link interesante, que compara TSP con 
metodologías ágiles, es http://c2.com/cgi/wiki?AgileAndTspDiscussion
[4] 
http://www.clickblocks.org/patterns1/pattern_synopses2.htm#GRASP%20Patterns
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)

iD8DBQFA6ZLjCAvt6RF8M0cRAh3SAJ42KUT0/EYrOgs2oT7Mvya+gAkgHgCguHur
IOhTyodbLINSRV7Nb4d8wvM=
=XaK3
-----END PGP SIGNATURE-----