O que fazer quando você não pode determinar um valor booleano?

38

Estamos criando um aplicativo Web para empresa, cuja administração existia apenas nas planilhas do Excel até o momento. Já estamos quase terminando agora, mas recentemente recebi uma tarefa para importar todos os dados dessas planilhas para o nosso novo sistema. O sistema é construído em Java, mas como essa importação é apenas uma vez, decidi escrever os scripts em Python e importá-lo diretamente com consultas SQL. Aí vem o problema. Os novos modelos de dados contêm alguns novos atributos, que não são incluídos nos dados existentes. Na maioria dos casos, isso não é um problema, basta colocar um nulo onde não consigo encontrar as informações. Mas então eu encontrei alguns atributos, que são booleanos e não podem ser NULL por padrão. Primeiro, tentei apenas permitir nulo para esses campos em nosso banco de dados, mas meu desenvolvedor sênior me disse para não fazê-lo, pois isso causaria problemas em nosso sistema no futuro. E agora não tenho muita certeza do que fazer. A solução óbvia é padronizar todos os valores booleanos desconhecidos como false, mas acho que isso também está errado, porque na verdade eu não sei se é falso.

Exemplo: Digamos que você tenha uma entidade Car que tenha um parâmetro hasRadio. Agora você precisa importar dados para esse modelo de dados, mas nos dados existem apenas as colunas "Modelo" e "Cor", nada sobre ter ou não rádio. O que você coloca em uma coluna "hasRadio", se não puder ser nula por design?

Qual é a melhor abordagem nesta situação? Devemos apenas dizer à empresa para preencher manualmente os dados ausentes? Ou o padrão é false?

Liberul
fonte
70
Para mim, permitir NULL seria a solução correta. Seu idoso foi mais específico do que "causar um problema em nosso sistema no futuro"? Caso contrário, pergunte a ele por razões mais específicas.
Larsbe
48
Você deve usar como padrão FileNotFound, obviamente.
Você
7
Seria possível adicionar um campo booleano, "isValidHasRadio" ou algo assim, ou isso também quebraria as coisas?
Hyde
9
A solução correta é considerar o lixo de dados de entrada e abortar toda a transação e, em seguida, exigir que a definição da tarefa seja ajustada se esses dados não puderem ser considerados lixo. Não há outro caminho aqui.
Sarge Borsch
17
A propósito, não sou muito fã de valores nulos. Prefiro usar uma enumeração com 'Desconhecido', 'Possui rádio' e 'Não possui rádio'. Dessa forma, você atende às suas necessidades e tem espaço para crescer se precisar especificar um tipo de rádio no futuro, como 'Rádio com TV integrada' ou algo assim.
Machado

Respostas:

129

Isso é principalmente um problema de análise de requisitos e não tem nada a ver com o fato de os dados em jogo serem "booleanos". Se você precisar inicializar tabelas em um banco de dados ou em qualquer outro tipo de armazenamento de dados e tiver entradas incompletas para algumas colunas, primeiro precisará descobrir qual é o valor padrão correto para os usuários do sistema ou seu cliente. para essas colunas e você precisa descobrir isso para cada atributo , geralmente não há uma resposta correta.

Isso normalmente leva a um dos seguintes casos:

  • existe um bom valor padrão para a coluna específica, os usuários não se importam se o valor é inicialmente o mesmo para todos os registros, eles podem definir os valores corretos facilmente depois, quando necessário

  • existe uma regra de como determinar o valor padrão ideal de outras informações, para que você possa colocar essa regra no código

  • os usuários ou seu cliente estenderão os dados de entrada e fornecerão os valores ausentes (talvez manualmente), antes de serem importados para o banco de dados

  • não existe um bom valor padrão para a coluna específica e / ou qualquer registro, os dados também devem ser importados, mas os usuários desejam saber para qual dos registros o valor específico já foi inicializado e para o que não. Assim, eles podem inserir o valor posteriormente e rastrear para quais registros o valor já está definido corretamente e para o que não.

O último caso requer algo como NULL para representar o estado não inicializado ou desconhecido, mesmo para um valor booleano, se o idoso gosta ou não. Se houver algum motivo técnico obscuro que proíba o uso de um valor NULL para uma coluna específica, você precisará simular o estado "desconhecido" de uma maneira diferente, introduzindo uma coluna booleana adicional (como hasRadioIsUnknown) ou usando um 3 enumeração -valued em vez de um booleano (como HasNoRadio=0, HasRadio=1, Unknown=2). Mas fale com seu sénior novamente, depois de fazer uma análise completa dos requisitos, para garantir que essa solução alternativa seja realmente necessária.

