TODO comentarios con plazos?

51

Antecedentes

Estoy trabajando en un equipo que busca implementar implementaciones de tiempo de inactividad cero. Estamos planeando usar una estrategia de implementación azul / verde para lograr esto. Una de las cosas de las que me estoy dando cuenta al investigar es lo complicado que resulta hacer cambios en la base de datos. ¡Una operación simple como cambiar el nombre de una columna puede tomar 3 ciclos completos de liberación hasta que se complete!

Me parece que tener el despliegue completo de un cambio tomar múltiples ciclos de lanzamiento introduce un gran potencial para el error humano. En el artículo vinculado, muestra que los cambios de código son necesarios para 2 versiones y una migración de base de datos para 3 versiones.

Lo que estoy buscando

Actualmente, si queremos recordar hacer algo, podemos crear un ticket en nuestro sistema de administración de problemas, lo que crea desorden y también puede ser trasladado a un sprint posterior o al retraso de la administración; o podemos crear un comentario TODO, que probablemente se olvidará por completo.

Lo que estoy buscando es una forma en que un comentario TODO pueda tener una fecha límite en su contra, y nuestro sistema de Integración Continua (actual indeciso que usaremos) rechazaría la compilación si esta fecha límite expirara.

Por ejemplo, si cambiamos el nombre de una columna, podríamos crear la migración inicial para ella, y luego dos comentarios TODO para garantizar que se creen las dos migraciones restantes:

// TODO by v55: Create migration to move constraints to new column, remove references to old column in app
// TODO by v56: Create migration to drop old column

Esto parece bastante simple de implementar, pero me pregunto si ya existe algo como esto, porque no quiero reinventar la rueda.

Pensamientos adicionales

Siento que podría estar sufriendo un problema XY aquí, dado que las implementaciones continuas y las implementaciones azul / verde se consideran una práctica recomendada, parece extraño que no pueda encontrar una solución para hacer que las actualizaciones de la base de datos sean menos dolorosas. Si crees que estoy investigando algo completamente incorrecto, ¡házmelo saber en un comentario! Dicho esto, el ejemplo de la base de datos que di es solo un ejemplo, y creo que los comentarios TODO con fechas de vencimiento también serían útiles en otras situaciones, por lo que incluso si me estoy acercando a esta situación específica completamente equivocada, realmente me gustaría responder a mi pregunta real también. ¡Gracias!

EDITAR: Acabo de pensar en otra situación en la que esto podría ser útil. Si usa las funciones de alternancia para activar partes de su aplicación cuando estén listas, debe tener cuidado de limpiarlas, de lo contrario, podría terminar con la deuda de alternancia . Los comentarios con fechas límite podrían ser una buena forma de recordar esto.

Joshua Walsh
fuente
19
El tema TODO es más una cuestión de disciplina que de herramientas.
Brandon
16
Creo que todos los humanos cometemos errores, y las herramientas pueden ser una buena forma de mitigar esto.
Joshua Walsh
3
¿Qué tal hacer esto programáticamente? Me refiero a escribir en un miembro de tu clase tu versión. Si no se inicia la aplicación si la versión es igual == 56 con el mensaje "clase y" necesita tener esta característica, puede tener una lista de dichos mensajes. ¿Qué piensas?
Tomer Ben David,
66
Dirigido a los que no lo dicen, no estoy de acuerdo: nuestra base de código se basa en muchos otros componentes en los que no trabajamos, por lo que utilizamos TODO <Bug#>:para rastrear soluciones a problemas con otros componentes. Cuando se elimina un error en uno de esos componentes, puede encontrar y abordar fácilmente las soluciones alternativas. No reemplaza un rastreador de problemas, lo hace más fácil de mantener.
TemporalWolf

Respuestas:

53

Esta pregunta es realmente dos preguntas en una.

Todo comentarios

De todas las formas de rastrear elementos de acción, esta es la peor. Los comentarios TODO son buenos durante el trabajo activo o como una forma de sugerencia para un responsable de mantenimiento, "esto es algo que podría mejorarse en el futuro". Pero si confía en los comentarios de TODO para realizar el trabajo, está condenado al fracaso.

Qué hacer al respecto

Los comentarios de TODO son básicamente deudas técnicas, por lo que deben manejarse como cualquier otra deuda técnica. Abórdelos de inmediato, si tiene tiempo, o póngalos en la cartera de pedidos para que puedan rastrearse y priorizarse.

