2010-03-25 15 views
11

me gustaría distinguir tres tipos diferentes de conflicto desde un sistema de control de versiones (VCS):Mejor y más simple ejemplo de 'conflicto semántico'?

  • Pruebas
  • sintáctica
  • semántica

Un Pruebas conflicto es uno que es detectado por el proceso de fusión o actualización. Esto es marcado por el sistema. Un compromiso del resultado no está permitido por el VCS hasta que se resuelva el conflicto.

A syntactic conflicto no está marcado por el VCS, pero el resultado no se compilará. Por lo tanto, esto también debería ser recogido incluso por un programador ligeramente cuidadoso. (Un ejemplo sencillo podría ser una variable de cambiar el nombre por izquierda y algunas líneas añadidas utilizando esa variable por derecho. La fusión tendrá probablemente un símbolo sin resolver. Por otra parte, esto podría introducir un semántica conflicto al escondite variable.)

Finalmente, el conflicto semántico no está marcado por el VCS, el resultado se compila, pero el código puede tener problemas al ejecutarse. En casos leves, se producen resultados incorrectos. En casos severos, un choque podría ser introducido. Incluso estos deben ser detectados antes de la confirmación por un programador muy cuidadoso, a través de la revisión del código o la prueba unitaria.

Mi ejemplo de un conflicto semántico utiliza SVN (Subversion) y C++, pero esas elecciones no son realmente relevantes para la esencia de la pregunta.

El código base es:

int i = 0; 
int odds = 0; 
while (i < 10) 
{ 
    if ((i & 1) != 0) 
    { 
     odds *= 10; 
     odds += i; 
    } 
    // next 
    ++ i; 
} 
assert (odds == 13579) 

La Izquierda (L) y derecho (R) cambios son los siguientes.

izquierda 's 'optimización'(cambiando los valores de la variable de bucle de toma):

int i = 1; // L 
int odds = 0; 
while (i < 10) 
{ 
    if ((i & 1) != 0) 
    { 
     odds *= 10; 
     odds += i; 
    } 
    // next 
    i += 2; // L 
} 
assert (odds == 13579) 

derecho' s 'optimización' (cambio de cómo se utiliza la variable de bucle):

int i = 0; 
int odds = 0; 
while (i < 5) // R 
{ 
    odds *= 10; 
    odds += 2 * i + 1; // R 
    // next 
    ++ i; 
} 
assert (odds == 13579) 

Esto es el resultado de una fusión o actualización, y no es detectado por SVN (que es el comportamiento correcto para el VCS), por lo que no es un conflicto de texto. Tenga en cuenta que se compila, por lo que no es un conflicto sintáctico.

int i = 1; // L 
int odds = 0; 
while (i < 5) // R 
{ 
    odds *= 10; 
    odds += 2 * i + 1; // R 
    // next 
    i += 2; // L 
} 
assert (odds == 13579) 

El assert falla porque es odds 37.

Así que mi pregunta es la siguiente. ¿Hay un ejemplo más simple que esto? ¿Hay un ejemplo simple donde el ejecutable compilado tiene un nuevo bloqueo?

Como una pregunta secundaria, ¿hay casos de esto que haya encontrado en el código real? De nuevo, ejemplos simples son especialmente bienvenidos.

+0

Esto no es particularmente relevante para C++, por lo que han eliminado esa etiqueta. Y para ser sincero, no entiendo la pregunta y no veo qué tiene que ver con el control de versiones. –

+1

rhubbarb probablemente quiere escuchar las experiencias de otras personas con respecto a estos cambios inadvertidos en la semántica, por lo que podría crear algún tipo de lista de verificación de cosas a tener en cuenta al fusionar el código. Podría llegar a ser un tema interesante si ese es, de hecho, lo que es el punto. –

+4

@Tomislav: sí, esa es una de las razones. @Neil: acepto la eliminación de la etiqueta C++; mi error. Por otro lado, esto tiene * todo * que ver con el control de versiones. Las operaciones de fusión son fundamentales para VCS, y también es importante conocer las formas en que estos sistemas tan útiles pueden ocasionalmente tener resultados inesperados. – Rhubbarb

Respuesta

8

No es obvio para llegar a simples ejemplos relevantes, y este comentario resumir mejor el por qué:

Si los cambios están muy cerca, a continuación, resoluciones triviales tienen más probabilidades de ser correcta (porque aquellos que son incorrectos son más propensos a tocar las mismas partes del código y, por lo tanto, resultan en conflictos no triviales), y en esos pocos casos donde no lo son, el problema se manifestará con relativa rapidez y probablemente de manera obvia.

[que es básicamente lo ilustra el ejemplo]

Pero la detección de conflictos semánticos introducidos por fusiones entre los cambios en áreas muy alejadas del código es probable que requiera la celebración de más del programa en su cabeza que la mayoría de los programadores pueden, o en proyectos del tamaño del kernel, que cualquier programador.
Así que incluso si revisara manualmente los difs de 3 vías, sería un ejercicio comparativamente inútil: el esfuerzo sería desproporcionado con el aumento de la confianza.

