Controle de versão semântico ao corrigir um bug importante

18

Atualmente, gerencio uma biblioteca que tem muito uso público e tive uma pergunta sobre o controle de versão semântico . Quero refatorar uma parte bastante importante da biblioteca que é implementada incorretamente - e sempre foi implementada incorretamente. Mas fazer isso significaria alterações na API pública, que é uma decisão importante.

A mudança que eu quero fazer gira em torno de como os iteradores são usados. Atualmente, os usuários precisam fazer isso:

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

O que está incorreto, pelo menos na interface Iterator nativa do PHP . Eu quero substituir por isso:

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

que é análogo a:

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

Se você olhar o guia de Tom para versões semânticas, ele afirma claramente que qualquer alteração na API pública (ou seja, aquelas que não são compatíveis com versões anteriores) deve justificar uma versão importante. Portanto, a biblioteca saltaria de 1.7.3 para 2.0.0, o que, para mim, é um passo longe demais. Estamos falando apenas de um recurso que está sendo corrigido.

Tenho planos de finalmente lançar a 2.0.0, mas pensei que era quando você reescrevia completamente a biblioteca e implementava inúmeras alterações de API pública. A introdução dessa refatoração justifica o lançamento de uma versão principal? Realmente não consigo ver como funciona - me sinto mais confortável em liberá-lo como 1.8.0 ou 1.7.4. Alguém tem algum conselho?

Hohner
fonte
O que impede você de manter a compatibilidade com versões anteriores?
Mouviciel 28/11
No momento, o next()método é usado para recuperar o elemento atual E mover o ponteiro interno para frente. O que está errado. next()deve mover o ponteiro, e current()é usado para recuperar ...
hohner
6
assim na nova versão as pessoas não devem se preocupar com o valor de retorno next()só isso é move o ponteiro, isso realmente não quebrar a compatibilidade
catraca aberração

Respostas:

29

Você hesita porque não deseja criar versões semânticas, deseja criar "anúncios que suportam versões". Você espera que o número da versão "2.0" diga ao mundo que você tem um monte de novos recursos interessantes em sua biblioteca agora, não que tenha alterado a API. Tudo bem (muitas empresas de software e / ou desenvolvedores fazem isso). IMHO você tem as seguintes opções:

  • atenha-se ao controle de versão semântico e convide com o fato de que você deve alterar o número da versão para 2.0.0
  • altere seu esquema de versão para 4 números. "1.1.7.3" é sua versão agora, "1.2.0.0" o próximo após alterar a API e "2.0.0.0" o primeiro da "família de produtos 2.x completamente nova"
  • torne sua correção compatível com versões anteriores (portanto, não altere a funcionalidade next, basta adicionar as funções valide current). Então você pode usar "1.8.0" como o próximo número da versão. Se você acha que mudar o comportamento de nexté realmente importante, faça-o na 2.0.0.
Doc Brown
fonte
Tanto quanto a última opção seria a solução perfeita: você não pode pedir next()para continuar fazendo o que está fazendo. Para implementar a funcionalidade corretamente, é preciso fazer algo diferente. Portanto, se eu torná-lo compatível com versões anteriores - a nova funcionalidade / correção também estará errada e prejudicará todo o ponto da alteração.
hohner
2
A sugestão mais ampla que você faz em seu terceiro marcador (tornando a correção compatível com versões anteriores) é boa a considerar. Pode não funcionar nesse caso específico, mas vale a pena considerar a técnica geral. A função acaba sendo mais complexa, mas pode ser uma rota viável.
Obrigado a todos: se eu pudesse aceitar dois, aceitaria. Acabei invadindo o novo next()método para fazer todas as novas funcionalidades, além do necessário para tornar a compatibilidade com versões anteriores. Parece horrível ter que manchar novas funcionalidades como essa, mas ei.
hohner
10
@hohner: Agora também é hora de documentar o comportamento antigo como obsoleto, para que você possa removê-lo no 2.0.0.
Jan Fabry
7