En términos generales, y esto es totalmente obstinado y abierto a debate, TODO los comentarios podrían considerarse un olor a código. Si un comentario de TODO llega al control de la versión, debe preguntarse, ¿realmente lo va a seguir en este momento? Si no, está bien. Solo sé honesto contigo mismo y ponlo en la cartera.

La forma en que gestiona este trabajo atrasado se reduce a procesos comerciales, políticas de la empresa y, tal vez, cierta autonomía personal. Pero aún necesita un registro de seguimiento rastreado y priorizado para asegurarse de que suceda.

Cambios en la base de datos.

Sí, los cambios en la base de datos son complicados con una política de tiempo de inactividad cero. Algunos trucos para ayudar a que sea menos doloroso:

Proceso posterior a la implementación

Cree un proceso posterior a la implementación que se ejecute como parte de la misma versión. Sin embargo, quieres que funcione. En el último sistema en el que trabajé, diseñé una implementación de 4 fases:

  1. guiones de base de datos preapp
  2. aplicaciones web
  3. scripts de base de datos postapp
  4. scripts de bases de datos de ventanas de mantenimiento

La idea era que siempre que fuera posible, pondríamos la mayor cantidad posible de cambios en la base de datos en preapp.

Postapp estaba reservado para los casos inusuales en los que necesitábamos hacer cambios de esquema incompatibles. En esos casos, preapp haría un cambio suficiente para hacer que el nuevo código de aplicación sea compatible (tal vez creando una vista temporal para compatibilidad), y postapp limpiaría dichos artefactos temporales.

La fase de la ventana de mantenimiento estaba reservada para los cambios que realmente requerían tiempo de inactividad o donde el riesgo o el costo de una implementación en vivo no valía la pena. Por ejemplo, los scripts que cambian cantidades masivas de datos pueden necesitar bloquear una tabla completa.

Implementar con frecuencia

Si implementa nuevas versiones con la frecuencia suficiente, puede llegar a un punto en el que llevar un cambio en 2 o 3 versiones es trivial. Los ciclos de lanzamiento largos amplifican el costo de los cambios en la base de datos.

Brandon
fuente
18
Los comentarios de Todo son una forma terrible de rastrear y priorizar el trabajo. Son una forma válida de explicar por qué un trozo de código medio terminado se agita en el viento. En un mundo perfecto, ningún código hace eso. Mientras tanto, en este ...
candied_orange
66
... a veces es bueno tener una forma de rastrear la deuda técnica que ninguna cantidad de privarización del jefe puede ocultar. Seguro que no obtendrás crédito por arreglarlo. A veces lo arreglas de todos modos.
candied_orange
3
Entonces, ¿la estrategia con la aplicación posterior es que esas migraciones se ejecutan una vez que la implementación de la aplicación se ha realizado correctamente? ¿Qué hay del código? Digamos que está cambiando el nombre de una columna de apellido a apellido. Su código anterior usa apellido_. Migra la base de datos para agregar apellido y cambia su código para usar el apellido si está disponible, de lo contrario, apellido_. Después de que la implementación se haya implementado por completo, ejecute la próxima migración y suelte la columna anterior last_name. Pero su código aún contiene el código para last_name, que ahora no se utiliza y, por lo tanto, es una deuda técnica. ¿Cómo haces cumplir la limpieza de esto?
Joshua Walsh
3
Si bien la gestión de elementos de acción en los comentarios es realmente una forma terrible, hacer que los comentarios creen problemas automáticamente en un sistema de seguimiento puede ser una buena herramienta para no olvidar hacer esto porque actualmente está en medio de la codificación de algo y no desea cambiar con dificultad contexto al sistema de seguimiento de problemas.
PlasmaHH
66
En mi humilde opinión esta respuesta está perdiendo el punto. El OP solicitó una solución en la que el CI notifica al equipo cuando se olvidó una limpieza importante, sin saturar el "sistema de gestión de problemas" (los comentarios TODO fueron solo un ejemplo, quizás no la solución ideal para esto). El OP dio algunas buenas razones por las que no quiere usarlo aquí. Sin embargo, esta respuesta sugiere confiar completamente en la cartera de pedidos, que en el caso del OP no es más que su "sistema de gestión de problemas". Entonces, en mi humilde opinión, esta respuesta ignora el núcleo de la pregunta y no presenta una solución.
Doc Brown
24

No use TODOs. Ya tienes una lista TODO en tu proyecto. Se llama el rastreador de problemas.

Creo que el verdadero problema está en esta oración:

podemos crear un ticket en nuestro sistema de administración de problemas, que crea desorden y también puede ser trasladado a un sprint posterior o al retraso de la administración.

