見出し画像

GoとgRPCとPOS連携と。O:der Platformのシステム構成と技術スタック

こんにちは。Showcase Gigのきくち (@_pochi) です。

この記事は、Showcase Gig Advent Calendar 2021 2日目の記事です。

アドベントカレンダー2日目の今日は、私たちShowcase Gigが開発・運用しているモバイルオーダープロダクトである「O:der」、そして「O:der Platform」のシステム構成や技術スタックについて書きます。

O:derとO:der Platform

こちらは、Showcase Gigのプロダクトページに掲載されている概念図です。

画像1

「O:der Table」, 「O:der Kiosk」, 「O:der ToGo」といった複数のプロダクトがある中で、それらは「O:der Platform」につながっているよ!POSシステムなどの外部連携は「O:der Platform」が担っているよ!という図です。

これをもうちょっと詳細化すると次のようになります。

画像2

これはエンドユーザーがモバイルオーダーで注文した際の注文データフローです。

エンドユーザーが「O:der Table / ToGo / Kiosk」を利用して行った注文は、「O:der Platform」のコアに受け渡され、そこから「Instore」と呼ばれるサービスを経て飲食店に届きます。一方、POSシステムをご利用中の飲食店においては、POS連携サービスを経由してPOSシステムに伝えることで飲食店に注文を届けます。

それぞれのサービスの責務と構成について、もう少し詳しく説明します。

O:der Plaform Core

画像3

テイクアウトやイートインという注文の形態によらない、プリミティブな「注文」を受け付ける、プラットフォームのコア機能です。主たる責務は、注文・会計・決済、マスタデータの管理、そしてプラットフォームの拡張性の担保です。

つまり、やることは単にデータのCRUDするだけなのですが、「注文」や「メニュー」はモデリングし始めると大変奥深いです。このトピックだけで記事が3本くらい書けそうなのですが、今回はこのあたりでやめておきます。

このサービスはO:der Platformの心臓部として、シンプルさを保つことを意識して開発を進めています。

利用技術
・言語: Go
・ソフトウェアアーキテクチャ: Onion Architecture
・API: gRPC
・インフラ: EKS

プラットフォームのコア機能として手堅く実装をしたいと考え、Onion Architectureを採用しました。開発手法としてもDDDを導入し、モデリングを随時行いながら開発を進めていく方針です。GoでOnion Architectureを採用したことによるメリットデメリットはそれぞれありますが、少なくとも、ドメイン層の実装は快適に行うことができています。

Instore

画像4

Instoreは、店舗スタッフの方とO:der Platformのインターフェースとなるサービスです。プラットフォームが受け付けた注文をスタッフの方に提示したり、調理が完了した注文のステータスを変更したり、といった役割があります。

注文の提示手段も店舗のオペレーションによって様々ですが、代表的なのは以下の2パターンです。

・キッチンディスプレイに表示し、インタラクティブにステータスを変更する
・キッチンプリンタによる単票を印刷する。以降は単票にペンで書き込むなどして注文のステータスを管理する

Instoreの技術的なポイントとしては、Instoreサービスとキッチンプリンタ、キッチンディスプレイといったエッジデバイスとの通信はgRPC Server Streamingを利用している点です。

また、キッチンディスプレイなどのエッジデバイスが店舗に複数存在する場合、それら複数の端末の内部状態は同期しておきたいものです。 一方で、店舗機器の通信状態は様々であるので、Push配信によってエッジデバイスが内部状態を更新していく過程で通信トラブルなどによって機器間でのデータ不整合が起こらないよう、Instoreサービスでエッジデバイスの内部状態を管理するような「Board」と呼ばれる機能も提供しています。

利用技術
・言語: Go
・API: gRPC (Unary call / Server Streaming)
・インフラ: ECS Fargate
・エッジデバイス(アプリケーション)開発: Flutter / Android
・そのほか: 上記Instoreサービスに加えて、デバイス認証サービスなどがモジュラーモノリス構成で同居

Instoreは、社内サービスで初めてgRPCを本格的に利用したサービスです。Unary callだけでなくStreamingも扱うなど、かなり野心的にチャレンジをしました。

POS連携

「飲食店を支える」プロダクトとして、POSシステムとの連携は欠かせません。

POSシステムとの連携においては、まずPOSシステムのインタフェースによって「どういう連携が可能であるか」「POS×モバイルオーダーにおいて、どういった業務オペレーションを提供できるか」といった点を考えながら連携仕様を検討する必要があります。そのため、連携先のPOSごとにアダプタとなるサービスを構築しています。

利用技術
言語: Go
API: OpenAPI
インフラ: ECS Fargate
そのほか: フレームワークとしてgoaを利用

なぜAPIがgRPCでないかといえば、社内のデファクトとしてgRPCが採択される以前の立ち上がったサービスだからです。一方で、社内で初めてGo言語を使った本格的なサービスであったりもします。

O:der Table / ToGo / Kiosk

O:der Platformを利用して実装されたモバイルオーダーサービスです。プラットフォームを利用して実装されたプロダクトであり、ユーザー体験の磨き込みや、必要とされる機能拡充を高速に行っていきます。

利用技術
・言語(バックエンド): Go
・ソフトウェアアーキテクチャ: Onion Architecture
・API: HTTP API
・インフラ: EKS
・Webフロントエンド: React / TypeScript
・そのほか: バックエンドはモジュラーモノリス構成(テイクアウト・イートイン)

私たちの利用する技術スタック

ここまでお読みいただきありがとうございました。

注意深く読まれた方におかれましては、「サービスによって技術スタック違いすぎないか...」と思われるでしょうか。開発言語についてはGoで統一されている一方で、Instoreはモジュラーモノリス、Platform Coreはモノリス。ほかにも、インフラがEKSであったりECSであったりします。

それらは、新規サービスの構築にあたって「1つは挑戦をしてみる」ことが良いと考えているからです。

・POS連携サービスにおいてはgoaを利用してみたり
・InstoreサービスではgRPC
・Platform CoreではEKS

等々。

挑戦とその振り返り

もちろん、挑戦をしっぱなし、というわけではありません。

たとえばInstoreで採用したgRPCについては「これはやはり良いよね」ということでその後のプロダクトにおいても採用され、今では「私たちのプロダクトにおけるサービス間通信ではgRPCを使おう」という標準ができあがりました。

一方で、POS連携サーバでのチャレンジであるgoaについては、良い面もありつつなかなか癖もあり、全社で利用するには至りませんでした。(断じて、goaが悪いという意図ではないです。少なくとも私は好きな技術です)

加えて、各サービスはそれぞれが担当するチームによって運用されています。ですので、チームの裁量の中でやりたいことをやろう。そのほうが楽しいよね、という気持ちを大切にしたいと思っています。

終わりに

以上、私たちのプロダクトにおける主要なサービスと技術スタックの紹介でした。

現状、「Go言語を使う」という軸はありつつ、その中で技術的に最大限にチャレンジしながら開発できる環境でありたいと考えています。そんな話をした直後ではありますが、私はいまRustを書きたいです。困った。

次回は O:der ToGo開発チームを牽引するtasakaさんの記事です。ブルドーザーのような推進力を持つエンジニアである彼の記事がどんな内容となるか楽しみです。

それではまた来年お会いしましょう。

この記事が気に入ったらサポートをしてみませんか?