Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
サーバサイドDartを試してみた
Search
ANDPAD inc
February 25, 2021
Programming
3
4.5k
サーバサイドDartを試してみた
2021/02/24 ANDPAD TechLive #2 Flutterって実際どうなの?設計からテストまで
ANDPAD inc
February 25, 2021
Tweet
Share
More Decks by ANDPAD inc
See All by ANDPAD inc
Catch Up: Go Style Guide Update
andpad
0
260
OSS開発者という働き方
andpad
5
1.8k
Vue・React マルチプロダクト開発を支える Vite
andpad
0
150
プロダクト開発を支えるデータ利活用:中央集権から「民主化」までの軌跡
andpad
0
190
アンドパッドの Go 勉強会「 gopher 会」とその内容の紹介
andpad
0
410
読もう! Android build ドキュメント
andpad
1
460
アンドパッドにおける CocoaPods ライブラリ群の SwiftPackageManager への移行戦略
andpad
0
240
Flutter は DCM が 9 割
andpad
1
370
Amplify で SPA をホスティングする際の注意点
andpad
1
330
Other Decks in Programming
See All in Programming
Six and a half ridiculous things to do with Quarkus
hollycummins
0
220
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
290
O Que É e Como Funciona o PHP-FPM?
marcelgsantos
0
200
Range on Rails ―「多重範囲型」という新たな選択肢が、複雑ロジックを劇的にシンプルにしたワケ
rizap_tech
0
7.7k
CSC305 Lecture 11
javiergs
PRO
0
280
AI時代に必須!状況言語化スキル / ai-context-verbalization
minodriven
2
100
NixOS + Kubernetesで構築する自宅サーバーのすべて
ichi_h3
0
1.2k
Things You Thought You Didn’t Need To Care About That Have a Big Impact On Your Job
hollycummins
0
260
AI 駆動開発におけるコミュニティと AWS CDK の価値
konokenj
5
270
One Enishi After Another
snoozer05
PRO
0
160
Developer Joy - The New Paradigm
hollycummins
1
370
Ktorで簡単AIアプリケーション
tsukakei
0
110
Featured
See All Featured
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.5k
Speed Design
sergeychernyshev
32
1.2k
The Illustrated Children's Guide to Kubernetes
chrisshort
49
51k
Producing Creativity
orderedlist
PRO
347
40k
Embracing the Ebb and Flow
colly
88
4.9k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4k
Designing for Performance
lara
610
69k
Learning to Love Humans: Emotional Interface Design
aarron
274
41k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.2k
GraphQLの誤解/rethinking-graphql
sonatard
73
11k
Docker and Python
trallard
46
3.6k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
1.7k
Transcript
サーバサイドDartを試してみた バベルの塔以前の世界へ ANDPAD Tech Live #2
1. 動機 2. なぜDartでサーバを実装するのか 3. サンプルの構成 4. サンプルのポイント解説 5. 感想
6. 実戦投入のはじめの一歩 目次 ※ FlutterやgRPCの基礎知識があることを前提にしている。本資料では、これらの詳細には触れない。
• サーバ、Webフロント、モバイルアプリで言語がばら ばらのせいか、相乗効果がない ◦ バベルの塔の建設現場っぽい • サーバのコードを読まないと、Web APIの仕様が分か らないことがある ◦
モバイルアプリエンジニアからすると、サーバの言語とツー ルに馴染みがないのでつらい 1. 動機(問題意識) 主は、人の子らが作ろうとしていた街と塔とを見ようとしてお下りになり、そして仰せられた、「なるほど、彼らは一つの民で、同じ言葉を話して いる。この業は彼らの行いの始まりだが、おそらくこのこともやり遂げられないこともあるまい。それなら、我々は下って、彼らの言葉を乱して やろう。彼らが互いに相手の言葉を理解できなくなるように」。 — 「創世記」11章1-9節
• サーバ、Webフロント、モバイルアプリで言語を統一 する ◦ ノウハウの共有ができる ◦ 担当外のコードも読みやすい ◦ フルスタック開発もできる 1.
動機(解決案)
• フルスタック開発ができる言語は2つ ◦ Javascript(Typescript込み) ◦ Dart • モバイルアプリ開発では、Javascript(ReactNative)よ りも、Dart(Flutter)の方が勢いがある 2.
なぜDartでサーバを実装するのか ※厳密にいえばGoなどでも全部開発できるが、この 2つの言語以外はロマンだと思う。
• サーバをDartで実装してみました ◦ サンプルコード ▪ https://github.com/KamikazeZirou/dart-ser ver-sample ◦ おなじみのTodoアプリ ▪
バックエンドのAPIのみ 3.サンプルの構成(概要)
3.サンプルの構成(アーキテクチャ) Repository MySQL Domain Model Service gRPC Handler API Client
Handler:APIのエントリポイント。データ形式の変換をして、 gRPCを隠蔽する。 Service:ビジネスロジックを担当。ロジックが単純すぎるので Repositoryのメソッド呼ぶだけ。 DomainModel:データとビジネスロジックを持つ。サンプルは単純すぎるので単なる構造体。 Repository:データのCRUD機能などを提供。データの保存方法を隠蔽する。 円の外から内の依存関係は良いが、逆は NG。 Dart Server
ライブラリ バージョン 備考 Flutter 1.26.0.17.6.pre beta channel, Dart 2.12。 grpc
3.0.0 このバージョンではDart 2.12以上が必要。 protoファイルからのコード生成は割愛。 公式の説明をお勧めします。 https://grpc.io/docs/languages/dart/ mysql1 0.17.1 MySQLドライバ。 riverpod 0.13.0-nullsafety.3 DIに使う。 3.サンプルの構成(利用ライブラリ) mysql1以外は、モバイルアプリ開発でも珍しくはない
3.サンプルの構成(開発環境) ツール 説明 Docker MySQLサーバとDartサーバを動かす用。 Dockerを使わなくてもサーバは起動できるが、実務ではコンテナとしてデプロイ することが多いので Dockerを使う。 protoc gRPCのAPIを定義するprotoファイルから各言語のコードを生成するツール。
protoc_plugin protoファイルからDartのクライントコードとサーバコードを生成するツール。 Dart のプラグイン。 Android Studio コードエディタ。サーバ独自の設定は不要。 もちろん、InteliJやVSCodeでもOK。
3.サンプルの構成(開発環境) service TodoService { rpc CreateTodo (CreateTodoRequest) returns (CreateTodoResponse) {}
} message Todo { int32 id = 1; string title = 2; string description = 3; } message CreateTodoRequest { // 作成するTodo Todo todo = 1; } message CreateTodoResponse { // 作成したTodo Todo todo = 1; } 補足:gRPCのコード生成 protoファイル Dart コード Go コード JS コード protocで 生成
4.サンプルのポイント解説(main) void main(List<String> arguments) async { final container = ProviderContainer();
var listener = container.listen(todoServiceHandlerProvider); // 1. serviceHandler の作成 final serviceHandler = await listener.read(); // 2. serviceHandler をgRPCのServerに登録 final server = Server( [serviceHandler], const <Interceptor>[], CodecRegistry(codecs: const [GzipCodec(), IdentityCodec()]), ); // 3. サーバ起動 await server.serve(port: 5001); ... }
4.サンプルのポイント解説(Handler) // 1. Handlerにはprotocが生成したAPIサーバ用の基底クラスを継承させる class TodoServiceHandler extends TodoServiceBase { //
2. APIに対応するメソッドがあるのでoverrideする @override Future<grpc.CreateTodoResponse> createTodo(ServiceCall call, grpc.CreateTodoRequest request) async { // 3. データをgRPC -> domain形式に変換 // 4. Serviceのメソッドを呼ぶ final newTodo = await _todoService.create(domain.Todo( title: request.todo.title, description: request.todo.description, )); // 5. Serviceの処理結果をgRPC形式に変換して返す return CreateTodoResponse( todo: grpc.Todo( id: newTodo.id, title: newTodo.title, description: newTodo.description, )); } } 形式変換をするのは、 Service がgRPCに依存しないようにす るため。
• Service ◦ サンプルではRepositoryのAPI呼ぶだけ • Repository ◦ モバイルアプリの時と同じように実装すればOK 4.サンプルのポイント解説(Service/Repository)
riverpodを使用。 Handler、Service、 Repositoryのオブジェクト のProviderを実装。 // MySQLConnection のプロバイダ final dbConnectionProvider =
Provider.autoDispose((ref) async { ... final connection = await MySqlConnection.connect(settings); ... return connection; }); // Repository のプロバイダ。 // ref.watch で依存オブジェクトを取得する。 // ここでは、MySQLConnection を取得している。 final todoRepositoryProvider = Provider.autoDispose((ref) => ref.watch(dbConnectionProvider).then((conn) => MySQLTodoRepository(conn))); final todoServiceProvider = Provider.autoDispose((ref) => ref .watch(todoRepositoryProvider) .then((repository) => TodoServiceImpl(repository))); final todoServiceHandlerProvider = Provider.autoDispose((ref) => ref .watch(todoServiceProvider) .then((service) => TodoServiceHandler(service))); 4.サンプルのポイント解説(DI)
マルチステージビルドを使う。 ビルド用と実行用でイメージを分け ることで、実行イメージのサイズを 抑える手法。 ビルドに使うDockerイメージのサイ ズは約250MBある。Dart SDKなど が含まれるため。 実行用のDockerイメージは、開発 用のツールが一切入っていないの
でサイズは約2.2MB。 (ビルドしたバイナリファイルのサイ ズは約8.7MB) 4.サンプルのポイント解説(Docker) # ランタイムなしで実行可能なサーバのバイナリファイルをビルドするイメージ FROM google/dart:2.12-beta as builder WORKDIR /app ADD pubspec.* /app/ RUN pub get ADD . /app RUN pub get --offline RUN dart compile exe bin/server.dart -o bin/server # ビルドしたバイナリを実行するイメージ FROM subfuzion/dart:slim WORKDIR /app COPY --from=builder /app/bin/server . CMD [] ENTRYPOINT ["./server"]
4.サンプルのポイント解説(docker-compose) • Docker単独よりもサーバの実行が簡単にできる ◦ サーバの起動時のコマンドがDockerコマンドよりも簡潔に なる ◦ コンテナ間の依存関係を設定できる ▪ DBのコンテナをDartサーバのコンテナより先に実行できる
4.サンプルのポイント解説(client) Future<void> main(List<String> args) async { // 1. gRPC接続チャンネルを作る final
channel = ClientChannel( 'localhost', port: 50051, options: ChannelOptions( credentials: ChannelCredentials.insecure(), codecRegistry: CodecRegistry(codecs: const [GzipCodec(), IdentityCodec()]), ), ); // 2. protoファイルから生成したClientのオブジェクトを作る final stub = TodoServiceClient(channel); // 3. gRPCのAPIを呼ぶ。 try { final response = await stub.createTodo( CreateTodoRequest( todo: Todo(title: 'title3', description: 'description3')), options: CallOptions(compression: const GzipCodec()), ); } catch (e) { ... } await channel.shutdown(); }
• 良かったこと ◦ アプリ開発とノウハウは共有できる ▪ riverpodは初めて使ったが、モバイルアプリ開発にも知見を転用でき る ◦ Dartの書き方をほぼ忘れていたが、Goよりは書きやすい ▪
並列処理が出てきたら、感想は変わりそう • 懸念 ◦ サーバ向けライブラリが充実していない ▪ 有力なORMが少ない • Web Framework Aqueductの一部としてならORMあるが・・・ ▪ AWSの公式SDKはなさそう・・・ 5.感想
• モバイルアプリ用のAPI Gatewayで採用する 6.実戦投入のはじめの一歩 BFFでは、API GatewayはAPIクライアント ごとの要件に沿って実装する。 開発の担当は、APIクライアント開発者が 良いらしい。クライアントの要件に詳しいの は、クライアントの開発者のため。
モバイルアプリ開発者が慣れている Dart をAPI Gatewayに採用すると、開発効率 は上がるはず。 ※今のANDPADにはAPI Gatewayなし
ANDPADでは、マイクロサービスを開発する メンバーを募集しています! こんな方におすすめです。 • アプリ開発以外もやってみたい • ユーザの業務を考えつつ開発をしたい • サービスの基盤を考えたい 最後に
番外 言語 MSにたとえると 補足 Kotlin ゲルググ Dart リック・ドムⅡ C# ドワッジ
Java ドム Go イフリート グフとドムの中間。 Rust グフ ゲームだと格闘が強い。使ったことはない。 C++ ザク C 旧ザク GCの壁