Si su rastreador de problemas crea demasiado desorden, busque formas de solucionarlo. Tal vez un tipo / etiqueta de problema especial que implica menos ceremonia. Quizás subtemas. Quizás menos ceremonia por completo. Realmente no podemos decirlo. Pero si su rastreador de problemas crea tanto trabajo, que las personas prefieren formular una pregunta elaborada en un foro público que simplemente agregar ese problema, algo está muy mal.

Si su administración retrasa indebidamente la última parte de una tarea, tiene dos opciones:

  1. Hable con su gerencia por qué es una mala idea.

  2. manejarlo como una sola tarea. Esta podría ser la solución estándar de oro. En un mundo perfecto, deberías poder hacer los tres cambios necesarios en cada paso. Aplique uno a la rama maestra, déjelo construir e implementar. Mientras tanto, aplique el segundo a la rama maestra, déjelo construir y desplegar, y así sucesivamente para que todo suceda en el mismo sprint, y si no lo hace, no se hace. Tal vez incluso algo automático tiene sentido cuando lógicamente haces una implementación, pero en realidad se divide en 3.

Jens Schauder
fuente
Un buen consejo, pensaré en las formas en que podemos hacer que el sistema de gestión de problemas funcione para nosotros para este propósito. También me gusta mucho la idea de "Tal vez incluso algo automático tiene sentido cuando lógicamente haces una implementación", estoy tratando de pensar en formas en que podemos hacerlo. Sin embargo, no estoy seguro de que sea realmente posible.
Joshua Walsh
11
Es completamente razonable tener comentarios sobre el formulario // TODO(#12345): Frobnicate the sprocket before passing it along, siempre que el error # 12345 sea un número de problema "real" y el problema se asigne a alguien. Esto hace que la fuente sea más fácil de leer al aclarar: "No, el paso de frobnicate no se esconde en uno de los métodos auxiliares, simplemente no está implementado. Ve al bug # 12345 para obtener más contexto". Idealmente, debería tener una interfaz diaria que se ejecute sobre la base de código en busca de números de problema cerrados o no válidos, por supuesto.
Kevin
9

Lo que estoy buscando es una forma en que un comentario TODO pueda tener una fecha límite en su contra, y nuestro sistema de Integración Continua (actual indeciso que usaremos) rechazaría la compilación si esta fecha límite expirara.

Lo que pides es factible si estás dispuesto a hacer el trabajo y seguir adelante.

// TODO by v55: crea la migración para mover las restricciones a la nueva columna, elimina las referencias a la columna anterior en la aplicación // TODO by v56: crea la migración para eliminar la columna anterior

grep para //TODO by v55cuando es hora de implementar v55. Deploy build ejecuta un script que lo hace como prueba de integración.

Puede vincular 55 en el seguimiento de su versión o simplemente solicitarlo.

Se vuelve interesante si desea verificar // TODO por v54 cuando hace 55. En lugar de buscar la base de código 55 veces, simplemente busque // TODO por. Luego filtre ese resultado de 1 a 55. Ahora 56 no activará una falla.

Puede pensar "oh, no necesitaremos eso. Solucionaremos esto siempre que tengamos el cheque". No. No, no lo harás.

naranja confitada
fuente
44
Si es así, no hacemos recomendaciones aquí.
candied_orange
3
Si hay un nombre genérico para este tipo de cosas que se puede proporcionar, pero si lee la página que enlazó la línea sobre recomendaciones, le
indicará
66
Para ser claros, es tu comentario al que me opongo en lugar de toda la pregunta.
candied_orange
2
Los sitios de @YM_Industries SE tienden a ser independientes, las recomendaciones son básicamente respuestas simples con enlaces a sitios externos, o lo invitamos a buscarlo en Google en lugar de un enlace, pero al final es el mismo. Pueden caducar y morir. Por lo tanto, una pregunta sobre la recomendación está fuera de tema, sin embargo, si alguien quiere mencionar una herramienta como complemento de una respuesta o un simple comentario, puede hacerlo.
Walfrat
2
"Me preguntaba si existe una solución existente" - intente consultarnos en softwarerecs.stackexchange.com
Mawg
4

Tuvimos un problema muy similar en nuestro equipo. Para resolver esto, escribimos una verificación de análisis estático que maneja estos TODOS verificando el problema JIRA o el Problema Git al que hacen referencia. Nuestra compilación falla cuando el problema especificado pasa de la columna "En desarrollo".

Por lo tanto, podemos tener TODO cómodamente sin preocuparnos de que se olviden.

Creé una implementación de código abierto de esto, en Java. Sí, un descargo de responsabilidad es que escribí esto, pero como dije es de código abierto y con licencia.

