Reformateo y control de versiones

23

El formato del código es importante. Incluso la sangría importa . Y la consistencia es más importante que las mejoras menores. Pero los proyectos generalmente no tienen una guía de estilo clara, completa, verificable y aplicada desde el día 1, y las mejoras importantes pueden llegar cualquier día. Tal vez encuentres eso

SELECT id, name, address
FROM persons JOIN addresses ON persons.id = addresses.person_id;

podría escribirse mejor como / está mejor escrito que

SELECT persons.id,
       persons.name,
       addresses.address
  FROM persons
  JOIN addresses ON persons.id = addresses.person_id;

mientras trabaja en agregar más columnas a la consulta. Quizás esta sea la más compleja de las cuatro consultas en su código, o una consulta trivial entre miles. No importa cuán difícil sea la transición, usted decide que vale la pena. Pero, ¿cómo realiza un seguimiento de los cambios de código en los principales cambios de formato? Podría simplemente darse por vencido y decir "este es el punto en el que comenzamos de nuevo", o podría formatear todas las consultas en todo el historial del repositorio.

Si está utilizando un sistema de control de versiones distribuido como Git, puede volver a la primera confirmación y volver a formatear desde allí hasta el estado actual. Pero es mucho trabajo, y todos los demás tendrían que pausar el trabajo (o estar preparados para la madre de todas las fusiones) mientras continúa. ¿Existe una mejor manera de cambiar el historial que ofrezca el mejor de todos los resultados:

  • Mismo estilo en todos los commits
  • Mínimo trabajo de fusión

?

Para aclarar, esto no se trata de las mejores prácticas al comenzar el proyecto, sino más bien ¿qué se debe hacer cuando una refactorización grande se ha considerado una buena cosa ™ pero aún desea un historial rastreable? Nunca reescribir el historial es excelente si es la única forma de asegurarse de que sus versiones siempre funcionen igual, pero ¿qué pasa con los beneficios del desarrollador de una reescritura limpia? ¿Especialmente si tiene formas (pruebas, definiciones de sintaxis o un binario idéntico después de la compilación) para asegurarse de que la versión reescrita funcione exactamente de la misma manera que la original?

l0b0
fuente
24
¿Por qué querrías reescribir la historia? Derrota el propósito del control de versiones. Desea asegurarse de que la aplicación que envió hace 3 meses coincide con la revisión xxxxxx sin la menor duda. Incluso el reformateo trivial es inaceptable.
Simon Bergot
55
Me gusta comentar confirma que hago esto con la etiqueta "Reformatear. Sin cambio funcional"
Plataforma
3
En un tema no relacionado, parece que estaba sugiriendo reescribir el historial de Git reformateando todo el código. No le dé idea a la gente, reescribir el historial de Git es malo para el 99.9% de los casos. Reformatear no es el caso de borde de .1%.
Andrew T Finnell
44
En algunos idiomas (te estoy mirando a TI, Python), el formateo puede cambiar el funcionamiento lógico del código. Debería poder analizar todos los idiomas almacenados en su VCS para rastrear e ignorar los reformateos de forma segura.
Joris Timmermans
3
Los reformatos son cambios de código y deben confirmarse como tales.
David Cowden

Respuestas:

26

Realice el reformateo como confirmaciones separadas. Esto interferirá mínimamente con el historial, y debería poder ver de un vistazo qué confirmaciones solo se están formateando y cuáles realmente cambian el código. Podría sesgarse git blamey ser similar, pero si apunta a una confirmación solo de reformateo, es bastante sencillo buscar el cambio anterior antes de eso.

