5. Que es? Code smell: Alternative classes with different interfaces Code smell: Un code smell es un indicio de que algo esta mal en alguna parte en el código y que este necesita un refactor para corregir dicho problema.
6. Que es? Code smell: Alternative classes with different interfaces Alternative classes with different interfaces: Si 2 clases son similares o iguales internamente, pero diferentes externamente, hablamos de clases alternativas con una interfaz diferente, y claramente estamos ante un code smell.
7. Que es? Code smell: Alternative classes with different interfaces Que problema nos genera esto? Si las clases similares tienen diferencias en sus interfaces, quien las use, tendrá diferencias en la interacción con cada una de las ellas. En cambio si las clases contaran con una interface común, quienes las usen podrían trabajar con cualquiera de las clases de forma uniforme, lo que significa una importante reducción de código duplicado y de posibles problemas.
10. Extract Sub or Super Class Code smell: Alternative classes with different interfaces
11.
12.
13.
14.
15. Code smell: Alternative classes with different interfaces Como renombrar métodos sin romper todo Para llevar a cabo esta tarea sin destruir nuestro código, o correr riesgos de dejar cosas mal hechas, la metodología a seguir es la siguiente: Volvamos al ejemplo anterior. Supongamos que tenemos 1 clase que maneja las toolbars de nuestra aplicación, también supongamos que tenemos 2 posibles toolbars a mostrar, dependiendo de algún factor externo (diferentes niveles de usuarios, etc).
16.
17. Para corregir esto podemos empezar por hacer que los métodos de una de las clases sean igual a los de la otra, pero usando métodos nuevos que sean llamados por los viejos. Como renombrar métodos sin romper todo Code smell: Alternative classes with different interfaces
18. Como renombrar métodos sin romper todo Por ejemplo, creamos en ActionsToolbarForUser un método nuevo, poniéndole como nombre el que deseamos que quede. Movemos todo el código del método viejo al nuevo, y hacemos una llamada desde ahí al método nuevo. setButtonSelected = function() { // código que había antes en setSelected } setSelected = function() { setButtonSelected(); } Code smell: Alternative classes with different interfaces
19. Como renombrar métodos sin romper todo Luego hacemos lo mismo en la otra clase: setButtonSelected = function() { // código que había antes en setButtonSel } setButtonSel = function() { setButtonSelected(); } Code smell: Alternative classes with different interfaces
20. Como renombrar métodos sin romper todo Ahora cambiamos en la clase que instancia estas otras dos: if (algo) { clase1.setButtonSel(); } else { clase2.setSelected(); } por: claseHija.setButtonSelected(); Code smell: Alternative classes with different interfaces
21. Como renombrar métodos sin romper todo Por último eliminamos los métodos de las clases hijas que ya no usaremos mas: setButtonSel y setSelected Code smell: Alternative classes with different interfaces
22. Add or remove parameters Como agregado a “Rename method” podemos hablar de agregar o remover parámetros, usando la mismo metodología que comentamos anteriormente. Cabe destacar que cuando necesitemos mas información en un método, y para ello queramos agregar un parámetro, siempre debemos buscar si no hay otra alternativa a esto, ya que agregar parametro nunca es conveniente, por que hace que la clase mas difícil de utilizar, ya que debemos conocer mas sobre esta por que deberemos recordar los parámetros que necesitan sus métodos. Code smell: Alternative classes with different interfaces
23. Add or remove parameters Si no tenemos mas alternativa que agregar un parámetro, deberemos al igual que al momento de renombrar un método, crear un método nuevo que reciba el nuevo parámetro, que este sea llamado desde el método viejo, agregando el nuevo parámetro en la llamada, y luego desde quien utilice a clase llamar al nuevo método con el parámetro agregado. En el caso de remover un parámetro la metodología también es la misma. Code smell: Alternative classes with different interfaces
24. Move methods Cuando encontramos un método que es usado en mas por otra clase que por la clase donde esta declarado, o internamente usa demasiadas propiedades o llamadas a otros métodos de una clase externa, es evidente que estamos ante la necesidad de mover este método a dicha clase externa. Utilizar esta metodología hace que nuestras clases terminen siendo mas simples, y tengan menor posibilidad de fallas, ya que tienen menos responsabilidades. Muchas veces es difícil tomar la decisión de cambiar de lugar un método, y normalmente, cuando la decisión es difícil de tomar, significa que en esos momentos no es tan importante el mover ese método. Code smell: Alternative classes with different interfaces
25. Move methods En este caso debemos realizar algo parecido a lo que ya habíamos visto. Para dar el ejemplo en este caso voy a usar algo que hice hace 2 días en el iATS. Code smell: Alternative classes with different interfaces
26. Ejemplo dentro del iATS Tenemos una clase AttachmentList y una clase AttachmentRecord. El problema con el que me encontré es que había en AttachmentList un link para agregar un nuevo attachment que cuando hacíamos click y elegíamos la opción “From Record” este inmediatamente instanciaba un AttachmentRecord, lo ponía en la UI, pero vacío, y era esta clase la que se encargaba de abrir el popup para elegir cual era el attachment a elegir. Una vez seleccionado el attchment, se actualizaba el link agregado en la UI poniéndole los datos del attachment agregado. Code smell: Alternative classes with different interfaces
27. Solución al ejemplo Esto provocaba que si el attachment elegido por alguna razón necesitaba ser mostrado/usado de otra forma a la normal, termine siendo muy fea su implementación, ya que debía agregar una condición para ver que attachment había sido elegido y en base a eso o solo actualizábamos el link, o había que redibujar toda la UI de ese widget. La solución era mover todo el código de selección del attachment afuera de la clase AttachmentRecord, y que esta funcionalidad sea implementada por AttachmentList, y que una vez que se seleccionaba el attachment, recién hay se instancie la clase hija, solo que esta vez, instanciábamos AttachmentRecord para los attachments normales, o una clase nueva, para el caso especial que se había presentado. Code smell: Alternative classes with different interfaces
28. Solución al ejemplo Para realizar este cambio de forma correcta, se debe como primera instancia, controlar que métodos son los que necesitan ser movidos, ver quien mas puede estar usándolos de forma externa y por ultimo, ver que cosas de la propia clase donde estaban declarados usaban y que al moverlos no íbamos a tener disponibles en forma directa. En ese análisis encontré que nadie mas usaba esos métodos de forma externa, ni que tampoco usaban propiedades o otros métodos de la clase donde estaba declarados, por lo que estos puntos no eran un problema que me traben o compliquen en el momento de mover el/los métodos. Code smell: Alternative classes with different interfaces
29. Solución al ejemplo También vi que los métodos a mover eran 3, el que abría el popup en cuestión, y 2 callers que eran usados al elegir un attachment, o al cancelar y cerrar el popup. Una vez terminado ese análisis es hora de empezar a mover los métodos. Como primera medida, se declaran los 3 nuevos métodos en la clase donde se van a poner, acomodando si es necesario los nombres para que concuerden con su nuevo entorno. Code smell: Alternative classes with different interfaces
30. Solución al ejemplo Luego copiamos todo el código de los métodos de la clase hija a la clase que los va a recibir, y acomodamos las llamadas a otros métodos, o uso de propiedades según sea necesario para que funcionen en la nueva clase. Una vez hecho esto podemos hacer que la clase que recibió los nuevos métodos haga uso de estos, y que la clase que aun los tiene (pero que va a dejar de tenerlos) deje de usarlos. Cuando vemos que esta todo ok a este punto, podemos eliminar de la clase original los métodos que copiamos en la clase externa, así como todo lo relacionado a su uso (calls y properties). Code smell: Alternative classes with different interfaces
33. Extract super or sub classes Extraer super classes o sub classes, es a mi parecer la mejor forma de hacer limpieza y mejora del código. Si bien de las 3 metodologías que hablamos en esta charla podría ser la que mas trabajo nos de, creo que es la que mejor resultado nos aporta. Usar esta metodología nos sirve cuando 2 o mas clases cuentan con funcionalidades iguales o similares, y que por ser parte de diferentes clases el código esta duplicado, además de que las clases son mas grandes (cantidad de lineas de código), tienen mayores responsabilidades/funcionalidades por lo que son mas propensas a fallos, que como venimos hablando, es lo que siempre trataremos de evitar. Code smell: Alternative classes with different interfaces
34. Extract super or sub classes Extract super class: Vamos a extraer parte del código de 2 o mas clases como una super class, cuando estas hacen cosas similares de una forma similar. Extract sub classes: Vamos a extraer parte del código de 1 o mas clases como una sub class, cuando estas hacen cosas similares, pero de una forma diferente, o cuando consideramos que una clases esta haciendo demasiadas cosas y estas podrían ser hechas por 2 o mas clases. Code smell: Alternative classes with different interfaces
35. Extract super class Supongamos que tenemos 2 clases: SingleLineInput y MultiLineInput. Ambas clases comparten parte de su funcionamiento, ya que tenemos muchos métodos que son iguales para ambas, como por ejemplo, getValue, setValue, show, hide, setDisable, etc. Si tenemos implementado cada uno de estos métodos en las 2 clases, tendremos no solo un montón de código duplicado, si no que ambas clases son mas difíciles de entender, son mas propensas a fallas, y además el día que necesitemos cambiar o agregar algo, deberemos hacer el doble de trabajo. Code smell: Alternative classes with different interfaces
36. Extract super class En este caso podemos extraer de estas 2 clases, 1 clase que se encargue de hacer todo lo que es común a las 2 (los métodos que mencionamos mas arriba). Podríamos por ejemplo, crear una nueva clase que tenga los métodos setValue, getValue, etc, y que las otras 2 hereden de esta, y solo tengan declarados los métodos que son específicos para cada una. Code smell: Alternative classes with different interfaces
37. Como hacer la separacion de la clase Primero debemos crear la nueva clase en blanco y hacer que las clases que tenemos actualmente hereden de esta. Una vez hecho esto deberemos ir viendo en las clases que estamos refactoreando cuales son los métodos que comparten funcionalidad, para ir pasándolos a la clase nueva. Code smell: Alternative classes with different interfaces
38. Como hacer la separacion de la clase En este punto podemos si los métodos que vamos a mover tienen diferentes nombres usar la metodología que vimos al principio “Rename classes”. (osea.. primero las renombramos, después las movemos). Tenemos que fijarnos los métodos que vamos a dejar en la clases que heredan que tengan el mismo nombre, para lo que volveremos a usar “Rename methods” Code smell: Alternative classes with different interfaces
39. Como hacer la separacion de la clase Una vez que tenemos esto hecho, podemos controlar los métodos que hacen cosas similares que quedaron en las clases que heredan, para ver si tienen código que puedan compartir, en este caso, pondremos ese código en un método separado en la clase padre, y que los métodos que quedan en las clases que heredan lo llamen. Code smell: Alternative classes with different interfaces
40. Extract sub class Cuando 1 o mas clases tienen demasiadas lineas de código, o tienen muchas funcionalidades, es seguro que debemos extraer parte de ese código como una sub clase. Por ejemplo supongamos que tenemos una clase ViewContactInfo, y que la usamos para mostrar los datos de contacto de una entidad de nuestra aplicación. Code smell: Alternative classes with different interfaces
41. Extract sub class Esta clase podría tener un montón de código extra, ya que debe conocer como mostrar los diferentes datos según el tipo de contacto que es.. Phone, Email, Website, etc. Nosotros podríamos extraer como se muestra cada ítem en particular en una clase diferente, y así hacer que cada una solo tenga una responsabilidad, y poco código. Code smell: Alternative classes with different interfaces
42. Como extraer las sub clases Para llevar a cabo esto, teniendo como ejemplo lo que comentamos sobre una clase ViewContactInfo, primero deberemos, analizar que partes de la clase, podemos separar, teniendo en cuenta que su funcionalidad, no sea especifica de la clase padre, si no que sea un pedasito especifico de esta. Code smell: Alternative classes with different interfaces
43. Como extraer las sub clases Esto significa que si un metodo trabaja sobre todos los items a mostrar por ejemplo, sin importar de que tipo es, ese método es de la clase padre, y no podremos sacarlo en una clase nueva. En cambio si tenemos un método que solo tiene código para ver como se muestra un phone, en ese caso podremos sacarlo en una nueva subClase llamada por ejemplo PhoneContactInfoItem. La clase ViewContactInfo, deberá implementar internamente las nuevas subclases que creemos. Code smell: Alternative classes with different interfaces
50. Tags Manager Code smell: Alternative classes with different interfaces
51. Advanced searches En los advance search en varios caso se podría usar “Extract Sub Class”, ya que tenemos casos por ejemplo de clases que tienen métodos: updateLocation1, updateLocation2, updateLocation3 Code smell: Alternative classes with different interfaces
52. Result Items de Search Page Acá tenemos varias veces ifs grandes controlando de que tipo es el ítem. Nosotros podríamos Extraer una Clase nueva que se encargue de instanciar el tipo de ítem Code smell: Alternative classes with different interfaces
53. Inputs del DOM e inputs nuestros Todavía quedan algunos inputs del DOM en la app, esto significa que nuestra app debe conocer las 2 interfaces .value y .getValue. Acá la solución es eliminar por completo el uso de inputs del DOM y en todos los casos usar de los nuestros para tener una sola interfaz de comunicación posible. Code smell: Alternative classes with different interfaces
54. SendEmail and MailSender EmailSender y MailSender son para lo mismo, pero tienen interfaces diferentes, acá hay que eliminar MailSender que es el mas incompleto y usar siempre el otro. Code smell: Alternative classes with different interfaces
55. Sistema de Tests Sistema de Tests, tenemos diferentes tipos de tests y sus interfaces no son iguales (Test de UI, Unit Test de UI, Unit Test de PHP). Mi conocimiento es demasiado básico en esta parte, y además el problema es muy grande, por lo que no podría nombrar así nomas una solución, solo nombro el problema y la solución la podemos charlar entre todos. Code smell: Alternative classes with different interfaces
56. Tag Manager El TagManager funciona tal cual lo haría un Datasource, por ende lo que hay que hacer es usar un Datasource en su lugar. Code smell: Alternative classes with different interfaces