2017年3月30日木曜日

サーバーサイドをNodeからSwiftに移行する

勉強の為に引用しました。


読了時間20分
こんにちは。リードアーキテクトのItoです。最近アナログオーディオをやっているのですが、つらい事件が起きました。
今月はじめにSwiftのコンパイラなどのソースコードがGithubで公開され、かなりの反響を呼びました。コンパイラだけではなく、パッケージマネージャやコアライブラリ、今後のマイルストーン、コーディング規約など、Swiftが一つのエコシステムとして公開されたことで、さらに盛り上がりを見せている気がします。
また、3月にはtry! Swiftという世界的なカンファレンスが渋谷・東京で行われるので、面白い四半期になりそうです。私もチケットを購入したので行く予定です。
カメリオは、iOS版がSwift、バックエンドのサーバーがNode.jsとPythonで書かれています。また、サーバーのAPIは、フロントAPIとバックエンドAPIに分かれ、マイクロサービス化がなされています。
iOSのSwift化の話についてはこちら、マイクロサービスの構成についての話はこちらをご覧ください。
今回はサービス全体をSwiftに移行しようという話なのですが、フロントAPIサービスを移行する場合について考えてみます。
フロントAPIは、Node.js(Express)で書かれたAPIサーバーで、仕事は、主にiOS版、Android版、Web版のAPIリクエストを受け付けます。また、セッションを管理したり、ユーザーの情報(フォローしているテーマ一覧・クリップ機能・広告・課金)などを処理するAPIを提供します。記事や分類に関する処理はバックエンドのPythonベースのサーバーが主です。
Nodeは最近v4系にアップデートされ、ES6の一部機能や、Promise、Generators(yield)などが使えるようになって、コールバックを意識せずに非同期処理を簡潔に書けるようになりました。最近新しく書いた部分に関しては新しい機能が使えてよいです。
var rows = yield db.execQuery(conf.USER_DB, “SELECT user_id, user_name, tw_id, fb_id FROM user_info WHERE user_id = ? LIMIT 1”, [req.user.user_id])
※yieldで非同期処理(SQLクエリの実行)を行う
従来のコールバックベースに比べてとても便利になりました。標準のNodeとcoというライブラリがあればPromiseをyieldとして使えたり、将来のasync, awaitに対応できるようになります。
Node(とJS)の特徴は、
  • JavaScript(v8)・ES6
  • 動的型付
  • 高速
  • 非同期の動作が保証される
  • モダンなパッケージとバージョン管理
(※ここで非同期というのは主にファイルやネットワークのIOが非同期であるという意味で使います。)
しかしながら、Nodeを書くための言語はJavaScriptということに変わりはなく、実際にサーバーを書いたり、テストしていると、JavaScriptの言語仕様にゆるさから、もう少し新しい設計の言語を使いたくなってくる気持ちもあります。
それでもJS(v8エンジン)自体は今では高速かつ安定に動作し、Nodeの発展と実用性の証明に貢献してきたと思いますが。
弊社で提供している法人向けカメリオAPIはGoを使って実装されています。開発時の話はこちら。Goもある程度社内で使ってきた言語で、
  • 静的型付
  • 高速(実行・コンパイル)
  • 言語仕様はC言語に近い
  • 非同期動作はライブラリ依存
  • パッケージ管理
のような特徴があります。
Goはかなりよく動いてくれましたが、Nodeに比べると、言語仕様が少し弱く、特に機能追加・変更の多いカメリオアプリのAPIにはあまり向かないように思います。
(実際、NodeからGoの置き換えも検討しましたが見送りました)
逆に、法人向けAPIのような機能追加や変更が少ない、常に安定させるサービスにはとてもよいです。
Swiftの特徴は、
  • 静的型付かつコードが簡潔
  • 高速(実行)
  • 型推論
  • モダンな設計
  • 強い表現力
  • コンパイルが遅い(現状)
  • 非同期動作はライブラリ依存
  • モダンなパッケージとバージョン管理
のようなものがあります。
iOSですでに使っている方ならお分かりですが、言語の設計が新しく、とても強力です。また、状況に応じて使えるさまざまなパターン(石川さんのスライドが詳しい)が使えるため、簡潔かつ安全に書けるようにもなります。それでいても、コードと見た目が短いところも大きいです。
逆にいえば、新しく・強力な言語であるため、言語仕様の拡張や変更も大きく、学習コストもかなり大きいことに違いはありません。
そこに関しては社内で継続的に勉強会をしたり、コードレビューをする必要がありますね。
基本言語やフレームワークを移行するのは、どうしてもやりたい人が中心に社内をドライブしていかないと、うまくいかないと思います。
さて、SwiftでWebサーバーを作るには何が必要でしょうか。
サーバーは出力にJSONのみを扱うため、HTMLについてはレンダリングできなくてもよいです。
だいたいこのくらいのライブラリが必要になってくると思います。
  • TCPサーバー
  • HTTPパーサー
  • JSON デコーダー・エンコーダー
  • ルーティング
  • Redisクライアント(ドライバー・アダプター)
  • MySQLクライアント
  • HTTPクライアント
  • JSON RPCクライアント
現状のAPIを移植する場合、ORMまでは必要ないですが、Nodeのmysqlのような最低限のものがあるといいです。
JSON RPCクライアントはバックエンドのサーバーと通信するときに使いますが、無ければ自分で作ってもいいかもしれません。
既知の問題は、各ライブラリがうまく非同期または何かの仕組みの上で、IOをブロックせずに動くかです。同期動作のライブラリはいくつかありますが、折角なので非同期のような仕組みに対応したライブラリを使いたいものです。
最近を見ていると、サーバーのライブラリはZewoが活発に動いているようです。
Webサーバー一式はもちろん、テンプレートエンジン・SSL・SQLなど一通り作られています。
RedisもGithubで探すといくつかあります。
さて、SwiftのMySQLのクライアントもすでにいくつかあるのですが、node-mysqlっぽく使えて、しっくり来るものが欲しかったので作ってみました。これをベースに既存のサービスを実験的に実装してみたいと思います。
クエリは生のSQLですが、クエリー文と結果のModelに関してはなるべくSwiftの型システムを使えるようにしました。
今のところCベースのlibmysqlclientを使用しているので、Nodeのように非同期IOとまではいきませんが、ある程度型ができてきたら、非同期も対応する予定です。
ただ、Swiftで使える非同期のMySQLクライアントライブラリが無いので、プロトコルも実装するしかないかな…
まだまだLinuxやサーバーサイドのSwiftは始まったばかりです。NodeのExpressやKoaのように、Middlewareの設計のパターンも型が決まってない状態です。Swiftの便利さをサーバーサイドでも使いたい人が増えればライブラリも増えてくるかもしれません。
基本的にはNodeのエッセンス(非同期・小さいライブラリなど)を踏襲しつつ、Swiftの型を取り入れたいと思います。
今後も引き続きAPIサーバーのSwift化に向けて、検証等を積極的にしていく予定です。
最先端情報吸収研究所 – AIAL
際限ない情報の中から、自分に価値のある情報を効果的に吸収することは、かつてなく大きなチャレンジです。最先端情報研究所はニュースアプリ「カメリオ」、レコメンドエンジン「カメクト」を提供する白ヤギコーポレーションのR&D部門として、データサイエンスの力でこの問題を解決していきます。白ヤギでは現在研究開発メンバーを募集しております。ご興味のある方は是非下記サイトを御覧ください!

0 コメント:

コメントを投稿