スキーマレスJSON形式のように、APIを介してオブジェクトを転送する場合、存在しない文字列プロパティを返す理想的な方法は何ですか?以下のリンクにある例のように、これを行うにはさまざまな方法があることを知っています。
私は過去にnullを使用したと確信していますが、それを行う正当な理由はありません。データベースを扱う場合は、nullを使用するのは簡単です。しかし、データベースは、APIの反対側の当事者に関係するべきではない実装の詳細のように見えます。例えば。おそらく、値(null以外)を持つプロパティのみを格納するスキーマレスデータストアを使用します。
コードの観点からは、文字列関数を1つの型、つまりstring
(nullではない)でのみ機能するように制限すると、証明が容易になります。 nullを回避することも、Option
オブジェクトを持つ理由です。したがって、要求/応答を生成するコードがnullを使用しない場合、私の推測では、APIの反対側にあるコードもnullを使用するように強制されることはありません。
Nullの使用を回避する簡単な方法として、空の文字列を使用するのが好きです。 nullを使用して空の文字列に対して私が聞いた1つの引数は、空の文字列はプロパティが存在することを意味するということです。私は違いを理解していますが、それが単なる実装の詳細であるかどうか、およびnullまたは空の文字列を使用すると実際の違いが生じるかどうかについても疑問に思います。また、空の文字列は空の配列に似ているのでしょうか。
では、これらの懸念に対処するための最良の方法はどれですか?転送されるオブジェクトの形式(スキーマ/スキーマレス)に依存しますか?
TLDR; nullプロパティを削除
最初に覚えておかなければならないのは、アプリケーションの エッジはオブジェクト指向ではない (そのパラダイムでプログラミングしている場合は機能しない)ことです。受け取るJSONはオブジェクトではないため、そのように扱うべきではありません。これは、オブジェクトに変換できる(または変換できない)構造化データです。一般に、着信JSONは、検証されるまでビジネスオブジェクトとして信頼されるべきではありません。 逆シリアル化されたという事実だけでは有効になりません。 JSONもバックエンド言語に比べてプリミティブが制限されているため、JSONに合わせて作成することはしばしば価値があります [〜# 〜] dto [〜#〜] 着信データ用。次に、DTOを使用して、API操作を実行するためのビジネスオブジェクト(またはエラーの試行)を作成します。
JSONを単なる送信フォーマットとして見る場合、設定されていないプロパティを省略する方が理にかなっています。回線を介して送信する方が少ないです。バックエンド言語がデフォルトでnullを使用しない場合、おそらくエラーを出すようにデシリアライザーを構成できます。たとえば、Newtonsoft.Jsonの一般的な設定では、null /欠落しているプロパティをF#option
型との間でのみ変換し、それ以外の場合はエラーになります。これにより、オプションのフィールド(option
タイプのフィールド)が自然に表現されます。
いつものように、一般化は今のところあなたを得るだけです。デフォルトまたはnullプロパティの方が適している場合があります。ただし、重要なのは、システムのエッジにあるデータ構造をビジネスオブジェクトとして見ることではありません。ビジネスオブジェクトは、正常に作成されたときにビジネス保証(少なくとも3文字の名前など)を備えている必要があります。しかし、ネットワークから引き出されたデータ構造には、実際の保証はありません。
pdate:混乱を招く可能性があるため、回答を少し編集しました。
空の文字列を使用することは、決定的なnoです。空の文字列はまだ値ですが、空です。何も表さない構造体null
を使用して値を示すことはできません。
API開発者の観点から見ると、プロパティは2種類しか存在しません。
null
を含めることもできます(MAY)。これにより、プロパティが必須の場合、つまり必須ですが、null
にすることはできません。
一方、オブジェクトのオプションのプロパティを設定せずに空のままにしておく場合は、いずれにしてもnull
の値を使用して応答に含めておきます。私の経験から、APIクライアントは、プロパティが実際に存在するかどうかを確認する必要がないため、APIクライアントが解析を実装しやすくなっています。これは、プロパティが常に存在し、null
を処理するだけで応答をカスタムDTOに変換できるためです。オプションとしての値。
クライアントの追加条件を含む応答力からフィールドを動的に含めたり削除したりします。
いずれにせよ、どちらの方法を選択する場合でも、必ずconsistentを維持し、十分に文書化してください。この方法では、動作が予測可能である限り、APIに何を使用しても問題はありません。
null
使用法はアプリケーション/言語に依存します最終的に、null
を有効なアプリケーション値として使用するかどうかの選択は、主にアプリケーションとプログラミング言語/インターフェース/ Edgeによって決まります。
基本的なレベルでは、異なるクラスの値がある場合は、異なるタイプを使用することをお勧めします。 null
は、インターフェイスで許可されていて、表現しようとしているプロパティのクラスが2つしかない場合は、オプションになることがあります。インターフェースやフォーマットで許可されている場合は、プロパティを省略してもかまいません。新しい集約タイプ(クラス、オブジェクト、メッセージタイプ)は、別のオプションになる場合があります。
文字列の例として、これがプログラミング言語の場合は、いくつか質問します。
Option
はおそらくあなたのインターフェース設計にとってより良いでしょう。Option
は、文字列がnullにできない場合にこのケースを最もよく満たします。ただし、とにかくユーザー入力でnull
文字列値を確認する必要があるので、おそらく質問の最初の行に戻ります。表現します。null
は私のプログラミング言語のプログラマエラーを示していますか?残念ながら、一部の言語では、null
が初期化されていない(または明示的に初期化されていない)ポインターまたは参照のデフォルト値であることがよくあります。 null
はデフォルト値として受け入れられる値ですか?デフォルト値としてsafeですか? null
は、割り当て解除された値を示す場合があります。インターフェイスのコンシューマーに、プログラムでのこれらの潜在的なメモリ管理または初期化の問題の兆候を提供する必要がありますか?そのような問題に直面した場合のそのような呼び出しの失敗モードは何ですか?呼び出し元は私のものと同じプロセスまたはスレッドにあるので、そのようなエラーは私のアプリケーションにとって高いリスクになりますか?これらの質問に対する回答によっては、null
がインターフェースに適しているかどうかを判断することができるでしょう。
例1
null
は文字列にスペースを割り当てるのに失敗したときに返される可能性のある文字列値です。回答:null
はおそらく適切ではありません
根拠:この場合のnull
は、実際には2つの異なるタイプの値を示すために使用されます。最初の値は、インターフェースのユーザーが設定したいデフォルト値である場合があります。残念ながら、2番目の値は、システムが正しく機能していないことを示すフラグです。そのような場合は、おそらく(システムにとってそれが何であれ)可能な限り安全に失敗したいと思うでしょう。
例2
char *
メンバーを持つC構造体を使用しています。NULL
を指していないことを確認しますchar *
メンバーのデフォルトで安全な値は、NULL
の単一の値で示すことができますchar *
メンバーを明示的に初期化しない可能性をユーザーに提供する必要があります。回答:NULL
が適切な場合があります
理論的根拠:構造体がNULL
チェックに合格する可能性はほとんどありませんが、初期化されていません。ただし、構造体の値に関する何らかのチェックサムや構造体のアドレスの範囲チェックがない限り、APIはこれを考慮できない場合があります。 MISRA-Cリンターは、初期化前に構造体の使用にフラグを立てることにより、APIのユーザーを支援する場合があります。ただし、char *
メンバーの場合、structへのポインターが初期化されたstructを指す場合、NULL
はstruct初期化子で指定されていないメンバーのデフォルト値です。したがって、NULL
は、アプリケーションのchar *
構造体メンバーの安全なデフォルト値として機能する場合があります。
それがシリアル化インターフェイス上にある場合は、文字列でnullを使用するかどうかについて、次の質問をします。
null
は潜在的なクライアント側エラーを示していますか? JavaScriptでのJSONの場合、null
は必ずしも割り当て失敗の指標として使用されるわけではないため、これはおそらく「いいえ」です。 JavaScriptでは、問題として設定される参照からのオブジェクトの不在を明示的に示すために使用されます。ただし、JSON null
をネイティブのnull
型にマップするJavaScript以外のパーサーとシリアライザーがあります。これが事実である場合、ネイティブnull
の使用が特定の言語、パーサー、シリアライザーの組み合わせで問題ないかどうかの議論が始まります。null
は、実際には新しいメッセージタイプが完全に存在することを示しています。完全に異なるメッセージタイプを指定するだけで、シリアライゼーションフォーマットのコンシューマにとっては、よりクリーンになる場合があります。これにより、Webインターフェースが提供する2つのメッセージの違いを、検証とアプリケーションロジックで明確に分離できます。一般的なアドバイス
null
は、それをサポートしないエッジまたはインターフェイスの値にはできません。プロパティの値の入力に非常に緩いもの(JSONなど)を使用している場合は、コンシューマEdgeソフトウェアで何らかの形式のスキーマまたは検証をプッシュしてみてください(例 JSON Schema )ifあなたはできる。それがプログラミング言語APIの場合は、可能な場合は(入力を介して)静的に、または実行時に感知できる程度に大声で(つまり、消費者向けのインターフェースでは 防御的プログラミング )、ユーザー入力を検証します。同様に重要なこととして、Edgeを文書化または定義して、次のことについて疑問がないようにします。
文字列が存在し、たまたま空の文字列である状況では、空の文字列を指定します。 「いいえ、このデータはありません」と明示的に伝えたい状況ではnullを指定します。そして、「そこにデータがない、気にしないでください」と言うキーを省略します。
あなたはこれらの状況のどれが起こり得るかを判断します。アプリケーションが空の文字列を持つことは理にかなっていますか? nullを使用して明示的に「データなし」と言うことと、値がないことによって暗黙的に区別することを区別しますか?クライアントが両方を区別する必要がある場合は、両方の可能性(nullとキーなし)のみが必要です。
これがすべてデータの送信に関することであることに注意してください。受信者がデータを処理するのは彼らのビジネスであり、彼らは彼らにとって最も便利なことをします。レシーバーすべきクラッシュすることなく、(おそらくデータを拒否することによって)そこに投げたあらゆるものを処理できます。
他に考慮事項がない場合は、送信者にとって最も便利なものを送信しますdocumentそれを送信します。 JSONのエンコード、送信、解析の速度が向上する可能性があるため、存在しない値を送信しないことをお勧めします。
ここでこれらの質問の私の個人的な分析。本、紙、研究など何でもないので、私の個人的な経験だけです。
null
としてこれは私にとっては立ち入り禁止です。空の文字列のセマンティクスと未定義のセマンティクスを混在させないでください。多くの場合、それらは完全に交換可能ですが、未定義と定義済みだが空であるという意味が異なる場合があります。
一種の愚かな例:外部キーを格納する属性があり、その属性が定義されていないかnull
であるとします。これは、関係が定義されていないことを意味しますが、空の文字列""
は定義された関係として理解でき、外部レコードのIDはその空の文字列です。
null
これは白黒のトピックではありません。どちらのアプローチにも長所と短所があります。
null
値を明示的に定義することを支持して、これらの長所があります:
存在しないキーがnull
のセマンティクスに等しいと仮定すると、次のようになります。
APIがなんらか安定していて、完全に文書化している場合は、存在しないキーがnull
の意味と等しいことを述べてもまったく問題ないと思います。しかし、それがより乱雑で無秩序である場合(かなり頻繁にそうであるように)、すべてのメッセージのすべての値を明示的に定義すれば、頭痛の種を回避できると思います。つまり疑わしい場合は、詳細なアプローチを採用する傾向があります。
とはいえ、何よりも重要なことは、意図を明確に述べ、一貫性を保つことです。ここで1つのことを行って、もう1つのことを行わないでください。予測可能なソフトウェアは、より優れたソフトウェアです。
資料!
TL; DR>
必要に応じて行います-場合によっては、それが使用されるコンテキストが重要になります。例:Oracle SQLへの変数のバインド:空の文字列はNULLとして解釈されます。
単に私は言うでしょう-言及された各シナリオを文書化することを確認してください
コードはさまざまな方法で動作する可能性があります-コードがそれにどのように反応するかを文書化します。
次に、それに加えて-一貫して行動し、おそらく独自のベストプラクティスを採用するかどうかは、あなた次第です。その一貫した動作を文書化します。例:
tl; dr-使用する場合:意味が一貫している。
null
を含めた場合、それはどういう意味ですか?それが何を意味するのかという事柄の宇宙があります。 1つの値では、欠けている値や不明な値を表すのに十分ではありません(これらは無数の可能性の2つにすぎません。例:欠落-測定されましたが、まだわかりません。不明-測定しようとしませんでした。それ。)
私が最近出くわした例では、誰かのプライバシーを保護するために報告されなかったため、フィールドが空である可能性がありますが、フィールドは送信者側で知られている、送信者側では知られていませんが、元のレポーターには知られているか、両方には不明です。そして、これらすべてがレシーバにとって重要でした。したがって、通常は1つの値では不十分です。
オープンワールドの前提条件(記述されていないことについて単に知らない)の場合、それを除外するだけで、何でもかまいません。閉じた世界の仮定(たとえば、SQLで述べられていないことが誤っている)では、null
が何を意味するかを明確にし、できるだけその定義と一致するようにします...
bestとは言えませんが、ほぼ間違いなく単純な実装の詳細ではありませんですが、その変数と対話する方法の構造が変わります。
何かがある場合nullにすることができます常にそれを扱っている必要がありますある時点でnullになりますしたがって、常に2つのワークフロー、1つになりますnullの場合、有効な文字列の場合。スプリットワークフローは、悪い処理とは限りませんが、利用できる可能性のあるエラー処理や特殊なケースでの使用はありますが、コードを難読化します。
常に同じ方法で文字列と対話するの場合、機能が頭に留まるのほうがおそらく簡単です。
したがって、「何が最善か」という質問と同様に、答えはそれは場合によって異なりますです。ワークフローを分割し、何かが設定されていないときにより明示的にキャプチャする場合は、nullを使用します。プログラムがそのまま実行し続けたい場合は、空の文字列を使用します。重要なことは、あなたがconsistentであるということです。共通のリターンを選び、それを守ってください。
APIを作成していることを考慮して、空の文字列に固執するをお勧めします。これは、ユーザーが補正する必要が少ないためです。APIのユーザーとして、すべての理由を知ることはできませんあなたのAPIは私にnull値を与える可能性がありますあなたが非常によく文書化されていない限り、何人かのユーザーはとにかく読まないでしょう。