Ao transferir objetos por meio de uma API, como no formato JSON sem esquema, qual é a maneira ideal de retornar uma propriedade de cadeia inexistente? Eu sei que existem diferentes maneiras de fazer isso, como nos exemplos nos links listados abaixo.
Tenho certeza de que usei null no passado, mas não tenho um bom motivo para fazê-lo. Parece simples usar nulo ao lidar com o banco de dados. Mas o banco de dados parece um detalhe de implementação que não deve preocupar a parte do outro lado da API. Por exemplo, eles provavelmente usam um armazenamento de dados sem esquema que armazena apenas propriedades com valores (não nulos).
Do ponto de vista do código, restringir as funções de string para trabalhar apenas com um tipo, ou seja, string
(não nulo), facilita a prova; evitar nulo também é uma razão para ter um Option
objeto. Portanto, se o código que produz solicitação / resposta não usar nulo, meu palpite é que o código do outro lado da API não será forçado a usar nulo também.
Eu gosto bastante da ideia de usar uma string vazia como uma maneira fácil de evitar o uso de null. Um argumento que ouvi por usar nulo e contra a cadeia vazia é que a cadeia vazia significa que a propriedade existe. Embora eu entenda a diferença, também me pergunto se é apenas o detalhe da implementação e se o uso de cadeias nulas ou vazias faz alguma diferença na vida real. Também me pergunto se uma string vazia é análoga a uma matriz vazia.
Então, qual é a melhor maneira de fazer isso que atenda a essas preocupações? Depende do formato do objeto que está sendo transferido (esquema / esquema)?
fonte
if( value === null) { use parent value; }
No entanto, se você definir o valor filho, mesmo que seja uma sequência vazia (por exemplo, substitua o valor pai padrão por branco), como você "herdará" novamente o valor? Para mim, defini-lo como nulo significaria "desmarcar esse valor para que possamos usar o valor pai".null
(é verdade quenull
é evitado como tal), o questionador significa "Retornar não nulo" [Objeto] (ou seja: String vazia, Matriz vazia, etc.) quando eles escreva "evitar".Respostas:
TLDR; Remover propriedades nulas
A primeira coisa a ter em mente é que os aplicativos em suas bordas não são orientados a objetos (nem funcionais se estiver programando nesse paradigma). O JSON que você recebe não é um objeto e não deve ser tratado como tal. São apenas dados estruturados que podem (ou não) converter em um objeto. Em geral, nenhum JSON de entrada deve ser confiável como um objeto de negócios até que seja validado como tal. Apenas o fato de ter desserializado não o torna válido. Como o JSON também possui primitivas limitadas em comparação com os idiomas de back-end, geralmente vale a pena criar um DTO alinhado ao JSON para os dados recebidos. Em seguida, use o DTO para construir um objeto de negócios (ou tentativa de erro) para executar a operação da API.
Quando você vê o JSON apenas como um formato de transmissão, faz mais sentido omitir propriedades que não estão definidas. É menos para enviar através do fio. Se o seu idioma de back-end não usar nulos por padrão, você provavelmente poderá configurar seu desserializador para dar um erro. Por exemplo, minha instalação comum para Newtonsoft.Json converte propriedades nulas / ausentes
option
somente para / de tipos F # e, caso contrário, ocorrerá um erro. Isso fornece uma representação natural de quais campos são opcionais (aqueles comoption
tipo).Como sempre, as generalizações apenas levam você até aqui. Provavelmente, há casos em que uma propriedade padrão ou nula se encaixa melhor. Mas a chave é não olhar para estruturas de dados na borda do seu sistema como objetos de negócios. Os objetos de negócios devem ter garantias de negócios (por exemplo, citar pelo menos três caracteres) quando criados com êxito. Mas as estruturas de dados retiradas do fio não têm garantias reais.
fonte
Atualização: editei a resposta um pouco, porque isso pode causar confusão.
Indo com uma string vazia é um não definitivo. String vazia ainda é um valor, está apenas vazia. Nenhum valor deve ser indicado usando uma construção que não representa nada
null
,.Do ponto de vista do desenvolvedor da API, existem apenas dois tipos de propriedades:
null
.Isso deixa bastante claro que quando uma propriedade é obrigatória, ou seja. necessário, nunca pode ser
null
.Por outro lado, se uma propriedade opcional de um objeto não for definida e deixada em branco, prefiro mantê-los na resposta de qualquer maneira com o
null
valor Pela minha experiência, torna mais fácil para os clientes da API implementar a análise, pois eles não precisam verificar se uma propriedade realmente existe ou não, porque ela está sempre lá, e eles podem simplesmente converter a resposta em seu DTO personalizado, tratandonull
valores como opcional.Incluir / remover dinamicamente campos das forças de resposta, incluindo condições adicionais nos clientes.
De qualquer maneira, da maneira que você escolher, mantenha-o consistente e bem documentado. Dessa forma, realmente não importa o que você usa para sua API, desde que o comportamento seja previsível.
fonte
null
para referências. Misturar valores com referências é uma das minhas preocupações. Como você diferencia os campos opcionais dos camposnull
de sequência não opcional que têmnull
valor? Re-analisando, não é o fato de testar a existência de propriedades tornar o analisador mais frágil?null
para indicar que o valor é opcional. Portanto, quando você define um objeto que possui uma propriedade de sequência não opcional e o consumidor não possui essa propriedade, ele deve enviar uma sequência vazia para essa propriedade. Isso esta certo?null
O uso depende do aplicativo / idiomaPor fim, a escolha de usar ou não
null
como um valor válido de aplicativo é amplamente determinada por seu aplicativo e linguagem de programação / interface / borda.Em um nível fundamental, recomendo tentar usar tipos distintos se houver classes distintas de valores.
null
pode ser uma opção se sua interface permitir e houver apenas duas classes de uma propriedade que você está tentando representar. Omitir uma propriedade pode ser uma opção se sua interface ou formato permitir. Um novo tipo agregado (classe, objeto, tipo de mensagem) pode ser outra opção.Para o seu exemplo de string, se isso estiver na linguagem de programação, eu me faria algumas perguntas.
Option
provavelmente será melhor para o seu design de interface.Option
provavelmente preenche esse caso melhor se sua sequência não for anulável. No entanto, você provavelmente terá que verificar a entrada do usuário para obter umnull
valor de string de qualquer maneira, portanto, provavelmente eu voltaria para a primeira linha de questionamento: quantos tipos de valores quero / quero representar.null
indicativo de um erro do programador na minha linguagem de programação? Infelizmente,null
geralmente é o valor padrão para referências ou ponteiros não inicializados (ou não explicitamente inicializados) em alguns idiomas. Onull
valor é aceitável como o valor padrão? É seguro como um valor padrão? Às vezesnull
é indicativo de valores desalocados. Devo fornecer aos consumidores da minha interface uma indicação desses possíveis problemas de gerenciamento de memória ou inicialização no programa deles? Qual é o modo de falha de uma chamada em face desses problemas? O chamador está no mesmo processo ou thread que o meu para que esses erros sejam um alto risco para o meu aplicativo?Dependendo das suas respostas a essas perguntas, você provavelmente poderá saber se
null
é ou não adequado para sua interface.Exemplo 1
null
é um possível valor de sequência passado após falha ao alocar espaço para uma sequência.Resposta:
null
provavelmente não é apropriadoJustificação:
null
neste caso, é realmente usado para indicar dois tipos diferentes de valores. O primeiro pode ser um valor padrão que o usuário da sua interface pode querer definir. Infelizmente, o segundo valor é um sinalizador para indicar que seu sistema não está funcionando corretamente. Nesses casos, você provavelmente deseja falhar o mais seguro possível (o que isso significa para o seu sistema).Exemplo 2
char *
membro.NULL
char *
membro para sua API pode ser indicado por um único valor deNULL
char *
membro.Resposta:
NULL
pode ser apropriadoFundamentação da petição: Há uma pequena chance de que sua estrutura passe na
NULL
verificação, mas não foi inicializada. No entanto, sua API pode não ser capaz de explicar isso, a menos que você tenha algum tipo de soma de verificação no valor da estrutura e / ou verificação de intervalo do endereço da estrutura. Os linters MISRA-C podem ajudar os usuários da sua API sinalizando o uso de estruturas antes da inicialização. No entanto, quanto aochar *
membro, se o ponteiro para estrutura apontar para uma estrutura inicializada,NULL
é o valor padrão de um membro não especificado em um inicializador de estrutura. Portanto,NULL
pode servir como um valor padrão seguro para ochar *
membro struct em seu aplicativo.Se estiver em uma interface de serialização, eu me perguntaria as seguintes perguntas sobre se deve ou não usar nulo em uma string.
null
indicativo de um possível erro do lado do cliente? Para JSON em JavaScript, esse provavelmente é um não, poisnull
não é necessariamente usado como uma indicação de falha na alocação. Em JavaScript, é usado como uma indicação explícita da ausência do objeto em uma referência a ser configurada problemática. No entanto, existem analisadores e serializadores não-javascript que mapeiam JSONnull
para onull
tipo nativo . Se for esse o caso, isso implica na discussão sobre se onull
uso nativo é ou não adequado para sua combinação específica de idioma, analisador e serializador.null
indica realmente que você tem um novo tipo de mensagem inteiramente. Pode ser mais limpo para seus consumidores do formato de serialização especificar apenas um tipo de mensagem completamente diferente. Isso garante que a validação e a lógica do aplicativo possam ter uma separação limpa entre as duas distinções de mensagens que sua interface da web fornece.Conselho Geral
null
não pode ser um valor em uma borda ou interface que não o suporte. Se você estiver usando algo de natureza extremamente flexível na digitação de valores de propriedades (por exemplo, JSON), tente inserir alguma forma de esquema ou validação no software de borda do consumidor (por exemplo, JSON Schema ), se puder. Se for uma API da linguagem de programação, valide a entrada do usuário estaticamente, se possível (por meio de digitação) ou o mais alto possível em tempo de execução (também conhecido como prática de programação defensiva nas interfaces voltadas ao consumidor). O mais importante é documentar ou definir a borda, para que não haja dúvidas sobre:fonte
Aqui minha análise pessoal dessas questões. Não é apoiado por nenhum livro, jornal, estudo ou qualquer outra coisa, apenas minha experiência pessoal.
Cadeias vazias como
null
Este é um não-vai para mim. Não misture a semântica da sequência vazia com a não definida. Em muitos casos, eles podem ser perfeitamente intercambiáveis, mas você pode encontrar casos em que não definido e definido mas vazio significam algo diferente.
Um tipo de exemplo estúpido: digamos que exista um atributo que armazene uma chave estrangeira, e esse atributo não esteja definido ou seja
null
, isso significaria que não há relação definida, enquanto uma cadeia vazia""
pode ser entendida como uma relação definida e o atributo O ID do registro estrangeiro é essa sequência vazia.Não definido vs
null
Este não é um tópico em preto ou branco. Existem prós e contras em ambas as abordagens.
A favor da definição explícita de
null
valores, existem os seguintes profissionais:A favor de assumir que uma chave inexistente é igual à semântica de
null
:Caso a API seja de alguma forma estável e você a documente completamente, acho perfeitamente correto afirmar que uma chave inexistente é igual ao significado de
null
. Mas se for mais bagunçado e caótico (como costuma acontecer), acho que você pode evitar dores de cabeça se definir explicitamente todo valor em cada mensagem. Ou seja, em caso de dúvida, tenho a tendência de seguir a abordagem detalhada.Tudo isso dito, o mais importante: exponha suas intenções claramente e seja consistente. Não faça uma coisa aqui e a outra ali. Software previsível é melhor software.
fonte
null
. Outro exemplo: em um jogo, há um objeto de personagem e ele tem um atributo "parceiro". Umnull
parceiro significa claramente que não há parceiro, mas""
pode ser entendido como existe um parceiro cujo nome é""
.null
string for vazia. Talvez renderizando-o em um formulário, mas nunca no modelo de dados.name
que eu estava falando, você permitiria que o nome do parceiro fosse nulo?Eu forneceria uma string vazia em uma situação em que uma string esteja presente, e por acaso seja uma string vazia. Eu forneceria null em uma situação em que desejo dizer explicitamente "não, esses dados não estão lá". E omita a chave para dizer "não há dados lá, não se preocupe".
Você julga qual dessas situações pode acontecer. Faz sentido para o seu aplicativo ter cadeias vazias? Deseja distinguir entre dizer explicitamente "sem dados" usando nulo e implicitamente sem ter valor? Você só deve ter as duas possibilidades (nula e sem chave presente) se ambas precisarem ser distinguidas pelo cliente.
Agora, lembre-se de que se trata de transmitir dados. O que o receptor faz com os dados é da sua conta e eles farão o que for mais conveniente para eles. O receptor deve ser capaz de lidar com qualquer coisa que você jogue com ele (possivelmente rejeitando os dados) sem bater.
Se não houver outras considerações, transmitirei o que for mais conveniente para o remetente e o documentarei . Prefiro não enviar valores ausentes, pois isso provavelmente melhora a velocidade da codificação, transmissão e análise do JSON.
fonte
Embora eu não possa dizer o que é melhor , quase certamente não é um simples detalhe de implementação , ele altera a estrutura de como você pode interagir com essa variável.
Se algo puder ser nulo, você sempre deve tratá-lo como se fosse nulo em algum momento , para ter sempre dois fluxos de trabalho , um para nulo e outro para uma sequência válida. Um fluxo de trabalho dividido não é necessariamente uma coisa ruim, pois há bastante manipulação de erros e usos de casos especiais que você pode utilizar, mas ofusca seu código.
Se você sempre interagir com a string da mesma maneira , provavelmente será mais fácil para a funcionalidade ficar na sua cabeça .
Assim como em qualquer pergunta "o que é melhor", fico com a resposta: depende . Se você deseja dividir seu fluxo de trabalho e capturar mais explicitamente quando algo não estiver definido, use null. Se você preferir que o programa continue fazendo o mesmo, use uma string vazia. O importante é que você seja consistente , escolha um retorno comum e continue com ele.
Considerando que você está criando uma API, eu recomendaria manter uma string vazia, pois há menos para o usuário compensar, porque, como usuário de uma API, não conhecerei todos os motivos pelos quais sua API poderia me dar um valor nulo, a menos que você ' está muito bem documentado, o que alguns usuários não lêem de qualquer maneira.
fonte
string
s, nunca nulos. Se a API usar nulo, em algum momento o produtor precisará criar issonull
para estar em conformidade com a API. Então o consumidor precisa lidarnull
também. Mas acho que entendi o que você está dizendo, apenas decida e defina a API com autoridade, certo? Isso significa que não há nada de errado com nenhum deles?Documento!
TL; DR>
Faça como achar melhor - às vezes o contexto em que é usado é importante. Exemplo, Vincular variáveis a um Oracle SQL: String vazia é interpretado como um NULL.
Simplesmente eu diria - Certifique-se de documentar cada cenário mencionado
Seu código pode agir de diferentes maneiras - documentar como o código reage a ele:
Além disso, cabe a você se comportar de forma consistente e, possivelmente, adotar algumas de suas próprias práticas recomendadas. Documente esse comportamento consistente. Exemplos:
fonte
tl; dr - se você o usar: seja consistente com o que significa.
Se você incluísse
null
, o que isso significaria? Existe um universo de coisas que poderia significar. Um valor simplesmente não é suficiente para representar um valor ausente ou desconhecido (e essas são apenas duas das inúmeras possibilidades: por exemplo, Faltando - foi medido, mas ainda não o sabemos. Desconhecido - não tentamos medir isto.)Em um exemplo que me deparei recentemente, um campo pode estar vazio porque não foi relatado para proteger a privacidade de alguém, mas era conhecido no lado do remetente, não era do lado do remetente, mas era do repórter original ou desconhecido para ambos. E tudo isso importava para o receptor. Portanto, geralmente um valor não é suficiente.
Com uma suposição de mundo aberto (você simplesmente não sabe sobre as coisas não declaradas), você simplesmente deixaria de fora e poderia ser qualquer coisa. Com a suposição de mundo fechado (as coisas não declaradas são falsas, por exemplo, no SQL), é melhor você esclarecer o que
null
significa e ser o mais consistente possível com essa definição ...fonte