Alterações interruptivas
É importante para uma biblioteca .NET encontrar um equilíbrio entre estabilidade para usuários existentes e inovação para o futuro. Os autores de bibliotecas inclinam-se para refatoração e repensar o código até que ele seja perfeito, mas quebrar seus usuários existentes tem um impacto negativo, especialmente para bibliotecas de baixo nível.
Tipos de projeto e alterações significativas
A forma como uma biblioteca é usada pela comunidade .NET altera o efeito das alterações de quebra nos desenvolvedores de usuários finais.
Bibliotecas de nível baixo e médio, como um serializador, analisador HTML, mapeador objeto-relacional de banco de dados ou estrutura da Web são as mais afetadas por alterações de quebra.
Os pacotes de blocos de construção são usados por desenvolvedores de usuários finais para criar aplicativos e por outras bibliotecas como dependências do NuGet. Por exemplo, você está criando um aplicativo e está usando um cliente de código aberto para chamar um serviço Web. Uma atualização de quebra para uma dependência que o cliente usa não é algo que você possa corrigir. É o cliente de código aberto que precisa ser alterado e você não tem controle sobre ele. Você tem que encontrar versões compatíveis das bibliotecas ou enviar uma correção para a biblioteca do cliente e esperar por uma nova versão. A pior situação é se você quiser usar duas bibliotecas que dependem de versões mutuamente incompatíveis de uma terceira biblioteca.
Bibliotecas de alto nível, como um conjunto de controles de interface do usuário, são menos sensíveis a alterações de quebra.
As bibliotecas de alto nível são referenciadas diretamente em um aplicativo de usuário final. Se ocorrerem alterações de quebra, o desenvolvedor pode optar por atualizar para a versão mais recente ou pode modificar seu aplicativo para trabalhar com a alteração de quebra.
✔️ PENSE em como sua biblioteca será usada. Que efeito terão as alterações significativas nas aplicações e bibliotecas que o utilizam?
✔️ MINIMIZE as alterações significativas ao desenvolver uma biblioteca .NET de baixo nível.
✔️ CONSIDERE publicar uma grande reescrita de uma biblioteca como um novo pacote NuGet.
Tipos de alterações de quebra
As mudanças de quebra se enquadram em diferentes categorias e não são igualmente impactantes.
Alteração de quebra de fonte
Uma alteração de quebra de fonte não afeta a execução do programa, mas causará erros de compilação na próxima vez que o aplicativo for recompilado. Por exemplo, uma nova sobrecarga pode criar uma ambiguidade em chamadas de método que eram inequívocas anteriormente, ou um parâmetro renomeado interromperá chamadores que usam parâmetros nomeados.
public class Task
{
// Adding a type called Task could conflict with System.Threading.Tasks.Task at compilation
}
Como uma alteração de quebra de fonte só é prejudicial quando os desenvolvedores recompilam seus aplicativos, é a alteração de quebra menos perturbadora. Os desenvolvedores podem corrigir seu próprio código-fonte quebrado facilmente.
Mudança de comportamento
As mudanças de comportamento são o tipo mais comum de mudança de quebra: quase qualquer mudança de comportamento pode causar um erro de lógica para um consumidor. Alterações na biblioteca, como assinaturas de método, exceções lançadas ou formatos de dados de entrada ou saída, podem afetar negativamente os consumidores da biblioteca. Até mesmo uma correção de bug pode ser qualificada como uma alteração de quebra se os usuários confiarem no comportamento quebrado anteriormente.
Adicionar recursos e melhorar maus comportamentos é uma coisa boa, mas sem cuidado pode tornar muito difícil para os usuários existentes atualizar. Uma abordagem para ajudar os desenvolvedores a lidar com alterações de quebra de comportamento é escondê-las atrás das configurações. As configurações permitem que os desenvolvedores atualizem para a versão mais recente da sua biblioteca e, ao mesmo tempo, optem por aceitar ou desativar as alterações. Essa estratégia permite que os desenvolvedores permaneçam atualizados, permitindo que seu código de consumo se adapte ao longo do tempo.
Por exemplo, ASP.NET Core MVC tem o conceito de uma versão de compatibilidade que modifica os recursos habilitados e desabilitados no MvcOptions
.
✔️ CONSIDERE deixar novos recursos desativados por padrão, se eles afetarem usuários existentes, e permitir que os desenvolvedores optem pelo recurso com uma configuração.
Para obter mais informações sobre alterações de quebra de comportamento em APIs .NET, consulte Compatibilidade de alterações comportamentais do .NET.
Alteração de quebra binária
Uma alteração de quebra binária acontece quando você altera a API pública da sua biblioteca, de modo que os assemblies compilados em versões mais antigas da sua biblioteca não podem mais chamar a API. Por exemplo, alterar a assinatura de um método adicionando um novo parâmetro fará com que assemblies compilados na versão mais antiga da biblioteca lancem um MissingMethodExceptionarquivo .
Uma alteração de quebra binária também pode quebrar um conjunto inteiro. Renomear um assembly com AssemblyName
mudará a identidade do assembly, assim como adicionar, remover ou alterar a chave de nomenclatura forte do assembly. Uma alteração da identidade de um assembly quebrará todo o código compilado que o usa.
❌ NÃO altere um nome de assembly.
❌ NÃO adicione, remova ou altere a chave de nomenclatura forte.
✔️ CONSIDERE o uso de classes base abstratas em vez de interfaces.
Adicionar qualquer coisa a uma interface fará com que os tipos existentes que a implementam falhem. Uma classe base abstrata permite adicionar uma implementação virtual padrão.
✔️ CONSIDERE colocar os ObsoleteAttribute tipos e membros que você pretende remover. O atributo deve ter instruções para atualizar o código para não usar mais a API obsoleta.
O código que chama tipos e métodos com o ObsoleteAttribute irá gerar um aviso de compilação com a mensagem fornecida ao atributo. Os avisos dão às pessoas que usam a API obsoleta tempo de migração para que, quando a API obsoleta for removida, a maioria não a esteja mais usando.
public class Document
{
[Obsolete("LoadDocument(string) is obsolete. Use LoadDocument(Uri) instead.")]
public static Document LoadDocument(string uri)
{
return LoadDocument(new Uri(uri));
}
public static Document LoadDocument(Uri uri)
{
// Load the document
}
}
✔️ CONSIDERE manter tipos e métodos com o ObsoleteAttribute indefinidamente em bibliotecas de nível baixo e médio.
A remoção de APIs é uma alteração de quebra binária. Considerar manter tipos e métodos obsoletos se mantê-los for de baixo custo e não adicionar muita dívida técnica à sua biblioteca. Não remover tipos e métodos pode ajudar a evitar os piores cenários mencionados acima.
Para obter mais informações sobre quais alterações da API do .NET quebram a compatibilidade binária, consulte Compatibilidade de contrato público do .NET.