Fique com o guia de Tom para versões semânticas.

Qualquer alteração significativa em uma API pública deve ser feita em um dos dois pontos:

  1. Nunca
  2. Em uma grande atualização de lançamento

Meu voto, a propósito, é o primeiro. Mas reconheço que isso é apropriado apenas para coisas triviais.

O problema é manter a compatibilidade com versões anteriores e garantir que você não quebre as coisas para os usuários anteriores da sua API.

Em essência, você está criando um erro de indexação para seus usuários que desconhecem a alteração. Forçar uma alteração como essa força todos os usuários a fazer o seguinte:

  1. Codifique a correção para usar a nova abordagem
  2. Valide a correção e verifique se não quebrou nada
  3. Envie novos lançamentos de seus produtos para seus usuários finais

Isso pode ser um grande esforço, especialmente quando você considera o quão poucos projetos possuem casos de teste para validar alterações como essa. A quantidade de esforço aumenta quando você considera o número de usuários downstream de seus usuários que também precisarão atualizar suas instalações.

Para algo tão pequeno, eu deixaria passar e não me incomodaria.
Se isso realmente incomoda você (o que aparentemente incomoda ou você não teria perguntado), eu faria o seguinte.

  1. Crie a ramificação v2.0.0 na sua árvore de códigos
  2. Faça a primeira contribuição para a ramificação v2.0.0, que é essa alteração
  3. Envie uma prévia Release Notesantecipando a transmissão de que a mudança está chegando

E então seja paciente, pois levará um tempo para acumular outras coisas que justifiquem a atualização do número da versão para uma nova versão principal. A notificação avançada (parte 3) permite que você receba feedback dos usuários finais para descobrir quanto impacto essa mudança terá.


Uma solução alternativa é adicionar uma nova função que funcione da maneira que você deseja.

Se você tiver foo(), você criaria fooCorrect()para fornecer a correção, mas também preservar totalmente a compatibilidade com versões anteriores. E em algum momento você pode se preterir foo()para que outras pessoas saibam que não deve usá-lo.

O desafio é que você encontrará outra coisa na fooCorrect()qual precisa ser atualizada e você teráfooCorrectedCorrect() outras bobagens bobas.

Se você realmente quer isso seja corrigido agora, essa abordagem alternativa é provavelmente a melhor rota. Esteja ciente e cauteloso de criar muitas funções extras dessa maneira, pois torna a API mais difícil de trabalhar. E essa conscientização pode ser suficiente para evitar o pior desses tipos de problemas.

Mas essa pode ser a abordagem "menos ruim" a considerar para algo pequeno.


fonte
Eu concordo com você. O problema que enfrento é que desejo reescrever completamente a biblioteca da v2.0.0 (porque há muitos desses problemas que precisam ser corrigidos); portanto, não quero que uma mudança tão pequena como iteradores forme a base dessa grande mudança. Portanto, minhas opções são: ignorar esse bug ou corrigi-lo e colocá-lo em uma nova versão principal?
hohner
@hohner - resposta atualizada para fornecer uma abordagem alternativa com a criação de novas funções. Lembre-se de que muitas funções novas com nomes semelhantes são quase tão ruins quanto alterar a própria API.
3
@hohner: Consistentemente errado> inconsistentemente certo neste caso. O comportamento ainda funciona, apenas não é idiomático. Considere que, se você fizer essa alteração, está quebrando o código do cliente. Fazer isso sem aviso não será apreciado.
Phoshi #
@ GlenH7 Neste caso, a utilização de um método nomeado alternativamente não funcionará. O iterador nativo do PHP depende desses métodos (ou seja, next()não nextCorrect()). Vou ver se consigo modificar next () para que seja compatível com versões anteriores E funcione ao implementar a Iteratorinterface.
hohner
1
@ Phoshi Você está no lugar - eu concordo completamente agora. Agora é hora de tentar codificar o impossível: D
hohner 28/11