キーバリュー型を汎用性があるからとそのままにしておかないほうがいい

June 05, 2021

こんにちは、荒木です。仕事をしていると、どこでもキーバリュー型のデータを変数にいれていろんなところで使用しているコードをよく見ます。

キーバリュー型はどこでも変更が可能だったり、どんな構成要素が入っているか定義せずに使えるデータ構造ですが、これを聞いてみなさんはどう考えますか?自由で便利につかえて良さそうと思われますか?

最近はこういうコードに出会ったら、とりあえずはキーバリュー型をやめて必要な情報だけを明示的に定義し、構成要素を変更できないようにな状態に書き換えます。

※キーバリュー型がどういったものかといった説明はこちらの「UIで使われているデータの型を探検」を参考にしてください。

なぜどこでも変更可能だとよくないのか

アプリケーションの中のどこか以下のようなユーザー情報を持っている変数があったとします。仮にuser_infoと変数名を付けておきます。

{
  "user": {
    "id": 123,
    "email": "test@example.com"
  },
  "access_info": {
    "last_access": "2021-05-30 12:00:31",
  }
}

このuser_infoのデータにアクセスしようとすると、user_info['user']['email']とするとemailの情報がとれます。ではどこでも変更が可能とはどういうことかというと、次のようにするとaccess_countというデータがaccess_infoの中に追加できます。

user_info['access_info']['access_count'] = 5;

つまり上のデータが以下のようになったということです。

{
  "user": ...,
  "access_info": {
    "last_access": "2021-05-30 12:00:31",
    "access_count": 5
  }
}

user_infoに簡単にデータが追加できました。しかし、ここで疑問がでてきます。さらなるコードの変更で、user_infoが作成される最初の段階でaccess_countが存在するようになったらどうなるだろうと。

もちろん、その変更を加える開発者が、別の場所でaccess_countが追加されていることを知らずに放置してしまうと、アプリケーションのどこかでaccess_countを使用している部分が思った値にならないかもでしょう。

UIの表示やその他の内部の計算では、データは一応存在するのでバグがあると気づきにくくなります。エラーがでたり、表示されてほしいものが表示されないようなバグだとわかりやすいのですが、すべての処理がうまくいってしまうのは特定が難しくなる場合が多いので危険です。

よって、どこでも変更可能な状態のデータを使い回すと、逆にアプリケーションの変更容易性を破壊してしまっていることが感じられると思います。

では、どうやって避ければいいのかというと、使用するプログラミング言語によって様々ですが、RubyやPHPであればclassに宣言しますし、Typescriptだと型をしっかりとつけていればコンパイラーの警告で気づくことができますね。

次は、定義をせずに利用できるデータがなにが良くないのかを見ていきます。

なぜ定義なしで使えるのがよくないのか

先程の例では、キーバリュー型のデータが作成される前提で話を進めました。でも良くないそのデータ型をそもそも使い始めなければいいのではないのかと思われるでしょう。

しかし、WEBサービスを作っていると自然とキーバリュー型のデータが発生してしまいます。それは外部サービスとの連携のAPIのレスポンスや、データベースの保存方法にキーバリュー型が使われているからです。

そして、通常、APIのレスポンスは情報はドキュメントにどんな要素がくるのか定義されています。そうなるとプログラマーは怠惰なので、、その定義をみればいいだろうといって、わざわざ自分たちのコードで改めてデータの定義を行うようなことをしたがりません。

それでも、やはり労力を払って定義する理由は、上の例の他にもあります。それは、定義をしっかりしていれば、エラーを発生する場所をコントロールできるからです。

つまり、APIからのでデータを受け取る場所において、必要なデータだけを取得するようにしておけば、API側の変更がありレスポンスのデータに必要なものが含まれなくなってしまっても、受け取るところでエラーが発生することになります。エラーの原因が特定しやすいですし、その回復方法も前もって設計できます。

プログラミング言語によっては、たとえ上記の例のaccess_countというキーがなかったとしても、計算によってはそれを0として処理を進めてしまう場合があります。これも、たとえばアクセス数によっては見せてはいけない画面を見れる状態にしてしまうバグを誘発してしまいます。

まとめ

プログラミングは汎用性・拡張性はとても重要ですが、それはしっかりと定義された部品の上に成り立つものであって、無秩序の上には良いアプリケーションを組み上げることはできません。

スピード重視や、はっきりと仕様が決まっていないからこそ、しっかりとその時に必要な最小限のデータの定義を決めて、小さな部品の組み合わせを意識したコードを書いていきたいですね。

ブログを見ていただき、弊社にご興味を持ってくださった方は、ぜひ弊社Webサイトもご覧ください。お仕事のご相談も可能です。