¿Cómo evitar los métodos de pegamento gigante?


21

En mi trabajo actual, me han encomendado la tarea de limpiar el código antiguo varias veces. A menudo, el código es un laberinto y los datos detrás de él están aún más enredados. Me encuentro combinando cosas en métodos agradables, limpios y modulares. Cada método hace una cosa y lo hace bien. Ahí es cuando las cosas comienzan a ir hacia el sur ...

Invariablemente, termino con una API limpia y no hay una forma real de vincularlo todo. La solución ha sido escribir un gran método de "pegamento" feo (generalmente lleno de declaraciones condicionales) que eventualmente llama a todos mis métodos "limpios".

El método de pegado generalmente termina siendo una versión concisa de la maraña de código / datos que estaba tratando de limpiar. Generalmente es más legible, pero sigue siendo molesto.

¿Cómo puedo evitar tales métodos? ¿Es este un síntoma de los datos enredados o un reflejo de algo que estoy haciendo mal?


3
Las API están destinadas a ser utilizadas. A partir del lío enredado que creó, creó una API y luego la volvió a enredar. Tal vez sea solo el requisito comercial. Pero agregaste valor porque alguien más puede venir y hacer que otra cola funcione fácilmente usando tu API. No es necesario retorcerse las manos ...
Aditya MP

1
¿Estamos hablando de objetos aquí o simplemente de funciones por todo el lugar?
Erik Reppen

3
No creo que esto sea un duplicado de esa pregunta, estoy hablando un poco más en general (y en una escala mayor que una sola función).
cmhobbs

1
erik: estoy hablando de objetos y métodos aquí. Tomé un par de problemas condicionales y los convertí en API. El problema surge cuando es hora de llamar a la API. Sin embargo, la primera respuesta aquí puede ser exactamente lo que estoy buscando.
cmhobbs

2
¿Cómo es eso un duplicado?
MattDavey

Respuestas:


12

Te daré nuestra experiencia refactorizando LedgerSMB. Tomamos la decisión de hacer las cosas de manera diferente desde el principio y todavía estamos haciendo exactamente lo que usted describe, pero sin muchos métodos de pegamento (tenemos algunos métodos de pegamento por cierto, pero no muchos).

La vida con dos bases de código

LedgerSMB ha sobrevivido con dos bases de código durante aproximadamente 5 años y pasarán varias más antes de que se elimine la antigua base de código. La antigua base de código es un verdadero horror para la vista. Mal diseño de base de datos, Perl construye como IS->some_func(\%$some_object);junto con el código que muestra exactamente por qué a veces se usa la metáfora del espagueti (rutas de ejecución que serpentean entre módulos y hacia atrás, y entre idiomas, sin rima ni razón). La nueva base de código evita esto moviendo las consultas db a los procedimientos almacenados, teniendo un marco más limpio para el manejo de solicitudes y mucho más.

Lo primero que decidimos hacer fue tratar de refactorizar módulo por módulo. Esto significa mover toda la funcionalidad de un área específica a un nuevo módulo y luego conectar el código antiguo al nuevo módulo. Si la nueva API está limpia, esto no es gran cosa. Si la nueva API no es complicada, es una invitación a trabajar un poco más en la nueva API ...

Lo segundo es que hay muchas ocasiones en que el nuevo código tiene que acceder a la lógica en el código anterior. Esto debe evitarse en la medida de lo posible porque conduce a métodos de pegamento que son feos pero que no siempre se puede evitar. En este caso, los métodos de pegamento deben minimizarse y evitarse en la medida de lo posible, pero deben usarse cuando sea necesario.

Para que esto funcione, debe comprometerse a reescribir toda la funcionalidad en un área específica. Si puede, por ejemplo, reescribir todo el código de seguimiento de la información del cliente a la vez, eso significa que no es difícil trabajar con el código que llama desde el código anterior, y se minimiza el envío al código antiguo desde el nuevo código.