harald
fuente
He visto proyectos descarrilados durante semanas porque uno de los desarrolladores pensó que era una buena idea. Si va a hacer esto, comprenda los riesgos de antemano y decida exactamente hasta dónde llegará con el formato. Creo que mjfgates tiene la respuesta correcta.
Johntron
1
Parece que el equipo en cuestión tiene mayores problemas que el formato de código. Pero sí, no recomiendo hacer esto a menos que tengas que hacerlo. Si desea hacer cambios en el formateo, todavía diría que es mejor hacerlo como confirmaciones separadas que entremezcladas con cambios funcionales.
harald el
Sí, muchos problemas: PI solo quiere advertir a los nuevos desarrolladores que no es tan simple como parece. Las herramientas de reformateo masivo son riesgosas (especialmente si lo construye usted mismo con regex, al menos use AST), y si le preocupa la revisión de código y el seguimiento de errores, realmente puede interferir con su proceso. Personalmente, escribo mi código para que sea coherente con el estilo de cada archivo, aunque no me importa revisar el código cuando se reformatean algunas funciones. Muchos desarrolladores se obsesionan con el estilo de código y descuidan los problemas más grandes como arquitectura, proceso, herramientas, etc.
Johntron
En programación, nada es tan simple como parece :)
harald
13

No reescriba el historial de VCS: va en contra de los principios de VCS.

No intente automatizar la fijación del formato: está tratando los síntomas, no el problema real (= los desarrolladores no siguen los estándares de codificación).

Defina el estándar de codificación y las mejores prácticas de formato en un documento común y haga que todos los desarrolladores estén de acuerdo.

Mencionas Git, que es genial, porque está distribuido. Con un DVCS es muy fácil aplicar las mejores prácticas a través del flujo de trabajo de gatekeeper . Los controladores de acceso rechazan las propuestas de fusión (= solicitudes de extracción en Git) que no se ajustan a las pautas comunes. Y me refiero a rechazar , en negrita, de lo contrario el codificador en violación no se molestará en seguir las reglas y continuar repitiendo los mismos errores.

Esta técnica me funciona bien. Los codificadores quieren que su trabajo se fusione, por lo que después de algunos errores al principio, comienzan a seguir las reglas.

Según la fijación de la base de código existente ... Recomiendo hacerlo gradualmente, quizás módulo por módulo, o según tenga sentido para su proyecto. Prueba cuidadosamente en cada paso. Puede sonar estúpido, pero los errores ocurren incluso con cambios triviales como solo el formato, así que prepárate para algunos golpes menores en el camino.

janos
fuente
1
Votados en contra, porque el autor declara claramente que esto es en el contexto de proyectos que no comenzaron con "... una guía de estilo clara, completa, verificable y aplicada desde el día 1". No puede tratar el verdadero problema, porque ya sucedió. Aunque estoy de acuerdo contigo :)
Johntron
2
rechazar significa que habrá una pelea entre los humanos y el robot. Estado allí. Tarde o temprano, el robot requerirá que una pieza de código realmente compleja se formatee de forma ilegible. Ejemplos: una cadena Java es, de hecho, una declaración SQL, pero el robot no lo sabe; los espacios en blanco antes de cerrar los parens pueden llevar información sobre la estructura del código para humanos, pero no para el robot; los parámetros de la función se dividen en varias líneas de la manera más insignificante ...
18446744073709551615
9

La respuesta a su pregunta real es: "No lo hace". No conozco ninguna herramienta SCM actual que pueda rastrear los cambios en la lógica desde el código formateado de una manera, a través de un cambio de formato importante, y a través de cambios posteriores después de formatear el código de la nueva manera. Y, usted sabe esto, perder el historial en un código no es bueno.

En consecuencia, voy a contradecir un poco su primera oración. De formato de código no importa que mucho. Pretty es agradable, pero no es para lo que estamos aquí. Entiendo tan bien como cualquiera que ser arrojado al viejo y extraño código variante K&R de alguien con las sangrías de dos espacios es una mierda (1), pero ... el formateo no es realmente un obstáculo para comprender lo que está sucediendo, a menos que sea algo excepcionalmente patológico. Y en ese caso, tendrá problemas para cambiar el código de todos modos, y no debería molestarlo.

Por lo tanto, no vale la pena realizar cambios en el código establecido ESTRICTAMENTE para formatearlo. Cambiar los nombres de las variables, dividir las funciones largas, todas esas cosas buenas de refactorización que cambian el contenido, sí, pero NO SOLO formatear de nuevo.