Doc Brown
fonte
29
Você também deve observar que a mesma resposta se aplica às outras colunas em que você convenientemente usou NULL. Você deve verificar se esse é o valor padrão correto. Se, por exemplo, alguma outra coluna indicar "processingIsFinished" e você importar dados antigos do histórico de pedidos dos clientes (pensando em uma loja virtual), poderá ser necessário definir o valor como "true" em vez de "NULL" para evitar que alguns processos sejam acionados quando encontrarem entradas ainda não processadas (de acordo com a interpretação dessa coluna).
Frank Hopkins
1
Este é um problema funcional. Como os modelos (excelente e o novo) não coincidem, o processo de migração deve ser revisado levando em consideração esses casos. O único que pode dizer como proceder é / são as partes interessadas (cliente ou quem). Tecnicamente, você pode resolver isso de várias maneiras, mas funcionalmente apenas em uma. O certo.
LAIV
12
Eu gosto desse colapso. Minha aversão a nulo nesse contexto deve-se principalmente à falta de um significado claro. Desconhecido é claro. Mas nulo significa desconhecido ou não aplicável? Como alguém saberia? Só porque faz sentido para você, não significa que todo mundo verá da mesma maneira.
Candied_orange 17/08
Opção 4: Os registros que faltam um valor específico da coluna são realmente inúteis e devem ser excluídos da importação. Opção 5: alguém precisa corrigir todos os dados recebidos antes de serem importados. Muitas opções, depende apenas de necessidades e orçamentos. Importar dados antigos é sempre uma grande bagunça.
precisa saber é o seguinte
@ jpmc26: bem, eu não incluí a opção 4, pois queria manter o que o OP literalmente escreveu (um caso em que os dados ausentes definitivamente não são incluídos nos dados de importação, sem registro). Vale a pena mencionar a opção 5, pois é outra maneira de evitar a necessidade de valores NULL. Editou minha resposta de acordo.
Doc Brown
39

Esta não é uma questão técnica; é uma questão de regras de negócios. Então, você precisa perguntar "aos negócios".

Aborde o proprietário do produto e / ou as partes interessadas e diga algo como:

Temos dados incompletos para um dos campos que você solicitou no aplicativo. Deseja que usemos um valor padrão? Deseja que adicionemos "desconhecido" como um valor válido? Ou você deseja que alguém da sua equipe corrija os dados antes da importação?

Alguma discussão provavelmente ocorrerá. Mas é basicamente isso. A solução técnica fluirá naturalmente das regras de negócios mais detalhadas.

svidgen
fonte
9

O problema geral é toda uma subárea de programação chamada limpeza de dados, que faz parte de uma subárea maior chamada integração de dados . Evitar esse tipo de problema provavelmente é uma grande parte do motivo da migração das planilhas do Excel e o motivo pelo qual o desenvolvedor sênior não deseja permitir que um campo se torne anulável. Não acho razoável dizer que essa é uma das maiores fontes de complexidade nas migrações de dados.

Apenas optar por usar NULL sempre que possível é provavelmente a coisa errada a fazer, e muito menos alterar o modelo de dados para tornar ainda mais nulos os campos. O Excel tem uma verificação de integridade fraca ou inexistente, o que provavelmente é a causa de muitos desses problemas. A coisa errada a fazer é remover a verificação de integridade no novo banco de dados e despejar lixo nele. Isso apenas perpetua o problema e adiciona complexidade significativa a integrações futuras que, de alguma forma, precisam lidar com dados sem sentido.

Parte da diferença provavelmente ocorre devido à incompatibilidade do modelo de dados. Lidar com isso é basicamente uma questão de estar (intimamente) familiarizado com os dois modelos de dados e saber como mapear o antigo para o novo. Desde que o novo seja capaz de capturar o antigo. (Caso contrário, sua equipe provavelmente terá um grande problema.) Isso pode exigir mais trabalho do que apenas copiar colunas. Darkwing dá um excelente exemplo disso (e também por que a inserção cega de NULLs é a coisa errada a se fazer). Elaborando sobre ele, se o modelo antigo tinha um ReceivedDatee um InProgresspouco e o novo modelo tem um StartDatee ProcessingEndTime, você precisará decidir se e como definir o ProcessingEndTime. Dependendo de como é usado, uma escolha razoável (mas arbitrária) pode ser configurá-la como a mesmaStartDate (ou logo depois, se isso causaria problemas).

No entanto, parte da diferença provavelmente se deve a dados que "deveriam" estar ausentes ou corrompidos. (Provavelmente devido a erros de entrada de dados ou migrações ou erros anteriores mal tratados nos sistemas de processamento de dados.) Se ninguém da sua equipe previu isso, você (coletivamente) se dedicou a gastar 20% do tempo do projeto " quase pronto. (Esse era um número inventado, mas pode estar longepior que isso, ou melhor. Depende da quantidade de dados incorretos, de quão importante é, de quão complexo é, de como é fácil obter o envolvimento dos responsáveis ​​pelos dados e de outros fatores.) Depois de determinar que os dados "devem" estar "lá, mas está faltando. Geralmente, você tenta determinar a extensão do problema consultando as fontes de dados antigas. Se são dezenas ou centenas de entradas, provavelmente são erros de entrada de dados e os clientes responsáveis ​​pelos dados devem resolvê-los manualmente (por exemplo, informar quais devem ser os valores.) Se são milhões de entradas (ou uma fração significativa dos dados) , talvez seja necessário reconsiderar se você identificou corretamente que "deveria estar" lá. Isso pode indicar um erro de modelagem no novo sistema.

