Existem exemplos de abordagens não CRUD?

14

Sou programador mas também trabalhei como arquivista. Como arquivista, é muito importante manter os dados.

Costumo entrar em discussões com colegas quando se trata de operações em dados. Eu não gosto muito do U e do D no CRUD. Em vez de atualizar um registro, prefiro adicionar um novo e ter uma referência ao registro antigo. Dessa forma, você constrói um histórico de mudanças. Também não gosto de excluir registros, mas sim marcá-los como inativos.

Existe um termo para isso? Basicamente apenas criando e lendo dados? Existem exemplos dessa abordagem?

    
por Pieter B 16.11.2012 / 18:57
fonte

8 respostas

16

A marcação de um registro como excluído é conhecida como exclusão automática . Eu nunca ouvi uma frase alternativa para atualização, mas acho que isso faz com que você delete o registro antigo e crie um novo.

Deve-se notar que esta é uma técnica controversa. Veja os links: Con vs Pro .

    
por 16.11.2012 / 19:02
fonte
11

Um dos problemas em manter um histórico de alterações é que ele sobrecarrega o banco de dados e pode aumentar drasticamente seu tamanho (dependendo dos padrões de uso). Portanto, uma boa ideia seria armazenar a trilha de auditoria em um local separado e manter as tabelas de aplicativos reais preenchidas somente com dados relevantes. Portanto, cada vez que uma operação CRUD é executada pelo aplicativo, a alteração é registrada nas tabelas de auditoria e a operação CRUD é executada nas tabelas de aplicativos (sem exclusões suaves).

Manter a trilha de auditoria separada fornece um armazenamento de dados novo para o aplicativo interagir, mantendo o histórico de alterações caso você precise. Você também pode arquivar a trilha de auditoria separadamente ou até mesmo destruí-la, dependendo dos requisitos do seu negócio.

    
por 16.11.2012 / 19:59
fonte
5

EventSourcing parece o padrão que você pode estar procurando.