La herramienta se llama Westie y un ejemplo del verificador de problemas de Jira está en README.md. Vea también el GitIssueAnalyser.

Para evitar la promoción personal si tiene más preguntas, envíeme un mensaje. Si decide usarlo y tiene alguna sugerencia, plantee cualquier problema en github.

tjheslin1
fuente
1
¡Eso es genial! También usamos JIRA, podría considerar usar esto. Realmente no resuelve mis preocupaciones sobre la creación de desorden en nuestro sistema de gestión de problemas, pero al menos garantizará que no se puedan olvidar.
Joshua Walsh
@YM_Industries me alegro. Estaré encantado de aceptar cualquier contribución o trabajar en cualquier tema que surja.
tjheslin1
4

No hacer Hazlo ahora.

TLDR: escriba (y pruebe) sus scripts de base de datos ahora, no más tarde; simplemente codifíquelos para que su ejecución dependa de la versión DB.

Ejemplo

Por ejemplo, imaginemos que desea cambiar el nombre de una columna de SSNa TaxID, un requisito común cuando se internacionaliza.

Para que esto suceda, tal vez tenga temporalmente una TaxIDy una SSNcolumna. Y si bien admite ambas versiones, tendrá un activador para actualizar una desde la otra. Pero no desea mantener ese desencadenador indefinidamente, por lo que más tarde, cuando ya no sea necesaria la compatibilidad con versiones anteriores, desea que se elimine ese desencadenante (y se elimine la SSNcolumna). Vamos a codificar todo eso por adelantado sin necesidad de elementos de tareas pendientes.

En nuestro ejemplo, implementaremos la compilación 102 (que tiene la nueva columna) mientras mantenemos la compatibilidad con la compilación 101 (que no).

Aquí están los pasos.

1. Configurar tabla de versiones

  1. Agregue una sola tabla llamada Configurationcon dos columnas, Namey Value.

  2. Agregue una fila con un Name"TargetVersion" y establezca Valuela versión de la nueva compilación que se implementará.

  3. Agregue una fila con un Name"CompatibleWith" y establezca el Valuenúmero de versión mínimo con el que la implementación debe ser compatible.

Inspeccione y actualice estas filas antes de cada implementación.

2. Modificar scripts de implementación

  1. Agregue una secuencia de comandos que cree una nueva columna de TaxID, lado a lado SSN, y la complete desde la SSNcolumna. Incluya este código en una Ifdeclaración que verifique TargetVersion; si la versión de destino es demasiado baja (es decir, TaxIDtodavía no es necesaria), omita.

    SELECT @TargetVersion = TargetVersion FROM Configuration
    IF @TargetVersion < '102' THEN RETURN
    ALTER TABLE Customer ADD COLUMN taxID VarChar(12) NOT NULL
    UPDATE Customer SET TaxID = SSN
    
  2. Agregue un script que cree un desencadenador que se complete TaxIDal insertar o actualizar SSNy viceversa. Incluya este código en una Ifdeclaración que verifique la versión de destino y la versión compatible; omita si TargetVersion es demasiado bajo ( TaxIDno es necesario) o si la versión CompatibleWith es demasiado alta (el SSNcampo no es necesario).

    SELECT @TargetVersion  = TargetVersion,
           @CompatibleWith = CompatibleWith 
    FROM Configuration
    IF @TargetVersion  < '102' THEN RETURN
    IF @CompatibleWith > '101' THEN RETURN
    CREATE TRIGGER SSNAndTaxIDTrigger ON Customer etc.
    
  3. Agregue un script para eliminar la SSNcolumna. Adjunte una Ifdeclaración que elimine la columna solo si la versión CompatibleWith es lo suficientemente alta ( SSNya no es necesaria).

    SELECT @CompatibleWith = CompatibleWith FROM Configuration
    IF @CompatibleWith <= '101' THEN RETURN
    IF OBJECT_ID('SSNAndTaxIDTrigger') IS NOT NULL DROP TRIGGER SSNAndTaxIDTrigger
    IF EXISTS (SELECT * FROM syscolumns c JOIN sysobject o ON o.id = c.is WHERE o.Name = 'Custeomr' AND c.Name = 'SSN') BEGIN
        ALTER TABLE Customer DROP COLUMN SSN
    END
    

3. Prueba

Asegúrese de probar su implementación con cualquier combinación de números de versión Azul / Verde que desee admitir en producción. Puede probar tan pronto como el código esté listo, manipulando la Configurationtabla en su entorno de control de calidad.

4. En su libro de jugadas de implementación