Por exemplo, imagine uma fatura com quantidades e totais por item (mas não preço unitário), exceto que algumas dessas quantidades estavam inexplicavelmente ausentes. Conversar com a pessoa que processa essas faturas pode produzir um (ou mais) dos seguintes cenários: 1) "oh, uma quantidade em branco significa uma quantidade de 1", 2) "oh, eu sei que esses itens custam cerca de US $ 1.000, então, claramente esta é uma ordem para 2 ", 3)" quando isso acontece, procuro o preço nesse outro sistema e divido e arredondo ", 4)" procuro em outro sistema ", 5)" que não são dados reais ", 6)" nunca vi isso antes ".

Conforme sugerido, isso pode indicar algumas maneiras de resolver a situação automaticamente, mas você deve ter cuidado para que a solução se aplique a todos os casos. É comum que outros sistemas estejam envolvidos que possam verificar os dados, e isso é uma coisa boa. No entanto, muitas vezes é uma coisa ruim, pois pode ser difícil obter acesso e integrar-se a esses sistemas para realizar a verificação cruzada, e geralmente vem à luz que os sistemas entram em conflito entre si, não apenas por falta de alguns dados. Muitas vezes, é necessária alguma intervenção manual e, dependendo da escala, pode ser necessário criar ferramentas e interfaces especificamente para a tarefa de limpeza de dados. Geralmente, o que é feito é que os dados são parcialmente importados, mas as linhas com dados ausentes são enviadas para uma tabela separada, onde podem ser revisadas.

Derek Elkins
fonte
14
Em resumo: se você acha que lidar com código herdado é desagradável, tente lidar com dados herdados.
Peter Taylor
0

Mude o modelo de dados.

Você pode normalizar o hasradio e não terá mais nulos.

Se você não pode determinar um valor booleano, não use um booleano.

Ao permitir que um valor booleano se torne nulo, ele deixa de ser um booleano. Um booleano pode ter 2 estados: Falso, Verdadeiro.

O que você precisa é de 3 estados: Falso, Verdadeiro, Desconhecido.

Você tem a opção de alterar o modelo de dados?

(E outra coisa em que pensei: se em python ou java você recupera os dados do seu banco de dados. Você recupera o registro, verifica o campo hasradio, o que acontecerá se você verificar se é verdadeiro ou falso e é nulo?)

Pieter B
fonte
2
Ao alterar o modelo de dados e "normalizar a hasRadio", presumo que algo média como a adição de uma nova tabela CarFeatures, com campos Car_ID, Feature_ID, Has_Feature? Parece uma boa ideia.
jpa
2
@jpa é um pouco complicado. Você tem que ser muito claro no que faz, porque a ausência de um registro em nossa situação significa desconhecido. Embora muitas vezes a ausência de um registro signifique que ele não possui o recurso.
Pieter B
1
Você está olhando errado, Pieter. Ninguém diz que a booltem mais de dois valores, porque, como você disse, não tem. A boolé trueou false. No entanto, no caso dos OPs, o OP não está lidando com um booldiretamente, mas sim um Option<bool>/Maybe<bool>, que pode ter Some -> true/falseou None.
Andy
@DavidPacker, meu argumento é que, por causa disso, é um Talvez <bool> você deva parar de chamá-lo de algo remotamente semelhante ou obterá confusão. E se você insistir em usar um booleano, encontre uma maneira segura de fazê-lo.
Pieter B
4
Na minha opinião, booleano anulável é completamente bom. Nunca tive problemas com valores nulos, apesar de conhecer desenvolvedores que o fizeram.
Andy
-1

Como outros já apontaram, o que você tem aqui é um valor booleano que não é verdadeiramente booleano e o problema é forçá-lo a ser booleano ou manipulá-lo de outra forma.

O que você pode fazer é, em vez de ter um único resultado booleano, ter dois resultados booleanos. Estes podem concordar ou discordar. Se eles concordarem, você terá um resultado verdadeiro / falso direto.

Se, no entanto, eles discordarem, você terá um resultado indeterminado e poderá, dependendo das circunstâncias em que ocorrer, decidir sobre como lidar com isso. Em alguns casos, um resultado indeterminado pode ser melhor interpretado como verdadeiro, enquanto em outros, o mesmo resultado indeterminado pode ser melhor interpretado como falso, de acordo com a opção mais segura.

Ainda assim, isso permitiria que o resultado fosse relatado como indeterminado, para que essa nuance adicional do valor não fosse completamente perdida, até o ponto em que o valor possa ser definitivamente resolvido e redefinido.

Lee Leon
fonte