Vamos dar um exemplo usando um objeto "carro" simples que gostaríamos de acompanhar a cor do código (pseudo código C # segue).

public class Car {
  public string Color { get; set; }
  public Car() { this.Color = "Blue"; }
}

Com uma implementação de CRUD quando atualizamos a cor do carro, a cor anterior seria perdida.

MyCar.Color = "Red";
MyCar.Save();  // Persist the update to the database and lose the previous data

Essa perda de informações parece-me o que você mais gostaria de evitar (daí a antipatia pela atualização e exclusão de parte do padrão CRUD).

Se tivéssemos que reescrever a classe de carro para responder aos eventos ao atualizar sua alteração, ela ficaria assim:

public class Car {
    public string Color { get; private set; } // Cannot be set from outside the class

    public void ApplyEvent(CarColorChangedEvent e) {
      this.Color = e.Color;
    }
}

Agora, como podemos atualizar a cor desse objeto? Poderíamos criar um evento CarColorChanged !

var evnt = new CarColorChangedEvent("Red");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

Observe a falta de um salvamento no objeto do modelo real? Isso porque, em vez de persistir o modelo diretamente, persistimos os eventos que colocam o modelo no estado atual. Esses eventos devem ser imutáveis .

Agora vamos avançar e mudar a cor mais algumas vezes:

var evnt = new CarColorChangedEvent("Green");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

var evnt = new CarColorChangedEvent("Purple");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

Se fôssemos examinar nosso armazenamento de eventos (poderia ser um banco de dados de relacionamentos, baseado em arquivo, etc.), veríamos uma série de eventos relacionados ao nosso objeto carro:

CarColorChangedEvent => Red
CarColorChangedEvent => Green
CarColorChangedEvent => Purple

Se quiséssemos reconstruir o objeto carro, poderíamos fazê-lo simplesmente criando um novo objeto carro e aplicando os eventos do nosso armazenamento de evento ao objeto mencionado.

var MyCar = new Car();
var events = MyDatabase.SelectEventsForCar("CarIdentifierHere");
foreach(var e in events) {
  MyCar.ApplyEvent(e);
}
Console.WriteLine(MyCar.Color); // Purple

Com o fluxo de eventos, podemos reverter o estado do carro para um período de tempo anterior simplesmente criando um novo objeto de carro e aplicando apenas os eventos que desejamos:

var MyCar = new Car();
var event = MyDatabase.GetFirstEventForCar("CarIdentifierHere");
MyCar.ApplyEvent(e);
Console.WriteLine(MyCar.Color); // Red
    
por 16.11.2012 / 23:17
fonte
5

O Event Sourcing é o caminho a seguir e você deve dar uma olhada no que Greg Young tem a dizer sobre isso.

link

Veja também esta apresentação em seu banco de dados (Event Store). Você também pode encontrar outros vídeos.

link

Eu não optaria pela resposta "exclusões de software", a menos que você precise pesquisar itens excluídos, mas não pense neles como excluídos, mas sim arquivados. Eu acho que a terminologia é muito importante aqui.

Eu também não gostaria de manter uma "tabela de versões". Todas as "tabelas de versões" que eu já vi (incluindo a que estou tentando limpar no momento - 7 anos de dados corrompidos por causa de bugs ... e nenhuma maneira de recuperá-los, mesmo que tenhamos histórico dados ... porque isso é tão corrupto) acaba corrompido devido a erros no código e no final você ainda perde dados porque você não pode voltar atrás e recriar os dados que a corrupção confundiu. / p>

Com o modelo de terceirização de eventos, esse não é o caso. Você sempre pode reproduzir exatamente o que o usuário fez. Esta é a diferença muito importante entre o CRUD e o Event Sourcing. A arquitetura Event Sourcing salva eventos em um armazenamento de eventos e não em objetos de dados ou objetos de modelo de domínio. Um evento pode afetar facilmente vários objetos. Basta pensar em uma solução de carrinho de compras em que você converte cada item no carrinho de compras em um pedido real. Um evento afeta todos os objetos de item, bem como os objetos do carrinho de compras, que são transformados em um objeto de pedido.

Se você mantivesse uma cópia com versão de cada linha em todas as tabelas do banco de dados, imagine o horror de ter que voltar a um timestamp específico, sem mencionar a quantidade insana de espaço e sobrecarga de desempenho na manutenção dessa tabela de versões. / p>

Com o Event Sourcing, você pode retroceder facilmente, apenas reproduzindo eventos até um certo ponto no tempo. Avanços rápidos podem ser implementados usando snapshots, mas isso é tudo uma questão de implementação.

Mas a vantagem real que eu acho que você vai gostar, visto que você está particularmente interessado em não perder dados, é que se você descobrir um bug no código que salva esses dados, então você não precisa voltar atrás. limpar os dados (o que geralmente é impossível porque os dados quase nunca estão completos). Em vez disso, corrija o bug e repita todos os eventos. Então você terá um banco de dados com bons dados corretos.

Em caso de depuração, quantas vezes você pediu ao usuário para lhe dizer o que eles fizeram ... porque não apenas reproduzir o que eles fizeram e, em seguida, percorrendo o código! Muito bonito, huh.

Espero que isso ajude.

    
por 17.11.2012 / 00:39
fonte
2

Não é exatamente o seu exemplo, mas em sistemas financeiros mais antigos você tinha o armazenamento WORM . Se você precisasse "atualizar", você escreveu um novo registro e sempre se referiu ao último registro como atual, mas nenhum dado confirmado poderia ser substituído.

Muitas pessoas levaram essa ideia para os sistemas posteriores. Eu ouvi o que você está descrevendo como tabelas WORM, mas apenas nesses círculos.

    
por 16.11.2012 / 20:36
fonte
2

Sim, é bastante comum em sistemas corporativos há basicamente duas abordagens: -

  • "bi-temporal" em que cada registro tem um carimbo de data válido e válido para a data e hora (o registro "atual" tem uma data válida de "para sempre" - nulo, "9999-12-31" ou algo assim valor). Os registros nunca são excluídos, em vez disso, a data "válida para" é definida para a hora atual e, no caso de uma atualização, um novo registro é inserido com uma data válida da hora atual e uma validade válida até a data.
  • "tabela de histórico" - toda vez que um registro é alterado, uma cópia do registro antigo é despejada em uma tabela de histórico / log com um registro de data e hora para o evento.

Existem grandes variações na granularidade para ambas as abordagens. por exemplo. Se a quantidade de widgets em um item do pedido for alterada, você mantém o histórico do pedido inteiro ou apenas desse item?

Em geral, "bi-temporal" é muito trabalho extra e só vale a pena se você tiver muitos casos de uso como "o auditor obtém o status do pedido em 31 de dezembro".

    
por 15.08.2014 / 04:18
fonte
1

Você pode usar "exclusões de software" como sugerido pelo pdr . Quanto às atualizações, você pode manter o histórico de registros, mais ou menos como minha resposta aqui: link onde o OP queria poder acompanhar todas as versões de certos tipos de dados.

    
por 16.11.2012 / 19:37
fonte
-2

basicamente, o crud não pode ser concluído sem essas 4 coisas. Crud significa criar, ler, atualizar e excluir assim quando você está apenas tentando ler dados, você pode usar a consulta simples para isso, mas todas essas três coisas estão ligadas a um e outros conceitos simples de banco de dados

    
por 17.11.2012 / 07:39
fonte