Lo segundo es que si tienes abstracciones razonables en tu lugar, deberías poder elegir a qué nivel de API llamar y cómo mantenerlo limpio. Sin embargo, debería pensar en reescribir las partes que están llamando a su API para que también estén un poco más limpias.

Hay muchas áreas de herramientas comerciales que son irreductiblemente complejas. No puedes deshacerte de toda la complejidad. Pero puede administrarlo centrándose en API limpias que hacen específicamente lo que necesita hacer, y módulos que utilizan esa API de manera constructiva. El pegamento debería ser el último recurso solo después de considerar que reescribir el resto del código de llamada puede ser más rápido.


Creo que puede haber dado en el clavo. La razón por la que existe el pegamento puede deberse al código que llama a la interfaz que he creado. Voy a esperar algunas respuestas más para ver si nos falta algo, pero creo que esta lo resume bastante bien.
cmhobbs

1
"rutas de ejecución que serpentean entre módulos y viceversa, y entre idiomas, sin rima ni razón", esto también me recuerda algunas prácticas modernas de OO.
user253751

8

Parece que lo que has hecho es tomar un lío enredado de una base de código anterior y ha creado una hermosa base de código modular anterior .

Invariablemente, termino con una API limpia y no hay una forma real de vincularlo todo. La solución ha sido escribir un gran método de "pegamento" feo (generalmente lleno de declaraciones condicionales) que eventualmente llama a todos mis métodos "limpios".

Con el código de procedimiento (incluso si está disfrazado como OO), siempre terminará con algún tipo de flujo de trabajo secuencial definido en alguna parte, a menudo lleno de ramas condicionales complejas como usted describe. Sospecho que es esta naturaleza procesal del código lo que te hace sentir que algo está mal. Esto no es necesariamente algo malo, y cuando se trabaja con código heredado puede ser completamente inevitable


6

Debe limpiar el método de pegamento feo grande de la misma manera que limpió la base del código original. Divídalo en métodos modulares limpios. Probablemente tenga grupos de líneas de código que realizan alguna tarea dividiendo estas líneas en métodos, si comparte algunas variables, podría considerar poner las variables compartidas y los nuevos métodos en una clase.


2
¿Entonces no obtienes un árbol de pegamento?
Pieter B

3
@PieterB tal vez, pero es más fácil extraer las diferentes dependencias cuando tienes diferentes tareas en diferentes métodos. Podría hacer otra pasada de refactorización después de extraer los nuevos métodos.
Paling

1

Básicamente, sigue agregando capas de abstracción, hasta que se ve bien en cada capa tomada por sí misma . Lo paradójico de la abstracción es que agregas complejidad para reducirla, porque cuando lees código abstraído, solo te preocupas por una capa a la vez. Si cada capa es lo suficientemente pequeña como para ser fácilmente comprendida, no importa en cuántas capas descanse.

Eso también es lo que hace que las abstracciones sean difíciles de escribir. Incluso algo tan simple como un lápiz es alucinante si intentas mantener todas sus capas de abstracción en tu cabeza a la vez. La clave es obtener una capa de la manera que desee, lo que ha hecho, luego olvidar toda la complejidad que subyace en esa capa y hacer lo mismo en el siguiente nivel.


0

Parece que está refactorizando la API simplemente pensando en la implementación de la API, pero sin pensar lo suficiente sobre el código que usa la API, es decir, el "código de pegamento" del que está hablando.

Si eso es cierto, puede intentar comenzar en el otro extremo. Vuelva a escribir las cosas que amenazan con convertirse en su código de pegamento feo primero, y cree un par de interfaces aún no implementadas que se convertirán en su API en ese proceso. Todavía no piense demasiado en la implementación real de esta API; está bien si tiene la intuición de que puede hacerlo. Y solo entonces reescriba el laberinto de código para cumplir con esa API. Por supuesto, habrá algunos cambios en la API y el código de pegamento en este proceso, pero debería encajar mejor.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.