Design: Como evitar a quebra da compatibilidade com versões anteriores devido a alterações no banco de dados

8

Este é o meu cenário, tenho esta interface:

public interface hitTheDataBase
{
    public void insertMe(String [] values);
    public void modifyMe(String [] values);
    public DataTable selectMe();
}

E eu tenho essas duas classes que implementam a interface:

public Class hitSqlServer implements hitTheDatabase
{
    public void insertMe(String [] values)
    {
         executes insert into table_in_sqlServerBD (col1, col2) values(values[0], values[1])
    }
    public void modifyMe(String [] values)
    {
         executes update table_in_sqlServerBD set col1 = values[0], col2 =  values[1] where rowid = values[3]
    }

    public DataTable selectMe()
    {
         executes select col1, col2 from table_in_sqlServerBD
    }
}

public Class hitSqLite implements hitTheDatabase
{
    public void insertMe(String [] values)
    {
         executes insert into table_in_sqLite (col1, col2) values(values[0], values[1])
    }
    public void modifyMe(String [] values)
    {
         executes update table_in_sqlLite set col1 = values[0], col2 =  values[1] where rowid = values[3]
    }

    public DataTable selectMe()
    {
         executes select col1, col2 from table_in_sqLite
    }
}

Isso faz parte de um aplicativo beta realmente em execução em ambientes de teste e produção (!), Mas será atualizado regularmente devido a correções de bugs não relacionadas às operações do banco de dados. As atualizações são feitas simplesmente através da desinstalação e reinstalação.

Agora, eu tenho um novo requisito para uma situação de canto muito específica que precisará que uma nova coluna "col3" seja adicionada à tabela e terei que inserir, selecionar e atualizar valores nessa coluna também. O problema é que não quero interromper a compatibilidade com os bancos de dados existentes em que o software já está sendo executado.

Eu estava pensando em codificar uma terceira classe que implementa a interface HitTheDataBase, uma classe auxiliar para verificar se "col3" existe e criar algo como:

hitTheDataBase hitMe = !helperclass.col3Exists() ? new hitSqlServer() : new hitSqlServerWithCol3();

Será esta uma boa abordagem? Parece bom para mim, exceto porque precisarei modificar o código nas classes que usam aquelas que "atingem o banco de dados". Também terei que verificar constantemente se o valor de col3 existe para mostrá-lo na GUI e permitir que o usuário o modifique.

Janela quebrada
fonte
2
Ainda será uma boa abordagem se você precisar fazer isso mais 15 vezes?
precisa
@DanPichelman nope, Ben está certo: Design olfato :(
Broken_Window
O código de exemplo é tão ruim que eu respirei fundo quando o vi.
Graham
@Graham é um horrendo Java / C # seudocode feitas dessa forma para não divulgar código proprietária
Broken_Window

Respostas:

11

Quando suas atualizações de software são implantadas, existe algum motivo para você também não poder atualizar seu esquema? Uma alteração no software que requer uma alteração no esquema do banco de dados implica que o esquema deve mudar no sistema de destino.

A compatibilidade com versões anteriores de versões anteriores de um esquema de banco de dados é normalmente algo a ser evitado, e invadir sua Camada de Acesso a Dados para suportar várias versões de esquema parece um cheiro de design.

Uma solução mais limpa é garantir que seu código esteja sempre em execução na versão do esquema para o qual esse código foi gravado. Isso não apenas tornará o código mais fácil de escrever e manterá o código mais limpo, como também facilitará o teste. Você pode incluir scripts de migração como parte do processo de instalação / desinstalação para atualização e reversão.

Seu esquema inclui algum tipo de tabela de versão? Caso contrário, você precisará adicionar uma tabela de versão do esquema o mais rápido possível. A versão do esquema é vital para atualizações e reversões.

Por um longo período, você provavelmente terminará com muitos scripts de atualização de esquema que precisarão ser executados em uma ordem específica durante a instalação / desinstalação. Um mecanismo de versão do esquema é essencial para garantir que as atualizações e reversões do esquema sejam executadas sem problemas.

Por outro lado, se você não tiver um mecanismo para manter seu esquema atualizado com a versão do software, sua Camada de Acesso a Dados poderá eventualmente explodir em complexidade à medida que você se deparar com um número crescente de "hacks" para preservar o atraso compatibilidade; e você será sobrecarregado com uma sobrecarga cada vez maior de testes de regressão toda vez que alterar algo em seu esquema.

Ben Cottrell
fonte
1

É o que acontece se o esquema do banco de dados não corresponder a uma versão do aplicativo. Qualquer aplicativo que obtiver o novo código col3 deve ter o banco de dados atualizado junto com ele.

Se você tiver o problema de verificar se existe uma coluna em uma tabela, crie-a durante a atualização para a versão mais recente.

JeffO
fonte
Você está certo, o aplicativo e o esquema bd devem corresponder. Eu fiz a "criação de colunas ausentes" no passado. Funciona apenas se o usuário que estou usando para a conexão com o banco de dados tiver privilégios suficientes, e esse nem sempre é o caso.
22416 Broken_Window
Em seguida, o administrador do sistema precisa executar o script de atualização que você está fornecendo.
precisa
@RubberDuck, essa é a solução que eu usei. Incluí os scripts de atualização com os arquivos de instalação e como atualizar o banco de dados no manual do usuário.
Broken_Window
1

Eu diria que não.

Esse tipo de [infinita] "se, mas, talvez, a menos que, exceto" a lógica apenas o levará à loucura e, talvez mais importante, desacelere seu aplicativo, porque todas essas "verificações" estão sendo executadas em tempo de execução.

Eu sugiro versionamento as alterações de esquema e armazenar essa versão [número] em algum lugar no banco de dados (como parte de seu progresso upgrade).

Crie uma versão da sua classe de acesso a dados para cada versão do banco de dados.

No tempo de execução, interrogue o banco de dados quanto à versão do esquema e instancie a classe "correta" com base nisso.

Phill W.
fonte
2
Você pode mencionar que sua última frase é uma referência ao padrão de estratégia .
TMN