$30 off During Our Annual Pro Sale. View Details »

Elixir で決済サービスをつくってみた

enerick
November 30, 2019

Elixir で決済サービスをつくってみた

Developer Boost 2019 の発表資料です

enerick

November 30, 2019
Tweet

Other Decks in Programming

Transcript

  1. Elixirで決済サービスを

    つくってみた
    Developer Boost 2019
    株式会社ミクシィ ID・ペイメント事業部
    橋本広⼤
    2019/11/30

    View Slide

  2. 今⽇話すこと
    つくってみた決済システムについて
    6gram サービス紹介
    決済システム概観
    Elixir でのアプリケーション開発について
    Elixir について
    Elixir の良いところ・悪いところ
    決済サービス開発で便利だったこと

    View Slide

  3. ⾃⼰紹介
    橋本広⼤(@enerick)
    株式会社ミクシィ ID・ペイメント事業部
    2016年4⽉⼊社

    → XFLAG ID の開発・運⽤

    → 幻のモバイル事業
    → 新規の決済系サービス「6gram」や

     社内決済基盤の開発・運⽤を⾏っている

    View Slide

  4. つくってみた決済システムについて

    View Slide

  5. View Slide

  6. 実は最近

    新しい決済サービスを

    リリースしました

    View Slide

  7. 決済システムについて
    ひとりでもみんなでも使えるウォレットサービス
    グループに⼊れたお⾦をシェアしたり、インスタントに発⾏したプリペイドカードに

    残⾼を割り付けたりといろんな使い⽅ができる
    ‣ JCB プリペイドカードを1アカウントで複数枚(!)発⾏できる
    ‣ Apple Pay/Google Pay と連携して QUICPay+ 決済を⾏える
    ‣ リアルカードも発⾏予定
    2019年11⽉にAndroid版をひっそり先⾏リリース
    ‣ 現在完全招待制
    ‣ 読み⽅は「ろくぐらむ」
    「6gram」サービス紹介

    View Slide

  8. 決済サービス基礎概念
    決済システムについて
    お⾦の流れには向きがある
    ⼊⾦:ウォレットへの残⾼チャージ
    出⾦:6gramカードを利⽤してウォレットから⽀払い
    それぞれで求められる役割が異なる

    View Slide

  9. 決済サービス基礎概念
    決済システムについて
    ⼊⾦⽅向でやること
    ‣ ユーザーが登録するクレジットカードや銀⾏⼝座情報の管理
    ‣ 決済リクエストの送信
    ‣ 加盟店として、カード会社や銀⾏への売上計上
    出⾦⽅向でやること
    ‣ 発⾏したプリペイドカードの管理
    ‣ ユーザーの与信管理
    ‣ 決済リクエストの受信、許可/拒否応答(オーソリゼーション)
    ‣ 利⽤された各加盟店から計上される売上に基づいて精算

    View Slide

  10. 決済サービス基礎概念
    決済システムについて
    ⼊⾦⽅向でやること
    ‣ ユーザーが登録するクレジットカードや銀⾏⼝座情報の管理
    ‣ 決済リクエストの送信
    ‣ 加盟店として、カード会社や銀⾏への売上計上
    出⾦⽅向でやること
    ‣ 発⾏したプリペイドカードの管理
    ‣ ユーザーの与信管理
    ‣ 決済リクエストの受信、許可/拒否応答(オーソリゼーション)
    ‣ 利⽤された各加盟店から計上される売上に基づいて精算
    6gramでは⼊⾦・出⾦の両⽅向で

    決済ネットワークとの接続システムから

    プリペイドカードのオーソリゼーション・精算システムまで

    すべて内製しました

    View Slide

  11. なんで内製?
    決済システムについて
    ランニングコストや PCI DSS の維持なども含めた運⽤コストを考えると初期
    にちょっと頑張って内製できるならそのほうが良いと判断
    6gram では可能な限りフルマネージドサービスを利⽤することで少⼈数でも運⽤可能
    なサーバーレス PCI DSS 対応構成を採⽤している
    ‣ 既存構成とマッチしそうなパッケージ製品はなさそうだった…
    ‣ ムリだったら運⽤コストを受け⼊れてパッケージ製品を利⽤すればよい

    View Slide

  12. なんで内製?
    決済システムについて
    「そもそもパッケージ製品って何をしてくれるんだろう…?

      接続仕様書はどのみち必要らしいし、作ってみたらわかるのでは? 」
    ある程度想像はしていたが、⼤変なことも多かった
    ‣ ⽂字通りの仕様書の⼭(紙のみ・複写禁⽌)
    ‣ 開発利⽤できる試験環境が無い
    ‣ パッケージを使わないため⼯程マシマシの試験、など
    ちなみにパッケージを利⽤してもこれらの全てから逃れられるわけではない
    しかし予定スケジュール通り⼊⾦・出⾦両⽅向の接続が完了
    サーバーレス PCI DSS 環境も保たれ結果的に後悔はない…!

    View Slide

  13. 6gram では Elixir をふんだんに利⽤しています
    決済システムについて
    Account
    アカウントや属性、認証情報の管理
    Payment
    決済に関連する情報の管理
    Gateway
    決済ネットワークとの接続・通信の管理
    その他
    決済基盤ダッシュボード、6gram 運⽤のための管理ツール

    View Slide

  14. Elixir での Web アプリケーション開発について

    View Slide

  15. Elixir ってどんな⾔語?
    Erlang VM 上で動作する
    Erlang/OTP との互換性がある
    どことなく Ruby inspired な⽂法
    マクロによる拡張性や Protocol による多相性などを加えている

    builderscon 2019 での ABEJA の⽯川さんの発表がオススメ
    ‣ builderscon tokyo 2019 - Elixir: Under the Hood - Qiita

    https://qiita.com/ishikawa@github/items/3d054f3d29920107687f
    Elixir での Web 開発について

    View Slide

  16. Elixir の良いところ・悪いところ
    Elixir での Web 開発について
    Developer Summit 2019 での gumi の幾⽥さんの発表がオススメ
    ‣ 私が愛する Elixir/Erlang の楽しさと⾟さ - Speaker Deck

    https://speakerdeck.com/cooldaemon/erlang-falsele-sisatoxin-sa
    わかりみ深い… がせっかくなので⾃分の感覚でもいくつか取り上げてみる

    View Slide

  17. Elixir の良いところ
    Elixir での Web 開発について
    ‣ Erlang VM の安定性、耐障害性
    ‣ Erlang/OTP のライブラリや資産がそのままつかえる
    ‣ コア周辺の開発・コミュニティが活発
    ‣ 公式ドキュメントがちゃんとしている
    ‣ パターンマッチ便利
    ‣ ⾮同期・並列処理が簡単にかける
    ‣ 細かい便利機能が⾊々備わっている

    View Slide

  18. 便利なパターンマッチ
    Elixir での Web 開発について
    基本的なパターンマッチ
    iex> {:ok, result} = {:ok, 13}
    {:ok, 13}
    iex> result
    13
    iex> {:ok, result} = {:error, :bad_request}
    ** (MatchError) no match of right hand side value:
    {:error, :bad_request}
    (stdlib) erl_eval.erl:450: :erl_eval.expr/5
    (iex) lib/iex/evaluator.ex:257: IEx.Evaluator.handle_eval/5
    (iex) lib/iex/evaluator.ex:237: IEx.Evaluator.do_eval/3
    (iex) lib/iex/evaluator.ex:215: IEx.Evaluator.eval/3
    (iex) lib/iex/evaluator.ex:103: IEx.Evaluator.loop/1
    (iex) lib/iex/evaluator.ex:27: IEx.Evaluator.init/4

    View Slide

  19. 便利なパターンマッチ
    Elixir での Web 開発について
    強いパターンマッチ
    先頭 2bytes に値の⻑さ、その後ろにその⻑さ bytes 分の値を持ち、

    その後ろにはまた同じ構造を持つようなバイナリ列をパースしたい
    8 "Content1" 4 "Hoge"
    2bytes

    8bytes

    View Slide

  20. 便利なパターンマッチ
    Elixir での Web 開発について
    強いパターンマッチ
    先頭 2bytes に値の⻑さ、その後ろにその⻑さ bytes 分の値を持ち、

    その後ろにはまた同じ構造を持つようなバイナリ列をパースしたい
    iex> bin = <<0, 8, "content1", 0, 4, "hoge">>
    iex> <> = bin
    <<0, 8, 99, 111, 110, 116, 101, 110, 116, 49, 0, 4, 104, 111, 103, 101>>
    iex> val
    "content1"
    iex> rest
    <<0, 4, 104, 111, 103, 101>>

    View Slide

  21. 便利なパターンマッチ
    Elixir での Web 開発について
    強いパターンマッチ
    先頭 2bytes に値の⻑さ、その後ろにその⻑さ bytes 分の値を持ち、

    その後ろにはまた同じ構造を持つようなバイナリ列をパースしたい
    iex> bin = <<0, 8, "content1", 0, 4, "hoge">>
    iex> <> = bin
    <<0, 8, 99, 111, 110, 116, 101, 110, 116, 49, 0, 4, 104, 111, 103, 101>>
    iex> val
    "content1"
    iex> rest
    <<0, 4, 104, 111, 103, 101>>
    パターン中で束縛した値をパターン中で使える。つよい

    View Slide

  22. 便利なパターンマッチ
    Elixir での Web 開発について
    ちなみに
    同様のパターンで「ある値と同じ値」も簡単なパターンで表現できる
    iex> {n, n} = {:ok, :ok}
    {:ok, :ok}
    iex> {n, n} = {:ok, 100}
    ** (MatchError) no match of right hand side value: {:ok, 100}
    (stdlib) erl_eval.erl:450: :erl_eval.expr/5
    (iex) lib/iex/evaluator.ex:257: IEx.Evaluator.handle_eval/5
    (iex) lib/iex/evaluator.ex:237: IEx.Evaluator.do_eval/3
    (iex) lib/iex/evaluator.ex:215: IEx.Evaluator.eval/3
    (iex) lib/iex/evaluator.ex:103: IEx.Evaluator.loop/1
    (iex) lib/iex/evaluator.ex:27: IEx.Evaluator.init/4

    View Slide

  23. 細かい便利機能たち
    Elixir での Web 開発について
    self-contained なリリースファイル⽣成
    mix release コマンドでランタイムコミコミのリリースを作成してくれる
    2019年6⽉ にリリースされた v1.9 から標準搭載
    ‣ アプリケーションサーバーに Erlang や Elixir のランタイムのインストールの必要
    なし
    リリースファイルのコマンドオプションでスクリプト実⾏も出来るので、バッチ処理
    も1バイナリでまかなえる
    ‣ 6gram の精算処理はこれを利⽤してアプリケーションサーバーと同じイメージを
    使って精算バッチを実⾏している

    View Slide

  24. 細かい便利機能たち
    Elixir での Web 開発について
    ETS (Erlang Term Storage) で in-memory データ保存
    ノード内に閉じたデータの保持をしたい場合に外部システムを要さずに

    ETS という OTP 組み込みのデータストレージが利⽤できる
    ‣ 直接 ETS をつかわなくても Elixir の Registry などからつかうこともできる
    ‣ 6gram では起動時にデータ読み込みが必要なモジュールで読み込み結果の保持な
    どにも気軽に利⽤している

    View Slide

  25. 細かい便利機能たち
    Elixir での Web 開発について
    簡単に⾮同期処理、並列処理が書ける
    Task で気軽に関数の⾮同期実⾏ができる
    ‣ 結果を気にしないタイプの⾮同期処理でも Task.Supervisor を使ってプロセスに紐
    付けるのを推奨
    ‣ 紐付けておくと、アプリケーションの exit シグナルをトラップして実⾏が中断さ
    れないようにしたりもできる
    Flow で気軽にリストなどに対して並列 map などができる
    ‣ ノード内での並列度のコントロールや処理の待ち合わせなどもできる

    View Slide

  26. Elixir の悪いところ
    Elixir での Web 開発について
    ‣ 動的型付けなので動かすと壊れてた・バグってたケースがままある
    ‣ よく⾔われているが Erlang VM の速度⾃体は速くはない
    ‣ Binary の操作はいろいろ整っている⼀⽅ Bitstring の操作がわりと貧弱
    ‣ 公式の SDK やライブラリは無い場合が多く、コミュニティ頼み or ⾃作
    ‣ ⼈気ライブラリでも放置気味なものも…

    View Slide

  27. Elixir でよくある動的型付け⾔語っぽいミス
    Elixir での Web 開発について
    だいたい Map や Struct アクセス時
    ‣ Map アクセス時の key の型違い(string/atom)
    ‣ Struct アクセス時の typo(コンパイルフェーズで気づけない)
    ‣ nil に dot access、など
    ほとんどはユニットテストで検出可能
    しかし、テスト⽤のモック実装と現実の実装の間で返り値に差があったりすると…
    ‣ それでも staging 環境で気付ける
    ‣ 常⽤開発環境がない外部システムなら接続試験で…

    View Slide

  28. Elixir でよくある動的型付け⾔語っぽいミス
    Elixir での Web 開発について
    Map アクセス時の key の型違い(string/atom)
    iex> map = %{hoge: 100}
    iex> map.hoge
    100
    iex> map = map |> Jason.encode! |> Jason.decode!

    iex> map.hoge
    ** (KeyError) key :hoge not found in: %{"hoge" => 100}
    JSON を介したりするとついやってしまいがち
    atom は GC されないので、string → atom は雑にできない

    View Slide

  29. Elixir でよくある動的型付け⾔語っぽいミス
    Elixir での Web 開発について
    Erlang の Dialyzer という静的解析ツールがあるが、

    現状は個⼈のローカル環境でのサポート程度にしか利⽤できていない

    View Slide

  30. bitstring の操作⽀援が貧弱
    Elixir での Web 開発について
    binary 向けオペレータは基本つかえない… が頑張ればなんとかなる
    # ݁߹ͷྫ
    iex> <<1, 2>> <> <<3>>
    <<1, 2, 3>>
    iex> <<1::1, 2::1>> <> <<3::1>>
    ** (ArgumentError) argument error
    (stdlib) eval_bits.erl:101: :eval_bits.eval_exp_field1/6
    (stdlib) eval_bits.erl:92: :eval_bits.eval_field/3
    (stdlib) eval_bits.erl:68: :eval_bits.expr_grp/4
    (stdlib) erl_eval.erl:481: :erl_eval.expr/5
    (iex) lib/iex/evaluator.ex:257: IEx.Evaluator.handle_eval/5
    (iex) lib/iex/evaluator.ex:237: IEx.Evaluator.do_eval/3
    # ΦϖϨʔλΛ͔ͭΘͣʹ݁߹
    iex> << <<1::1, 2::1>>, <<3::1>> >>
    <<5::size(3)>>

    View Slide

  31. 放置気味なライブラリもやっぱりある
    Elixir での Web 開発について
    ⼈気ライブラリでもそういうものもある
    tzdata というタイムゾーン管理のライブラリ(累計ダウンロード数でhex.pmの1ペー
    ジ⽬にある定番ライブラリ)にリソースの開放漏れに関する PR を送ったときは8ヶ⽉
    後にマージされた
    ただこれはどの⾔語でもある問題な気がする

    View Slide

  32. 決済システム開発で便利だったこと
    Elixir での Web 開発について
    Erlang のエコシステムに乗っかれるのはやはり便利
    6gram における ISO8583(クレジットカード取引のプロトコル)処理は Erlang ⽤ラ
    イブラリをベースに実装している
    ‣ Bitmap の処理や中間表現のみを利⽤し、フィールドの定義や変換処理は⾃前実装
    ‣ こういう拡張性のある実装のライブラリは Elixir には存在しなかった

    View Slide

  33. 決済システム開発で便利だったこと
    Elixir での Web 開発について
    バイナリプロトコルの処理も不⾃由なくかける!(慣れれば)
    C⾔語などのスタイルでの処理に慣れている⼈にはまどろっこしく感じるところもあ
    りそう
    パターンマッチ、SpecialForms (<<1, 2>> みたいなやつ) を使いこなすのが鍵

    View Slide

  34. 決済システム開発で便利だったこと
    Elixir での Web 開発について
    ログやスタックトレースの表⽰をコントロールできる
    PCI DSS 的にカード番号や CVC などがログにでるのはインシデント
    ‣ 標準の Logger が拡張性あるので JSON ログするついでにフィルター関数も呼ばれ
    るように拡張
    ‣ v1.8 で導⼊された Custom Inspect Optionを利⽤するとより事故を回避しやすく
    ‣ CVC は3桁程度のため、カード番号のように正規表現で⼀括フィルタしづらく、

    どうやってエラー時などにもログに出さないようにするか悩ましかった
    ‣ Inspect Option 付の Struct に⼊れて引き回すことで不意の内容展開時も安⼼

    View Slide

  35. まとめ

    View Slide

  36. まとめ
    6gram という新しいサービスがでました
    Elixir でのアプリケーション開発はいいところが⾊々ある
    6gram、これからがんばっていきます!

    View Slide

  37. View Slide

  38. なんで Elixir?
    Appendix
    すでに弊社の中では採⽤実績も複数ある選択肢だった
    弊社で最初に Elixir を採⽤したのはリアルタイム通信を必要とするゲームのバックエ
    ンド
    発⾜時点のメンバーが全員 Elixir 経験者
    個⼈的にも、⼊社以来サーバーサイドはほとんど Elixir を扱っていた
    ‣ 未経験者でもそれほど初期の学習コストが⾼くないことも知っていた
    前プロジェクトの資産を活かせる
    前プロジェクトも Elixir で、その資産も活かせるため⾃然な流れで採⽤

    View Slide