De hecho, yo diría que la concentración es una cortina de humo:
este tipo de choque semántica entre partes dispares pero interdependientes del código es inevitable el momento en que pueden evolucionar por separado.
Cómo se organiza este proceso simultáneo de desarrollo: DVCS; CVCS; tarballs y parches; todos editan los mismos archivos en una red compartida, no tiene ninguna consecuencia en absoluto a ese hecho.
La fusión no causa enfrentamientos semánticos, la programación provoca conflictos semánticos.

En otras palabras, el caso real de conflictos semánticos que he encontrado en código real después de una fusión no fuera simple, sino más bien bastante complejo.


Dicho esto, el ejemplo más simple, como se ilustra en Martin Fowler in his article Feature Branch es un cambio de nombre de método:

El problema que preocupa más es un conflicto semántico.
Un ejemplo simple de esto es que si el Profesor Plum cambia el nombre de un método que llama el código del Reverendo Green. Las herramientas de refactorización le permiten cambiar el nombre de un método de forma segura, pero solo en su código base.
Así que si G1-6 contiene nuevo código que llama foo, el profesor Ciruela no puede contar en su base de código que él no lo tiene. Solo descubres en la gran fusión.

un cambio de nombre de función es un caso relativamente obvia de un conflicto semántico.
En la práctica, pueden ser mucho más sutiles.

Las pruebas son la clave para descubrir ellos, pero el código más hay que fusionar el más probable es que usted tiene conflictos y, más difícil es para solucionarlos.
Es el riesgo de conflictos, particularmente conflictos semánticos, que hacen que las grandes fusiones sean aterradores.


Como Ole Lynge menciones en his answer (upvoted), Martin Fowler hicieron escribir hoy (hora de esta edición) un post sobre "conflicto semántico", incluyendo la siguiente ilustración:

semantic conflict illustration

Una vez más, esto se basa en el cambio de nombre de función, aunque se mencionan caso más sutil basado en interna refactorización función:

El ejemplo más simple es el cambio de nombre de una función.
decir que creo que el método clcBl sería más fácil trabajar con si se llama calculateBill.

Así que el primer punto aquí es que por más poderoso que sus herramientas es, que sólo le protege de los conflictos textuales.

Hay, sin embargo, un par de estrategias que pueden ayudar significativamente a lidiar con ellos

  • El primero de ellos es SelfTestingCode. Las pruebas están investigando efectivamente nuestro código para ver si su punto de vista de la semántica del código son consistentes con lo que el código realmente hace
  • La otra técnica que ayuda es la de integrar más a menudo

A menudo, las personas tratan de justificar en base DVCSs en cómo hacen que la función de ramificación sea fácil. Pero eso pasa por alto los problemas de los conflictos semánticos.
Si sus características se crean rápidamente, dentro de un par de días, se encontrará con menos conflictos semánticos (y si es menor que un día, entonces es en efecto igual que CI). Sin embargo, no vemos esas ramas cortas tan a menudo.

Creo que es necesario encontrar un término medio entre las sucursales de vida real y las ramas características.
Y fusionarse a menudo es clave si tiene un grupo de desarrolladores en el mismo rama de función.

+1

Parte de la razón para haber planteado esta pregunta es que estoy planeando dar una presentación sobre el control de fuentes en general y SVN en particular. Uno de los puntos que quiero ilustrar es que ninguna herramienta de software es un sustituto de una buena planificación o buena comunicación. Otro punto que quiero ilustrar es que SVN hace un buen trabajo, pero no puede leer tu mente. Es por eso que quiero un ejemplo artificialmente simple. Gracias por tu respuesta. Todavía espero más respuestas o comentarios sobre mi pregunta ... – Rhubbarb

+1

@rhubbarb: entendí, y encuentro su pregunta muy interesante. Con respecto a SVN, el verdadero problema es, por supuesto, la fusión: ver http://stackoverflow.com/questions/2475831/merging-hg-git-vs-svn/2477089#2477089 y http://stackoverflow.com/questions/2471606/ ¿Cómo y por qué? se está fusionando en Git-mejor que en svn/2472251 # 2472251 – VonC

+0

Wow, he estado leyendo sobre conflictos semánticos durante todo el día (en realidad para entender el silencio patológico considerándolos en la mayoría de las pláticas sobre fusiones automáticas exitosas ...), y ahora esta única oración finalmente arroja una luz nítida en la dirección correcta: "Fusionarse no causa enfrentamientos semánticos, la programación causa enfrentamientos semánticos". ¡Gracias! :) (Aquí es donde está el comentario original, en una increíble publicación de blog, BTW: http://yosefk.com/blog/dvcs-and-its-most-vexing-merge.html) –