Versiones semánticas al corregir un error importante

18

Actualmente administro una biblioteca que tiene mucho uso público, y tenía una pregunta sobre el control de versiones semántico . Quiero refactorizar una parte bastante importante de la biblioteca que se implementa incorrectamente y siempre se ha implementado incorrectamente. Pero hacer esto significaría cambios en la API pública, que es una decisión importante.

El cambio que quiero hacer gira en torno a cómo se usan los iteradores. Actualmente, los usuarios tienen que hacer esto:

while ($element = $iterator->next()) {
   // ...
}

Lo cual es incorrecto, al menos en la interfaz Iterator nativa de PHP . Quiero reemplazar con esto:

while ($iterator->valid()) {
   $element = $iterator->current();
   // ...
   $iterator->next();
}

que es análogo a:

foreach ($iterator as $element) {
    // ...
}

Si nos fijamos en la guía de Tom para el control de versiones semántico, él afirma claramente que cualquier cambio en la API pública (es decir, aquellos que no son compatibles con versiones anteriores), debe justificar una versión importante. Entonces, la biblioteca saltaría de 1.7.3 a 2.0.0, lo que, para mí, es un paso demasiado lejos. Solo estamos hablando de una característica que se está arreglando.

Tengo planes de lanzar eventualmente 2.0.0, pero pensé que esto fue cuando reescribió completamente la biblioteca e implementó numerosos cambios públicos de API. ¿La introducción de esta refactorización garantiza el lanzamiento de una versión principal? Realmente no puedo ver cómo funciona, me siento más cómodo lanzándolo como 1.8.0 o 1.7.4. ¿Alguien tiene algún consejo?

hohner
fuente
¿Qué le impide mantener la compatibilidad con versiones anteriores?
Mouviciel
Por el momento, el next()método se utiliza para recuperar el elemento actual Y mover el puntero interno hacia adelante. Cuál está mal. next()debería mover el puntero, y current()se usa para recuperar ...
hohner
66
así que en la nueva versión, a la gente no debería importarle el valor de retorno de next()solo eso que mueve el puntero, esto realmente no rompe la compatibilidad
monstruo de trinquete

Respuestas:

29

Duda porque no quiere hacer versiones semánticas, quiere hacer "versiones de soporte publicitario". Espera que un número de versión "2.0" le diga al mundo que tiene un montón de nuevas características interesantes en su biblioteca ahora, no que haya cambiado la API. Eso está bien (muchas compañías de software y / o desarrolladores hacen eso). En mi humilde opinión tienes las siguientes opciones:

  • atenerse a las versiones semánticas y vivir con el hecho de que tiene que cambiar el número de versión a 2.0.0
  • cambie su esquema de versiones a 4 números. "1.1.7.3" es su versión ahora, "1.2.0.0" la siguiente después de cambiar la API, y "2.0.0.0" la primera de la "familia de productos 2.x completamente nueva"
  • haga que su solución sea compatible con versiones anteriores (así que no cambie la funcionalidad de next, solo agregue las funciones validy current). Luego puede usar "1.8.0" como el próximo número de versión. Si cree que cambiar el comportamiento de nextes realmente importante, hágalo en 2.0.0.
Doc Brown
fuente
Tanto como la última opción sería la solución perfecta: no puede pedir next()seguir haciendo lo que está haciendo. Para implementar la funcionalidad correctamente, tiene que hacer algo diferente. Entonces, si lo hago compatible con versiones anteriores, la nueva funcionalidad / corrección también será incorrecta y socavará todo el punto del cambio.
Hohner
2
La sugerencia más amplia que haga en su tercera viñeta (hacer que la solución sea compatible con versiones anteriores) es buena para considerar. Puede que no funcione en este caso particular, pero vale la pena considerar la técnica general. La función termina siendo más compleja, pero esta puede ser una ruta viable.
Gracias a todos: si pudiera aceptar dos lo haría. Terminé pirateando el nuevo next()método para hacer toda la nueva funcionalidad, además de lo que se necesitaba para hacer compatible con versiones anteriores. Se siente un poco horrible tener que empañar una nueva funcionalidad como esta, pero bueno, hola.
hohner
10
@hohner: Entonces ahora también es el momento de documentar el comportamiento anterior como obsoleto, para que pueda eliminarlo en 2.0.0.
Jan Fabry
7

