Versione semantica durante la correzione di un bug importante


18

Attualmente gestisco una libreria che ha molto utilizzo pubblico e avevo una domanda sul controllo delle versioni semantico . Voglio riformattare una parte abbastanza importante della libreria che è implementata in modo errato - ed è sempre stata implementata in modo errato. Ma fare questo significherebbe modifiche all'API pubblica, che è una decisione importante.

Il cambiamento che voglio apportare ruota attorno al modo in cui gli iteratori vengono utilizzati. Attualmente, gli utenti devono fare questo:

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

Il che non è corretto, almeno nell'interfaccia Iterator nativa di PHP . Voglio sostituire con questo:

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

che è analogo a:

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

Se guardi la guida di Tom al controllo delle versioni semantico, afferma chiaramente che qualsiasi modifica all'API pubblica (vale a dire quelli che lo sono non compatibili con le versioni precedenti), dovrebbe giustificare una versione importante. Quindi la libreria passerebbe dall'1.7.3 alla 2.0.0 che, per me, è un passo troppo avanti. Stiamo solo parlando di una funzionalità che viene risolta.

Ho intenzione di rilasciare finalmente la 2.0.0, ma pensavo che fosse quando hai riscritto completamente la libreria e implementato numerose modifiche all'API pubblica. L'introduzione di questo refactoring garantisce una versione principale? Non riesco davvero a vedere come va - mi sento più a mio agio nel rilasciarlo come 1.8.0 o 1.7.4. Qualcuno ha qualche consiglio?


Cosa ti impedisce di mantenere la retrocompatibilità?
mouviciel,

Al momento, il next()metodo viene utilizzato per recuperare l'elemento corrente E spostare il puntatore interno in avanti. Che è sbagliato next()dovrebbe spostare il puntatore e current()viene utilizzato per recuperare ...
hohner,

6
quindi nella nuova versione la gente non dovrebbe preoccuparsi del valore di ritorno di next()solo ciò che sposta il puntatore, questo non rompe la compatibilità
maniaco del cricchetto

Risposte:


29

Esiti perché non vuoi fare il versioning semantico, vuoi fare "pubblicità che supporta il versioning". Ti aspetti un numero di versione "2.0" per dire al mondo che hai un sacco di nuove fantastiche funzionalità nella tua libreria ora, non che hai cambiato l'API. Va bene (molte aziende di software e / o sviluppatori lo fanno). IMHO hai le seguenti opzioni:

  • attenersi al controllo delle versioni semantico e convivere con il fatto che è necessario modificare il numero di versione in 2.0.0
  • cambia il tuo schema di versione in 4 numeri. "1.1.7.3" è la tua versione ora, "1.2.0.0" la successiva dopo aver cambiato l'API e "2.0.0.0" la prima della "famiglia di prodotti 2.x completamente nuova"
  • rendere la tua correzione retrocompatibile (quindi non modificare la funzionalità di next, basta aggiungere le funzioni valide current). Quindi è possibile utilizzare "1.8.0" come numero di versione successivo. Se pensi che cambiare il comportamento di nextsia davvero importante, fallo in 2.0.0.

Per quanto l'ultima opzione sarebbe la soluzione perfetta: non puoi chiedere next()di continuare a fare quello che sta facendo. Per implementare correttamente la funzionalità, deve fare qualcosa di diverso. Quindi, se lo rendo compatibile con le versioni precedenti, anche la nuova funzionalità / correzione sarà errata e minerebbe l'intero punto della modifica.
hohner,

