refactoring - sinonimo - refactory
Estrategia para la refactorizaciĆ³n a gran escala (9)
Actualmente estoy trabajando en un fragmento de código donde tanto la lógica como el acceso a los datos están presentes en las clases de GUI. Obviamente, me gustaría mejorar en esta situación.
La estructura actual actual es básicamente:
- Gran bola de barro
El objetivo final es lograr una estructura similar a DDD:
- DAL
- Modelo de dominio
- Capa de servicio
- Modelo de presentación
- GUI
Entonces, ¿cómo atacarías el problema?
- Big Bang
- Define la estructura para el estado final y envía el código a su hogar definitivo.
- Divide y conquistaras
- Intenta separar la gran bola de barro en dos partes. Repita hasta que termine ...
- Estrangulamiento
- Estrangular las clases (como se describe en http://martinfowler.com/bliki/StranglerApplication.html )
Comenzar con una arquitectura nueva y limpia y mover las piezas antiguas de código en esta nueva arquitectura pieza por pieza y refactorizarla para adaptarla al nuevo arco sería una buena opción. Creo que un enfoque ascendente cuando mueva las funciones sería bueno.
Depende de si tiene que tener siempre un estado de trabajo, para que pueda corregir errores y desplegar cada vez que sea necesario, entonces Devide y Conquer sería una buena solución. Si puede mantener el código anterior, mientras trabaja en uno nuevo (y tiene la disciplina para aplicar correcciones de errores a ambas bases de código) una reescritura puede ser una mejor solución.
Nunca había oído hablar del término ''Aplicación de Estrangulador'' - me gusta. Siempre que sea posible, este sería siempre un buen enfoque, ciertamente minimiza el riesgo y es bastante pragmático, eliminando el gran edificio pieza por pieza.
Donde eso no funciona en mi experiencia es cuando se necesitan cambios razonablemente significativos de inmediato, cambios que requerirán un poco de refactorización (o una gran cantidad de piratería informática). En esa situación, a menudo descubrí que los cambios que debía hacer estaban en el corazón de la gran bola de lodo y no había otra opción que ensuciarme: incluso lo que debería haber sido mantenimiento estándar o cambios menores de mejora eran simplemente horribles y refactor importante fue la mejor opción.
Para esos casos, elegiría dividir y conquistar; el primer objetivo que siempre aspiro es la capacidad de prueba, una vez que tienes todo el resto es mucho más fácil. De hecho, ese es a menudo uno de los principales impulsores que tengo para refactorizar lejos de la gran bola de lodo: ese tipo de código a menudo es casi imposible de probar, con suerte hay ejemplos de entradas y salidas de IU, pero a veces incluso eso falta .
Así que cuando me enfrento con un código donde todo está agrupado en la UI, generalmente empiezo por factorizar unidades discretas de funcionalidad en clases y métodos, y luego presiono esas partes de código en un dominio o capa de servicio. Hacerlo poco a poco reduce en gran medida las posibilidades de romper algo y facilita la localización del código de corte cuando las cosas van mal.
Ejecute los casos de prueba que tenga disponibles al final de cada cambio y asegúrese de que todavía se encuentre con algún tipo de línea de base.
Si escribes buenas pruebas unitarias sobre la marcha, puedes comenzar a reducir la escala del problema y he descubierto que pronto es práctico adoptar el enfoque de estrangulamiento, con pruebas unitarias decentes o al menos el marco adecuado para permitir la escritura de pruebas unitarias es mucho más práctico reemplazar gradualmente partes de la funcionalidad.
Nunca intente "Big Bang". Casi siempre te golpea en la cara, ya que es una medida desesperada y de alto riesgo cuando todo lo demás ha fallado.
Divide y conquista: Esto funciona bien ... si tu mundo tiene solo dos lados. En el software real, tiene que conquistar tantos frentes al mismo tiempo, que rara vez puede darse el lujo de vivir en una fantasía de blanco y negro.
Creo que he estado usando algo así como "Estrangular" durante la mayor parte de mi carrera profesional: convertir gradualmente el código viejo y malo en un código nuevo y brillante. Aquí está mi receta:
Comienza en alguna parte, en realidad no importa dónde. Escriba algunas pruebas unitarias para ver cómo se comporta realmente el código. Averigüe con qué frecuencia hace lo que cree que hace y con qué frecuencia no lo hace. Use su IDE para refactorizar el código para que pueda probarlo.
Después del primer día, adivina si has comenzado en el lugar correcto para separar a este monstruo. Si es así, continúa. Si no, busca un lugar nuevo y comienza de nuevo.
Ventajas de esta estrategia: funciona en pequeños pasos, por lo que el riesgo puede mantenerse bajo control y si algo se rompe, debe estar en el código en el que estuvo trabajando la semana pasada.
Desventaja: lleva mucho tiempo y te sentirás frustrado porque a menudo, el progreso parecerá tan lento hasta que aparezca el "nudo" y, de repente, todo comienza a caer en su lugar como por arte de magia.
Para mí, depende de la situación.
Si se trata de un proyecto muy pequeño, estaría tentado de volver a escribirlo desde cero ... sin embargo, a menudo no tienes ese lujo.
Si no lo hago, iré por eliminarlo pieza por pieza. Escribía pruebas unitarias para verificar la funcionalidad existente y usar lentamente TDD para transformar el código en un sistema elegante y bien diseñado. Dependiendo de cuánto tiempo va a durar este proceso, probablemente comenzará a parecerse a la aplicación Strangler que mencionó anteriormente.
BigBang es muy arriesgado ya que no tiene una forma fácil de verificar que el sistema actualizado haga lo mismo que el anterior.
Divide y conquista es menos riesgoso que BigBang ... pero si es un sistema lo suficientemente grande, puede terminar siendo tan problemático como BigBang.
Si al refactorizar, te refieres a mejorar el código sin modificar la funcionalidad, comenzaría por crear una línea base de pruebas de regresión automática. Hay muchas herramientas para ayudar con esto. Yo uso TestComlete aunque hay buenas alternativas baratas.
Después de establecer una línea de base para la prueba de regresión, personalmente me gustaría dividir y conquistar, ya que, según mi experiencia, es la que más probabilidades tiene de tener éxito. Una vez que tenga una línea de base de prueba, importa menos qué enfoque elija.
¿Es una reescritura total una opción? En mi experiencia, reescribir desde cero a menudo puede ser más eficiente que tratar de limpiar el desastre existente. Todavía conservas partes del código existente pero en un nuevo contexto. Y lo mismo aplica para la GUI y la base de datos si tiene una. Reescribe desde cero y lleva contigo lo que puedes usar.
Me encontré con "el Método Mikado" que parece prometedor para atacar problemas de esta naturaleza.
http://mikadomethod.wordpress.com/
También se habla sobre el Método Mikado de Øredev 2010.
http://oredev.org/2010/sessions/large-scale-refactorings-using-the-mikado-method
Big Bang / Gran rediseño / reescritura del SW ... o lo que sea que otros nombres no funcionen para un SW vivo. Las razones son:
Aún necesita admitir el SW existente con (probablemente) los mismos recursos que tiene.
Probablemente no tenga los requisitos para volver a escribir. Su código anterior tiene todos los requisitos integrados. Ninguno de sus ingenieros conoce todos los dominios SW y todos los requisitos.
Reescribir llevará tiempo. Al final de este tiempo, encontrará que el SW existente ha cambiado para admitir cosas que se requerían durante este tiempo. su nuevo SW en realidad se separó del original y se necesitará fusión (lo que también llevará tiempo).