1) - Una vez tuve el Windows Clipboard Viewer por un tiempo. Todo fue uno, 150k, módulo C. Encontré un lugar donde diferentes personas habían usado, creo, cinco estilos diferentes de aparatos ortopédicos dentro de treinta líneas entre sí. Pero esa sección de cosas funcionó. Llevé una copia impresa de ese fragmento de código durante diez años, pero no lo puse porque esa historia importaba, y ese código estaba en al menos tres árboles fuente (Windows 3.x, NT, futuro 95) que todos vivían en diferentes edificios

mjfgates
fuente
En el pasado, usando hg, descubrí que la fusión por partes es una herramienta invaluable para hacer frente a las grandes y difíciles fusiones de refactorización. Por lo general, lo que haría sería fusionar los commits antes del refactorización grande, luego fusionar el refactorización en sí mismo y finalmente fusionar los commits desde el refactorización. Cada una de estas tres fusiones por sí solas es mucho más fácil que tratar de desenredar el desorden que resulta de hacer todas las fusiones de una vez.
Mark Booth
¡Estoy totalmente de acuerdo! Además, he visto a muchos desarrolladores exagerados (incluida una versión más joven de mí mismo) en el reformateo y el estilo de código, y terminan presentando defectos. Aquí falta una coma / punto y coma, declaraciones de variables movidas a la parte superior de las funciones, bucles for cambiados a for-each's; todos pueden introducir errores sutiles. Se necesita una cantidad engañosa de habilidad para realizar estos cambios de manera segura.
Johntron
4

Pero, ¿cómo realiza un seguimiento de los cambios de código en los principales cambios de formato?

Los cambios de formato son cambios de código; trátelos como lo haría con cualquier otro cambio en su código. Cualquiera que haya trabajado en un proyecto significativo probablemente habrá visto errores y otros problemas que se crearon cuando alguien decidió "simplemente" reformatear algún código.

Pero es mucho trabajo, y todos los demás tendrían que pausar el trabajo (o estar preparados para la madre de todas las fusiones) mientras continúa.

¿Por qué tienes que formatear todo todo al mismo tiempo? Especialmente si el formateo no cambia el significado del código, debería poder formatear los archivos individualmente y registrarlos a medida que avanza. Mejor, haga que todos en su equipo acuerden un estilo (de lo contrario, no tiene sentido reformatear de todos modos) y haga que todos se encarguen de reformatear en el transcurso de su otro trabajo. Después de un tiempo, habrá cubierto la mayor parte del código sin interrumpir el resto del proyecto.

Caleb
fuente
1

Hay dos enfoques viables que he visto para esto.

1. Reformatear código en commit-hook

Aunque inicialmente es espeluznante alterar el código después de haberlo enviado, si su procedimiento de reformateo (por ejemplo, un estilo ) no daña el código, entonces es una operación segura. Con el tiempo, todo el equipo apreciará que todo el código finalmente se vea igual. Claramente, tener pruebas integrales de unidad / automatizadas asegurará que nada se rompa.

2. Reformateo único de todo el código

Esto es más peligroso en mi experiencia, y hace que los problemas de seguimiento en el big-bang sean difíciles, pero es posible. Ejecutar todas las pruebas después es esencial. Para el estilo de codificación, la mayoría de las diferencias giran en torno al uso de espacios en blanco: sangría o nuevas líneas. Una herramienta de fusión decente debería poder decir que ignore todas las diferencias de espacios en blanco, por lo que esto ayudará con las fusiones.

JBRWilkinson
fuente
1
¿No se elegiría la opción uno cuando se activa la ondulación en la mayoría de la base de código rápidamente, lo que resulta en la misma gran explosión de cada cambio de archivo?
Firma el
@Sign: Exactamente mi punto: cuando cambia el enlace de confirmación, su historial podría deteriorarse en algo casi inútil. El formato que no cambia la funcionalidad no debe ser una confirmación, sino que debe trasplantarse a lo largo del historial del código.
l0b0
1
Si el IDE lo admite, también hay 3) tener el autoformato IDE al guardar. Luego, use la misma configuración en todas partes; esto es más fácil si usa el valor predeterminado con el IDE.
He hecho ambos enfoques. El primer enfoque es muy molesto porque habrá un montón de cambios cada vez que se confirma un nuevo archivo por primera vez. El segundo enfoque es mejor para el equipo, como arrancar una venda rápida.
Druska