2
Il suggerimento più ampio che fai nel tuo terzo proiettile (rendendo compatibile la correzione all'indietro) è una buona considerazione da considerare. Potrebbe non funzionare in questo caso particolare, ma vale la pena considerare la tecnica generale. La funzione finisce per essere più complessa ma questa potrebbe essere una strada praticabile.

Grazie a tutti: se potessi accettarne due, lo farei. Ho finito per hackerare il nuovo next()metodo per fare tutte le nuove funzionalità, oltre a ciò che era necessario per rendere compatibile con le versioni precedenti. È orribile dover offuscare nuove funzionalità come questa, ma ehi.
hohner,

10
@hohner: Ora è anche il momento di documentare il vecchio comportamento come deprecato, quindi puoi rimuoverlo in 2.0.0.
Jan Fabry,

7

Segui la guida di Tom al controllo delle versioni semantiche.

Qualsiasi modifica significativa a un'API pubblica deve essere effettuata in uno dei due punti:

  1. Mai
  2. A un importante aggiornamento della versione

Il mio voto, comunque, è per il primo. Ma riconosco che è appropriato solo per cose insignificanti.

Il problema è mantenere la retrocompatibilità e assicurarsi di non interrompere le cose per gli utenti precedenti della tua API.

In sostanza, stai creando un errore di indicizzazione per i tuoi utenti che non sono consapevoli della modifica. Forzare un cambiamento come questo obbliga tutti i tuoi utenti a fare quanto segue:

  1. Codificare la correzione per utilizzare il nuovo approccio
  2. Convalida la correzione e assicurati che non abbia interrotto nulla
  3. Spedire nuove versioni del loro prodotto agli utenti finali

Questo può potenzialmente essere un grande sforzo, specialmente se si considera il numero di progetti in cui sono in atto casi di test per convalidare cambiamenti come questo. La quantità di sforzo aumenta quando si considera il numero di utenti a valle dei propri utenti che dovranno anche aggiornare le loro installazioni.

Per qualcosa di così piccolo, lo lascerei andare e non mi preoccuperei.
Se ti disturba davvero (cosa che a quanto pare fa o che non avresti chiesto), farei quanto segue.

  1. Crea il ramo v2.0.0 nella tua struttura di codice
  2. Dai il primo contributo al ramo v2.0.0, che è questa modifica
  3. Invia in Release Notesanticipo un'anteprima trasmettendo che il cambiamento sta arrivando

E quindi sii paziente poiché ci vorrà del tempo per accumulare altre cose che giustificano l'aggiornamento del numero di versione a una nuova versione principale. La notifica avanzata (parte 3) ti dà il tempo di ricevere feedback dagli utenti finali per scoprire quale impatto avrà il cambiamento.


Una soluzione alternativa è quella di aggiungere una nuova funzione che opera nel modo desiderato.

Se lo foo()hai, crei fooCorrect()per fornire la correzione ma anche per preservare completamente la compatibilità con le versioni precedenti. E ad un certo punto puoi deprecare foo()per far sapere agli altri di non usarlo.

La sfida è che troverai qualcos'altro all'interno del fooCorrect()quale è necessario il suo aggiornamento e alla finefooCorrectedCorrect() o qualche altra sciocca sciocchezza.

Se vuoi davvero risolverlo ora, questo approccio alternativo è probabilmente il percorso migliore. Sii consapevole e diffida della creazione di molte funzioni extra in questo modo poiché rende l'API più difficile da lavorare. E quella consapevolezza può essere sufficiente per prevenire il peggio di questi tipi di problemi.

Ma questo potrebbe essere l'approccio "meno cattivo" da considerare per qualcosa di piccolo.


Sono d'accordo con te. Il problema che devo affrontare è che voglio riscrivere completamente la libreria per v2.0.0 (perché ci sono molti di questi problemi che devono essere risolti); quindi non voglio che un piccolo cambiamento come gli iteratori costituisca la base di questo grande cambiamento. Quindi le mie opzioni sono: ignorare questo errore o correggere l'errore e inserirlo in una nuova versione principale?
Hohner,

@hohner: risposta aggiornata per fornire un approccio alternativo alla creazione di nuove funzioni. Ricorda che molte nuove funzioni, con nomi simili, sono quasi dannose come cambiare l'API stessa.

3
@hohner: coerentemente sbagliato> incoerentemente giusto in questo caso. Il comportamento funziona ancora, semplicemente non è idiomatico. Considera che se apporti questa modifica stai infrangendo il codice client. Fare questo senza preavviso non sarà apprezzato.
Phoshi,

@ GlenH7 In questo caso, l'utilizzo di un metodo con nome alternativo non funzionerà. L'iteratore nativo di PHP si basa su questi metodi (cioè next()non nextCorrect()). Vedrò se posso modificare next () in modo che sia compatibile con le versioni precedenti e funzioni durante l'implementazione Iteratordell'interfaccia.
Hohner,

1
@Phoshi Sei perfetto - Sono completamente d'accordo ora. Ora è il momento di provare a scrivere l'impossibile: D
hohner,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.