メドピア開発者ブログ

集合知により医療を再発明しようと邁進しているヘルステックカンパニーのエンジニアブログです。読者に有用な情報発信ができるよう心がけたいので応援のほどよろしくお願いします。

Golang(Go言語)を採用して、たった二人で基盤となるAPIゲートウェイを開発した話

はじめに

初めまして、気がつけば先月の25日で入社1年目を迎えた、
技術部 & Sake部部長 の@shinofara(篠原)です。
1月頃からGo言語(Golang) ばかり触りすぎて、PHPをたまに触ると; を忘れて怒られます。
困ったものです....

今回は、僕も含めた2名で進めてきた、弊社初の Go言語(Golang) プロダクトについてのお話をしたいと思います。
少し長いですが、お付き合いいただければとてもうれしいです!

※関係無いですが、gopher君可愛いです。

f:id:shinofara:20151209165705p:plain

Go言語のロゴ、マスコットは2009年にRenée French(http://reneefrench.blogspot.jp/)さんによって作成・公表されました。 これらはCreative Commons Attribution 3.0 Unported License(http://creativecommons.org/licenses/by/3.0/)で保護されています。 ライセンスの全文はhttps://golang.org/doc/gopher/README をご覧ください。

さて、本題に入りたいと思います。

先月末、2015年11月25日に JSON RPC API ゲートウェイ のリリースを行いました。
(と言っても社内限定利用ですが)
開発には Go言語(Golang) を採用しています。
アプリ開発を除くと、PHP以外で開発した弊社初のプロダクトになります。

当記事では、MedPeer × Go言語(Golang) での開発に関して
下記の三点にフォーカスしてお話していきたいと思います。

  1. Go言語(Golang) でのゲートウェイ開発が始まった経緯
  2. どのような体制・環境でゲートウェイの開発を行ったか
  3. 今後どうして行きたいか

なぜ Go言語(Golang) でのプロダクト開発が始まったのか

ゲートウェイ作成の背景

弊社のサービスは、良くも悪くもモノリシック として、今まで提供してきました。 モノリシック でもスケールさせ続ける事は可能ですが、以下の様な問題が発生しやすくなります。

  1. 小さい機能ひとつのデプロイだとしても、アプリケーション全体に影響を与える事が考えられます。
  2. ソースコードの肥大化に伴い、複雑性も高まってしまう為、修正の影響範囲が特定し辛くなると考えられます。

などなど、モノリシック から マイクロサービス にしていく事に関しては、様々なTech Blogなどで公開されておりますので、今回は省略させていただきます。

マイクロサービス については、最近 株式会社FiNCがslideshareに公開した、以下のスライドがわかりやすいかと思います。

引用元:株式会社FiNC, slideshare)

そして、弊社でマイクロサービス 化を実現する為に、クライアントの認証と、APIへのアクセス制御を考慮した結果ゲートウェイの開発を行う事となりました。

実際に作成したゲートウェイの簡単な図を載せておきます。

f:id:shinofara:20151210155610p:plain

PHPカンパニーが、Go言語(Golang)導入をどの様に決定したのか

今回開発する事になったゲートウェイの開発初期段階に、以下の事を考えた結果、
Go言語(Golang) でやってみようという事になりました。

  • 求められている事は何なのか?
  • 求められている事に一番最適な言語は何なのか?

最後の方は勢いだったかもしれません。

全てをお話する事はできませんが、掻い摘みますと 以下の内容になります。

なぜGo言語(Golang)なのか?

  1. 静的型付け言語である事
    コンパイル時に、型の不整合に起因するバグを捕捉する事ができます。
    それ故に開発サイクルの後でバグ修正する多くのコスト、またはその場所で起こる多くのバグのコストを取り除く事ができるからです。 メリットは分かるのですが、やはり動的型付け言語経験者からすると、煩わしかったりもします。
    ですが、 Go言語(Golang) には、型推論があるおかげで、静的型付けで型の恩恵を受けながら違和感無く開発できますので、とても親しみやすいです。

  2. 大抵の必要な物は、標準ライブラリに含まれている
    Go言語(Golang) は十分な標準ライブラリが潤沢ですので、言語自体をインストールするだけで大抵の事が可能になります。

  3. 本番環境でGo言語を動かす為に必要な物は何一つ準備しなくてよい コンパイルする手間は発生してしまいますが、コンパイル後のバイナリを実行するだけでアプリケーションを立ち上げる事ができます。
    本番構築に関しては後述しますが、環境構築をとてもシンプルに保てると思いました。

Golangにする事で発生するデメリットは何なのか

  • 不慣れな言語に対する学習コスト
    Golangで実戦経験0の状態で着手した事も有りますが、どんな言語でも学習コストは発生してしまいます。
  • 依存管理が課題
    公式では、ベンダー管理が未サポート(1.5 からvendorを使ったコンパイルをサポートはしているが、管理に関してはまだです)
    今後この辺りが公式サポートされるのかは要観察です。

ゲートウェイのインフラ周辺、利用したライブラリや、技術について

今回は深くは説明することが出来ませんので、使っている環境、技術などをさっと紹介したいと思います。
詳細に関しては、またお話させていただければと思います。

