Goのgoaを使ったAPIデザインまででイケてるところ
goa goa goaでAPIデザインまでしてみた
GoのWAFであるgoaの最大の特徴であるAPIデザインまでやって、イケてるなと感じた点を挙げてみました。
結論
goaにはDSLというものがあって、それを覚えるのが「最初はだるい」ですが、覚えてしまえば、すぐに追加や修正が出来るのと、最初の時点で設計をしないと開発に入れないので、今まで以上にどういう設計にすべきかを考えれるので、僕のようなすぐに手を動かしちゃう人には良い。
現時点でイケてるなと感じた点
現在、goaは趣味で開発しているアプリのバックグラウンドに使う目的で開発をしています。
セキュリティ周りのロジックが簡単に適用できる
端末の識別に使うtokenなどをHTTPのヘッダーに含めて、それが正しいものをかを毎回チェックしたりするのですが、そのチェックのロジックを全てのエンドポイントで行うわけではなく、必要な時とそうじゃない時の2パターンがありました。
goaでは、そのチェックロジックgあ以下のように簡単に記述することが出来ました。
セキュリティ · goa :: Design-first API Generation
examples/security at master · goadesign/examples · GitHub
ヘッダーチェックロジックの定義(標準で用意されている)
var UserAuth = APIKeySecurity("key", func() { Description("ユーザートークン") Header("X-Authorization") })
適用する
var _ = Resource("users", func() { BasePath("/users") Security(UserAuth) <-----/user以下のエンドポイントでヘッダーのチェックをする // このエンドポイントは特殊でチェックしたくない。 Action("tmp account create", func() { Routing( POST("/tmp"), ) ~~~~~~ NoSecurity() <------/user/tmpではチェックしない Response(OK, Token) Response(BadRequest, ErrorMedia) }) // ▼チェックされる▼ Action("account create", func() { Routing( POST("/new"), ) ~~~~~~ Response(OK, Token) Response(Unauthorized) Response(BadRequest, ErrorMedia) }) Action("list", func() { Routing( POST("/"), ) ~~~~~~ Response(OK, User) Response(Unauthorized) Response(BadRequest, ErrorMedia) }) // ▲チェックされる▲ })
まあ、便利!wという感じでしたね。他にもデフォルトでチェックのロジックはgoaで用意されており、ごく普通なアプリを開発するには困らなさそうでした。
パラメーターのバリデーションが行える
地味にかったるいバリデーション。ですが、やらない訳にもいかない。しかし、だるい。
goaはとても簡単にこの問題を解決してくれます。
Param("email", String, "メールアドレス", func() { // メールのフォーマットになっているかチェック Format(goa.FormatEmail) }) Param("client_version", String, "アプリのバージョン") Param("platform", String, "OSとバージョン") Param("identifier", String, "識別子(android:Android_ID, ios:IDFV)", func() { // 正規表現 Pattern("(^[a-z0-9]{16}$|^[a-z0-9\\-]{32}$)") }) Required("email", "client_version", "platform", "identifier")
他にも文字数チェックやEnum形式で特定の文字列だけを許可したりなど、いい感じにバリデーションしてくれます。 · goa :: Design-first API Generation
Swagger食わせるだけでAPIドキュメントが出来上がる
実際に作成したDSLをSwaggerのフォーマットに合ったjsonとyamlファイルを作成してくれます。これに関してはすごいの一言でしたね。。。
見たほうが早いので、以下に自分の作成したものの実例を貼っておきます。
Build, Collaborate & Integrate APIs | SwaggerHub
作らないといけないけど、正直面倒なドキュメント。goaは強制的にドキュメント作成されるので、共同開発する上で最高です。
ビジネスロジックに集中が出来る
goagenコマンドを実行して、フォルダ移動を多少必要としますが、ビジネスロジックが全てcontrollerパッケージにまとまります。
※controllerとserverフォルダはデフォルトではありませんが、私の好みで作成してます。
. ├── LICENSE ├── Makefile ├── README.md ├── app ├── client ├── controller <----------ビジネスロジックを書く(雛形は自動生成される) │ ├── events.go │ ├── genres.go │ ├── prefs.go │ └── users.go ├── design <----------APIでざいんを書く │ ├── api_definition.go │ ├── media_types.go │ ├── resources.go │ └── security.go ├── glide.lock ├── glide.yaml ├── server │ ├── app.yaml <-------GAEの設定ファイル │ └── main.go <-------ミドルウェアの定義など(雛形は自動生成される) ├── swagger │ ├── swagger.json │ └── swagger.yaml ├── tool └── vendor
DSLで定義したセキュリティ周りやバリデーションなどは、自動的に生成されているので、組む必要がありません。そのため、コントローラがビジネスロジックだけを組めばいい状態になり、シンプルで目的がハッキリとしたコードにすることが出来ます。これはいつもごちゃごちゃになりがちな自分にとっては嬉しかったです。
goaは面倒なところもあるけど、結構良さそう
他にもイケてる点はありますが、とりあえず、印象的だった点を挙げてみました。これから実装に入るところなので、最終的な生産性に関して未知数ですが、微妙にだるい点などもいくつかあるので、うまく解消する方法などが見つかったら紹介していきたいと思います。
Realm World Tour 17 Mobile DatabaseとRealm Mobile Platformについて
そもそもRealmってどういうもの?からRealm Mobile Platformはどういった経緯で、開発がスタートしたのかが分かりやすかったので、記事にしました。
※聞き起こしに近いので、誤字脱字やニュアンスが違う可能性があります。
The Realm Mobile Platform Experience
Realmは様々なプラットフォームに対応しています。
正式版がリリースされてから、多くの企業に使われています。恐らく世にあるアプリの一箇所以上は使われているのではないかと思います。
データベースのエンジンはモバイルに最適化するために、フルスクラッチで作成されています。そして、様々な便利な機能が盛り込まれています。
ライブオブジェクトであったり、リアクティブであることが特徴ですが、その中でもデータベースの特徴であるライブオブジェクトを使って、リアルタイム性のあるの良いものを作ろうと考えています。
例えばRealmのライブオブジェクトを使うと、自動的に要素が更新されますので、毎回フェッチする必要がなくなります。それをうまく使うことでスマートにリアルタイム性のあるアプリケーションを作ることが出来ます。
Realmの動作フロー
この図は、Realmの重要なフローを表しています。
最初はオブジェクトとのAPIです。
スライドにあるように、まずはRealmのオブジェクトを作成します。使い方は簡単でクラスを作成するだけで使うことが出来ます。特にデータモデルを定義するための中間ファイルなどは必要ありません。またRealmのためのミドルウェアも必要がなく、シンプルに使えることがRealmの最大の特徴です。
このRealmのモデルには、自由にプロパティを設定する。メソッドを定義することが出来ます。またリレーションもプロパティを使うことで関連付けの表現をすることも出来ます。SQLのように高度な記述は必要なく、単純にポインタでの関連付けなので、シンプルにデータを取得することが出来ます。
作成したオブジェクトを使うには、クエリを使って取得する必要があります。クエリを使ってオブジェクトを取得すると、Resultを使って結果を取ってくることが出来ますし、関連しているデータも取得することが出来ます。
関連には逆方向関連も使うことが出来、それはプロパティを使うことで実現することが出来ます。Realmのクエリで自由なことは、クエリのために使ったメモリをコピーせずに使うことが出来るので、メモリ消費がほとんど発生しません。
これが実際に構築されたクエリです。見たらわかると思いますが、すごく簡単なことがわかります。この例ではageが2以下のものを検索していますが、もし、このageの内容が変わった場合は、自動的に更新されているので、検索結果を再読込することを気にする必要がありません。また、変更があったことは通知もできるので、アプリ側はそれに従って動けばいいだけなので、簡単に機能を実現することが出来ます。
さらに、Realmはできるだけメモリのコピーをしないようにしているので、例えばこのクエリの場合、全てのデータを取ってるように見えますが、アクセスされるまでメモリを確保されないので、全てのデータを取っているわけではなありません。そのため特別な処置を必要としません。
Realmのクエリの結果、または関連のオブジェクトに変更があった場合、通知を用いて画面の再描画をすれば良いです。
その通知の例がこちらのスライドになります。この通知では、何が変更された追加された削除されたという情報が細かく通知されます。これを使うことで部分更新やきれいなアニメーションを使った再描画が可能となっています。例えば、アプリケーションで犬専用のインスタグラムがあったとします。その場合、このスライドのようなクエリを書くことになります。そして、更新があったら通知を使って、データを更新するのですが、追加の通知を乱暴にすることなく、何が通知されたかを適切にユーザーに見せることが出来ます。
ネットワークからデータを取ってくるだけではなく、ユーザーによる並べ替えや更新などによって変更がされることもあります。それにはトランザクションを使います。
Realmはトランザクションによってまとめた変更や削除などをひとつの処理として扱うことが出来るので、データの整合性を確保することが出来るので、処理が完了していないデータなどが見えてしまうことがありません。
ここまでの流れがRealmの基本動作になります。Realmは高速でモバイルデータベースを提供しています。
Realm Mobile Platform
今まではモバイルデータベースを提供してきましたが、もうひとつモバイル開発者が考えていることがあると思います。それはRDBMSなどのデータベースとの連携だと思います。その解決のために考案されたのが、Realm Mobile Platformになります。
誰もがアプリ作成のためにデータの同期をサーバとやることがあると思います。その作業をシンプルにしたくても、思わぬトラブルや難しい問題に直面することがあります。
その問題を表現する時に我々はこの氷山を使った説明をします。
この図の上の部分は、データを更新して、UIへ反映してという単純な部分を表していますが、この処理だけでも色々な問題が介在していて、簡単ではありません。
サーバーからデータを取得して、保存が出来たとしても、別のユーザーの変更も考慮しなければいけなく、一筋縄ではいきません。
Realmを使ったデータ管理の場合とRestAPIの比較図になります。
従来のやり方では、JSONのパースなどの処理が必要でしたが、Realmの新しいプラットフォームでは、一切そういった操作は必要がありません。サーバーとクライアントで双方向の通信をしていて、それは全て自動で行われています。例えば、データの更新の衝突した場合でも、こちらで用意したルールに従って処理が行われますので、ケアをする必要はありませんし、CPUやメモリの消費も最小限に抑えられています。
なので、Realmを使う場合は、赤い枠の部分だけを気にすれば良いと言うことになります。先程までに詳解した自動同期などは全てRealmがカバーしてくれますので、今まで通りローカルのデータベースを使うようにやれば良いだけです。唯一違うことは、バックグラウンドスレッドで更新がされる場合と同じように、他のデバイスの変更の通知を知る術を用意する必要はあります。
本当に簡単になります。データの変換も必要ありませんし、今までは一回の処理のために複数回APIを叩くこともあったかもしれませんが、それが全て任せれるようになります。
ネットワークが繋がっていれば、いつでも使うことが出来ますし、データも差分だけなので最小限に済ませるようにしています。Push Notificationを使ったBackgorund Fetchも少ない時間で終わらせることが出来ます。
よくある通信のあるモバイルアプリはサーバーとの通信、JSONとのやり取りがあると思います。それはスパゲッティのように複雑になりがちです。普通にやるとメンテナンスコストがかかると思います。
これが実際にRealmで行った時の図になります。このようにものすごくシンプルになっていることが分かると思います。また、一部分だけRealmを使うなども出来るので、シンプルに導入することが出来ます。
サーバー側のコードもRealmを使うときと同じように使うことが出来ます。
これはサーバー側でRealmを使った時のコード例になります。いまのところはNodejsを使って構築することになっています。サーバーサイドのRealmでの変更はトランザクションを用いて更新します。
このスライドにあるように、同期に加えて他にも多くの機能を提供しています。ユーザーの認証だったり、エンタープライズのみになりますが、スケーリングなどもあります。これについては後でDemoを致します。
Realmはサーバーサイドとクライアントで同期はもちろんですが、双方向のやり取りや継続的なバックアップ機能も提供しています。
岸川さんがマリウスさんに、漢字の書き方を教えるDemoの様子。
リアルタイム同期なので、書き方はもちろん書き順も教えることが出来ます。
以下に動画があるので、そちらで参照出来ます。
Realm: リアクティブなモバイルアプリを短期間に
Realm Mobile Platformを使ったソースも公式から公開されています。
Realm Demos · GitHub
Realmのウェブサイトから、demoを取得することが出来ますので、ほとんどの機能を試せるようになっています。
DeveloperエディションとPlatformエディションの2つがあり、platformエディションは月々$1,500がかかりますが、2ヶ月のトライアル期間があります。違いとしては、サーバーサイドから変更の通知や同期などが使えるかどうかです。クライアント側での同期だけなら、無料で使えます。
Realm Pricing
Realmは人材採用をしてます!
多くのエンジニアがリモートで働いています。もし、リモートワークに興味がある方がいましたら、是非チェックしてみてください。
当日のゲスト枠の発表
Realm Mobile Platformについての情報
Go Con 2017スライドまとめと感想
GoCon2017参加してきました。
Go Conference 2017 Spring - connpass
Twitter上で、全国のgopherがやたらと合コンと言って、#goconをつけて呟いていたイベントです。
合コン?#gocon pic.twitter.com/qXbxth1TII
— つぶやき実験室 (@totoro5000) 2017年3月25日
いつも後で見返そうと思って、放置してURLわからなくなるので、今回はまとめることにしました。リンクが抜けているスライドは発見が出来なかったものです。
もし、あれば教えていただきたいです。
発表枠
- Coding in the context era@lestrrat
- [Goで書くエディタの壁を超える開発支援ツール@zchee]
- Go でつくる汎用言語処理系 実装戦略@Linda_pp
- Goでヤフーの分散オブジェクトストレージを作った話@ono_matope
- 実践!Go/GAE+DDDでのクローラー構築@timakin
- [GoImagick 詳解@yoya]
- How Communicating Sequential Goroutines Work@niconegoto
- How We Built Testable HTTP API Server@achiku
- 条件式評価器の実装による管理ツールの抽象化@tenntenn
- Details of net/http package@kaneshin
LT
- Go 1.7のContextをnet/httpで使ってみた@fkm
- goaを使ったAPI開発@decafe09
- デスクトップアプリを連携させる仕事を請けたので Go で書いた@Toru Furukawa
- Go言語はインフラの世界でも熱いんです@野田 真
- go 1.8 とコネクションのタイムアウト制御@t2y
- [depで管理@mizkei]
- ちいさくはじめるGoコントリビューション@haya14busa
- cgoでもクロスコンパイル@shibu_jp
- Goをカンストさせる話@moriyoshi
関連リンク
- goarista/cmd/ockafka at master · aristanetworks/goarista
- Goでかんたんソースコードの静的解析
- Big Sky :: golang オフィシャル謹製のパッケージ依存解決ツール「dep」
- Contribution Guide - The Go Programming Language
- Kubernetes, Docker Swarmって言葉よく聞くけど実はあんまりわかってない…というエンジニアに贈る。GKE概論 - Qiita
- kubernetes/client-go: Go client for Kubernetes.
- 分散サービス環境へのCircuit Breakerの適用 « LINE Engineers' Blog
- mattn/gom: Go Manager - bundle for go
- decafe09/swrt
- rhysd/gocaml: Practical functional programming language implementation with Go and LLVM
- Si案件でGo言語を使ってみた!
- いまさら聞けないselectあれこれ
- go runtime - Qiita
- ASCII.jp:Goならわかるシステムプログラミング
- Golangのcontext.Valueの使い方 | SOTA
- rubyist/circuitbreaker: Circuit Breakers in Go
- Advanced Testing with Go // Speaker Deck
- Golangにおけるinterfaceをつかったテスト技法 | SOTA
- GolangでAPI Clientを実装する | SOTA
- goパッケージで簡単に静的解析して世界を広げよう #golang - Qiita
- gographics/imagick: naive Go binding to ImageMagick’s MagickWand C API
- lestrrat/sharaq: Image Transformer
参加者としての感想
これで無料でいいのか!?というぐらい良い話を聞けました。gopherなら参加しないと勿体無いと思えるくらいの満足度でした。
カンファレンスとは直接関係ないですが、趣味で作っているITイベント検索アプリのeventory(iOS/Android)のバックエンドが、GAE/Goで動かしていまして、今回のカンファレンスでは、GAE/Goの話題が多かったので、この勢いでそろそろGoのバージョン上げてほしいなーと思っていたら・・・
カンファレンスに参加していたGoogle開発者様から希望に満ちたリプを頂きました。今後もGoの成長に期待です!@tikasan0804 1.6.x right now, 1.8 very soon.
— Chris Broadfoot (@broady) 2017年3月25日
最後に、このカンファレンスを主催された運営様、登壇者の皆様ありがとうございました!