DAppsは日本語で、非中央集権型アプリや分散型アプリなどと呼ばれていますが、実際のアプリケーションは全く非中央集権型(Decentralized)ではなく中央集権型(Centralized)のアプリケーション「CApps」になっているというは周知の事実だと思います。
実際問題アプリケーションの楽しさやユーザビリティを考えると、ある程度は中央集権型になるのは仕方のないことなのだと思います。
ではDAppsのユーザービリティの向上を目指すにあたり、どのようなアーキテクチャにするべきなの考えてみます。
キーとなるのは、GraphQL + MongoDBによるAPIサーバーです。
なぜAPIサーバー?
コントラクトの不得意なことの一つとして、一覧データの取得があります。
コントラクト内の一覧データを取ってくるには、データの件数だけループしてトランザクションを発行する必要があったり、コントラクト内で検索機能を実装しようとすると記述量が大幅に増えてコードがカオスになるためリッチな検索機能が提供しづらかったりします。
そのため、ユーザビリティを向上させるためにはコントラクトのデータをDBに同期し、API経由でデータを取得するようなバックエンドが必要になります。
また、複数のサービスが同じコントラクトを参照する場合、ABIとコントラクトアドレスを全てのサービスで共有する必要がありますが、DBにABIとコントラクトアドレスを保存することで、APIサーバー経由で自由にABIとコントラクトアドレスを取得できるようにもなります。
構成図
APIサーバーを導入すると、DAppsの構成は下記の図のようになります。
name | description |
---|---|
APP | SPAとして作られたフロントエンド |
API Server | MongoDBに格納されたデータをGraphQLを用いて返却する参照用のサーバー |
Sync Batch | コントラクトのイベントを監視し、コントラクト内のデータをMongoDBに格納する処理 |
GraphQLを使う理由
基本的にDAppsにおける主役はフロントエンドです。
(トランザクションの代理発行をバックエンド側で行うようなサービスは別ですが。)
DAppsはフロントエンドに秘密鍵を持っている性質上トランザクションの発行を含む全てのビジネスロジックをフロントエンドが持ちがちなので、責務を明確に分離するためには、ビジネスロジックはフロントエンドに持ち、APIはデータを返すだけにする必要があります。
GraphQLであればQueryを用いてフロントエンド側で欲しい項目を指定してデータを取得できるので、データを返却する以外のロジックをサーバー側で持つ必要がありません。
また、データの更新はコントラクト側で行うためAPIサーバーは参照機能しか必要ないので、認証やバリデーションなどのロジックすらサーバー側で実装する必要がありません。
そのため、エンドポイント1つで自由度の高い参照機能を提供できるGraphQLを使うとサーバー側で実装すべきロジックが大幅に減り、とてもシンプルで分かりやすい構成になります。
これらの理由から、DAppsにおけるAPIサーバーではGraphQLを使うべきと考えています。
MongoDBを使う理由
厳密にはMongoDBでなければならない理由はありませんが、コントラクト内のデータにはリレーションがなく、またコントラクトのイベントを監視してガンガンデータを格納していくのでパフォーマンス的な面からもRDBよりはNoSQLが向いていると思われます。
さらに検索機能をリッチにしたいので、NoSQLの中でも比較的自由度の高いクエリを発行できるMongoDBを使うべきと考えています。
おわりに
現状DAppsにおけるデファクトスタンダートはまだ存在していないので、他にも良い方法があるかもしれませんが、GraphQL + MongoDBによるAPIサーバーを導入する手法はとても便利だと思います。
また、今後全ての機能をコントラクトで実装する良い解決案も出てくるかもしれないので、DAppsのこれからの進化に注目です。
ブログでも書いています
DAppsのバックエンドにGraphQL + MongoDBによるAPIサーバーを導入すべき理由