言語

もちろん Go言語,Golang 1.5
開発初期は 1.4 でしたが、vendorサポート など恩恵を受けたい機能追加がありましたので、早い段階から1.5 を使い始めました。

開発環境

go の開発自体はmacでも問題無くできるのですが、mysql や関係するサービス環境を誰が作っても再現できるようにする為に、docker-compose を使って確認を行っています。

docker 実行環境は docker-machine を使って立ち上げています。

開発支援

開発時には以下のコマンドを使ってコーディングスタイルなどの統一化を行う様にしています。

依存管理

良くなかった事でも書きましたが、まだ公式では依存するパッケージのバージョン管理方法に関しては、未サポートなので、実行タイミングや、実行者、環境によってパッケージのバージョンが変わってしまう問題が発生してしまいます。

その為、弊社ではGoogleの公式ドキュメントで推奨と書かれている GO15VENDOREXPERIMENTの使い方 を参考にして、バージョンの固定とvendorを使ったコンパイルを実現する事で、誰がコンパイルしても同じ結果を得られる状態にしています。

  • バージョン管理は、PHPのcomposerã‚„rubyのbundler に似た、glideを使ってvendorのバージョン管理しています。
  • vendorを使ったコンパイルは、バージョン 1.5 でサポートされた設定 を使って、GOPATH よりvendor/... を優先して参照させるようにしています。

現在の所、特に問題なく使えてるため、最近はオススメっす!といろいろな場所で話をしています。

マイグレーション

Go言語で作成された、goose を使ってスキーマ管理とマイグレーションを行っています。
使って見た感想としては、とてもシンプルで使い勝手がよく現時点では満足しています。

バリデーション

バリデーションには、gojsonschemaを採用しています。 ゲートウェイ開発では、Request/Responseのスキーマ定義をJSON-Schemaを採用していますので、gojsonschema を使う事で、ドキュメントとバリデーションの設定が同時に変更できるというメリットを得ることができています。

ユニットテスト

Go言語(Golang) で標準に用意されているtestパッケージのtestingを使っています。
assert とか無く不便かな?と思ってましたが、特に不便なく使えています。

CI(継続的インテグレーション) ツール

CIツールは、Github Enterprise と連携可能な CircleCI Enterprise を利用しています。

クラウドのCircleCI では、golang 1.5 のサポートが開始しているのですが、
エンタープライズ版では 1.4 の為、cricle.yml を以下の様に記述しています。

※サポートを今か今かと楽しみに待っています!!(切実

machine:
  environment:
    GO15VENDOREXPERIMENT: 1
    GOROOT: "/home/ubuntu/.go"
    GOPATH: "/home/ubuntu/go"
    PATH: "/home/ubuntu/.go/bin:$PATH"

dependencies:
  cache_directories:
    - "/home/ubuntu/.go"
  pre:
    - if [[ ! -e /home/ubuntu/.go/bin/go ]]; then cd /home/ubuntu; curl https://storage.googleapis.com/golang/go1.5.2.linux-amd64.tar.gz | tar -xz; mv go .go; fi
  override:
    - mkdir -p $HOME/go/src/path/to/organization
    - ln -s $HOME/$CIRCLE_PROJECT_REPONAME $HOME/go/src/path/to/organization

test:
  override:
    - |
      cd $HOME/go/src/go/src/path/to/organization/$CIRCLE_PROJECT_REPONAME;
      go vet $(go list ./...|grep -v vendor);
    - |
      cd $HOME/go/src/go/src/path/to/organization/$CIRCLE_PROJECT_REPONAME;
      go test $(go list ./...|grep -v vendor);

一覧がGreenだと嬉しいですね! f:id:shinofara:20151204172353p:plain

テスト結果はこんな感じです。

f:id:shinofara:20151204172358p:plain

フレームワーク

使用しておりません。 この辺りに関しては、次回お話できればと思います。

本番環境構築

ゲートウェイの本番環境は、AWS上に構築しています。
構築に利用した技術は、以下の2点です。

Goの場合は本番環境にGo言語自体の実行環境は不要ですが、Nginx などいくつか必要なパッケージがありますので、それらの構成管理として利用しています。
また、terraformはvpc全体のインフラ構成を管理する為に利用しています。
どちらもなれるまでは大変でしたが、なれてみると一昔前の構築にものすごく時間がかかっていた時代は何だったのか!と思いました。

開発からデプロイの簡単な流れ

今回は各工程の深掘りは出来ないですが、よくある図で表してみました。

f:id:shinofara:20151209022708j:plain

今後どうして行きたいか

弊社での Go言語(Golang) を使ったプロジェクトはリリースで終わりではありません、ここからが本当の意味でのスタートとなります。

今後は、更に踏み込んだ技術のお話などをブログで公開していく予定です。 例えば開発現場についてとか、フレームワークを使わずに、どの様に開発をしたかなど

もし、弊社のプロダクトや、Go言語(Golang) に関して少しでも興味がありましたら、ぜひ一緒に働きましょう! 気軽にお声がけくだされば、ランチとかでも大丈夫です!!