Agregue un paso para que un ingeniero actualice la versión CompatibleWith y las filas TargetVersion. Si está implementando en Blue, configure TargetVersion en el número de versión de Blue y la versión CompatibleWith en el número de versión de Green; inviértelas si estás desplegando Green.

Trampas

Está bien que sus scripts de implementación hagan referencia y confíen en los números de versión contenidos en esa tabla de base de datos. NO código de tiempo de ejecución.

Si comienza a escribir su código de tiempo de ejecución para inspeccionar los números de versión, está introduciendo un nuevo nivel de complejidad en su aplicación que podría convertirse en un gran problema de mantenimiento. Cada ruta de ejecución de tiempo de ejecución debe ser probada; Si llevas estas condiciones en el futuro, el control de calidad tendrá que armar una matriz de dolor para validarlas con cada lanzamiento. Mi consejo es mantener condiciones como estas solo en los scripts de implementación.

El resultado de todo esto

Al final, deberías poder escribir todo el código por adelantado (y probarlo también) sin temor a que se ejecute demasiado pronto. Además, el código limpiará el activador de compatibilidad con versiones anteriores cuando llegue el momento sin que tenga que preocuparse más por ello.

De esta manera, puede escribir y probar todo el código por adelantado, cuando lo esté pensando, y no necesita lidiar con esos comentarios desordenados de tareas pendientes.

John Wu
fuente
Realmente me gusta este enfoque, es más elegante que los comentarios de ToDo. Lo pensé poco después de hacer esta pregunta y estaba pensando en hacer otra publicación preguntando sobre la mejor manera de implementar esto, pero pensé que primero haría mi propia investigación. El truco para nosotros es que estamos usando Phinx para nuestras migraciones de bases de datos, y realmente no es compatible con esto. Cuando tenga tiempo, buscaré una manera de extenderlo para admitir este tipo de flujo de trabajo. Este enfoque no resuelve el problema de cómo garantizar que el código de compatibilidad con versiones anteriores se elimine de mi nivel de aplicación, pero es elegante para el problema de la base de datos.
Joshua Walsh
1

Usted está recibiendo muchos rechazos en su idea TODO, pero personalmente no veo ningún problema con eso. Al final, la mejor (y más fácil) manera de asegurarse de que la migración entre en producción es fallando una prueba unitaria si no es así. Literalmente, le llevará menos de un minuto desactivar una función de migración vacía que arroje una excepción si la versión es 55 o más (o cualesquiera que sean los requisitos).

Luego, si intenta liberarlo, terminará con una prueba fallida, y alguien tendrá que convertir esa excepción en un código de migración real.

Eterno21
fuente
1
Sí, idealmente esperaba tratar un TODO caducado como una prueba fallida. La cantidad de retroceso contra TODO me ha sorprendido un poco, sé que no son un sustituto de un sistema de gestión de problemas, pero dada la prevalencia de TDD / BDD, está claro que no hay un problema real con la definición de requisitos en el código y el uso del código para hacer cumplir característica de finalización.
Joshua Walsh
-2

Nadie parece centrarse en la raíz de su queja, que es el hecho de que los cambios en la base de datos pueden tomar demasiados ciclos de lanzamiento. Quiere continuar con su programa de implementación azul / verde y la solución ya debería estar allí, pero a menos que me falte algo, su descripción parece indicar que solo hay una base de datos compartida por ambos sistemas. No es un verdadero sistema azul / verde si ese es el caso. Dado que parece que la base de datos es el polo largo de la tienda, también debe duplicarse para que, sin importar cuánto tiempo o cuántos ciclos de lanzamiento se necesiten para implementar los cambios de la base de datos en el sistema fuera de línea, no se activen hasta que se completen y Totalmente probado. En el sistema sin conexión provisional, los scripts pueden mantener la base de datos sin conexión totalmente actualizada diariamente.

mpiazza
fuente
1
La replicación de la base de datos en una implementación azul / verde causa mucho dolor de cabeza. Cuando mi prod env está en algún lugar entre azul y verde (50% de carga distribuida a cada uno, por ejemplo), necesito que el código de replicación mantenga ambas bases de datos sincronizadas, incluso si sus esquemas son diferentes. Según la investigación que he realizado, parece que la mayoría de las personas en el mundo real tienen una instancia de base de datos compartida entre sus pilas azules y verdes. No veo esto como un problema importante, siempre y cuando las migraciones de la base de datos sean bastante rápidas. Las pilas azules / verdes necesitan compartir algunos recursos, como mínimo el equilibrador de carga / proxy inverso.
Joshua Walsh