Siga con la guía de Tom sobre versiones semánticas.

Cualquier cambio significativo en una API pública debe hacerse en cualquiera de los dos puntos:

  1. Nunca
  2. En una actualización de lanzamiento importante

Mi voto, por cierto, es por el primero. Pero reconozco que solo es apropiado para cosas insignificantes.

El problema es mantener la compatibilidad con versiones anteriores y asegurarse de no romper las cosas para los usuarios anteriores de su API.

En esencia, está creando un error de indexación para sus usuarios que desconocen el cambio. Forzar un cambio como este obliga a todos los usuarios a hacer lo siguiente:

  1. Codifique la solución para usar el nuevo enfoque
  2. Valide la corrección y asegúrese de que no rompa nada
  3. Enviar nuevas versiones de sus productos a sus usuarios finales

Potencialmente, eso puede ser un gran esfuerzo, especialmente cuando considera pocos proyectos que tienen casos de prueba para validar cambios como este. La cantidad de esfuerzo aumenta cuando considera la cantidad de usuarios intermedios de sus usuarios que también necesitarán actualizar sus instalaciones.

Para algo tan pequeño, lo dejaría pasar y no me molestaría.
Si realmente te molesta (lo que aparentemente hace o no hubieras preguntado), entonces haría lo siguiente.

  1. Cree la rama v2.0.0 en su árbol de código
  2. Haga la primera contribución a la rama v2.0.0, que es este cambio
  3. Enviar una vista previa Release Notesantes de tiempo transmitiendo que el cambio se acerca

Y luego sea paciente, ya que tomará un tiempo acumular otras cosas que justifiquen actualizar el número de versión a una nueva versión principal. La notificación avanzada (parte 3) le da tiempo para recibir comentarios de los usuarios finales para averiguar cuánto impacto tendrá ese cambio.


Una solución alternativa es agregar una nueva función que funcione de la manera que desee.

Si es foo()así, crearía fooCorrect()para proporcionar la solución, pero también preservaría completamente la compatibilidad con versiones anteriores. Y en algún momento puedes foo()dejar de usarlo para que otros sepan que no deben usarlo.

El reto que hay que encontrar algo más dentro de fooCorrect()lo que requiere que la actualización y se termina con fooCorrectedCorrect()o algún otro tonterías.

Si realmente quiere que esto se solucione ahora, este enfoque alternativo es probablemente la mejor ruta. Tenga cuidado y desconfíe de crear muchas funciones adicionales de esta manera, ya que hace que sea más difícil trabajar con la API. Y esa conciencia puede ser suficiente para prevenir el peor de estos tipos de problemas.

Pero este podría ser el enfoque "menos malo" a considerar para algo pequeño.


fuente
Estoy de acuerdo contigo. El problema que enfrento es que quiero reescribir completamente la biblioteca para v2.0.0 (porque hay muchos de estos problemas que deben corregirse ); así que no quiero que un cambio tan pequeño como los iteradores formen la base de este gran cambio. Entonces, mis opciones son: ¿ignorar este error, o corregir el error y ponerlo en una nueva versión principal?
Hohner
@hohner: respuesta actualizada para proporcionar un enfoque alternativo con la creación de nuevas funciones. Tenga en cuenta que muchas funciones nuevas con nombres similares son casi tan malas como cambiar la API en sí.
3
@hohner: consistentemente incorrecto> inconsistentemente correcto en este caso. El comportamiento aún funciona, simplemente no es idiomático. Tenga en cuenta que si realiza este cambio, está rompiendo el código del cliente. Hacer esto sin previo aviso no será apreciado.
Phoshi
@ GlenH7 En este caso, usar un método con nombre alternativo no funcionará. El iterador nativo de PHP se basa en estos métodos (es decir, next()no nextCorrect()). Veré si puedo modificar next () para que sea compatible con versiones anteriores Y funcione al implementar la Iteratorinterfaz.
Hohner
1
@Phoshi Estás en lo cierto: estoy completamente de acuerdo ahora Ahora es el momento de tratar de codificar lo imposible: D
hohner