UZABASE Tech Blog

〜迷ったら挑戦する道を選ぶ〜 株式会社ユーザベースの技術チームブログです。

「ここではすべてが流れている!」SPEEDA の開発チームに入って驚いた 3 つのこと

7 月から SPEEDA 開発チームに参加しました、野口です!

SPEEDA 開発チームでは、XP のプラクティスを大きく取り入れて日々の開発を進めています。
私は入社前から XP やスクラムのようなアジャイル開発手法とその考え方には慣れ親しんでいたのですが、SPEEDA 開発チームに参加してみて、ユニークだなと感じたことがいくつもありました。

この記事では、SPEEDA 開発チームで私が特にユニークだと感じた 3 つのことについて紹介します。

おことわり

この記事の目的は、SPEEDA 開発チームのユニークな文化を紹介することです。
これらの取り組みには、SPEEDA 開発チームの現在のフェーズに固有の部分も少なからずあると思っており、これを読まれた方の組織やチームで、ここに書かれているようなことをただちに実践することを勧めるものではありません。

私自身、チームに入ってからしばらく経ちますが、まだ十分には消化しきれていない部分もあり、これからも実践しながら考え続けていきたいと思っています :)

その 1: チームのメンバーを「安定させない」

SPEEDA 開発チームは、開発を担う機能エリアごとに、数名程度の小さなチームに分かれています。(以後、この「小さなチーム」のことを単に「チーム」と呼ぶことにします)

日々の開発(スタンドアップや見積もり、ふりかえり等を含む)はこのチームごとに行うのですが、このチームのメンバーは、数ヶ月に一度入れ替えを行っています。実際、私が入社してからも一度入れ替えがあり、7 名いたメンバーのうち 2 名が交代しました。 *1

個人的には、チームのメンバーがお互いの個性やチームの文化・慣習を知り、チームとして安定してパフォーマンスを出せるようになるには時間がかかるため、頻繁な入れ替えは避ける方がよいと考えていました。

では、なぜあえてチームメンバーを安定させず、メンバーが「流れる」ようにするのでしょうか?
今のところ、私は以下の理由があると考えています。

  • やる理由: 製品全体についての知識、および文化を共同所有するため。
    • 個々のチームに知識を閉じず、開発チーム全体で製品全体を共同的に理解し、開発・保守・運用できるようになることが目的。また、文化についても同様。
  • できる理由: 「さまざまなものが流れる」文化があるため。
    • チームメンバーの入れ替えに限らず、SPEEDA の開発チームでは多くのものを安定させず、常に流れる状態に置いている。「流れる」ことが定常状態であるため、メンバーの入れ替えもそのうちの一つにすぎず、チーム・メンバーのいずれも入れ替えにすばやく適応できる。

よく見ると、「やる理由」と「できる理由」は表裏一体になっています。メンバーを入れ替えることによって知識や文化が撹拌され、それによってさらに入れ替えがやりやすくなる、という正のフィードバックの関係です。

その 2: 属人化を防ぐためにドキュメントを「残さない」

SPEEDA 開発チームでは、ドキュメントを用いることがかなり稀です。

アジャイルソフトウェア開発宣言では「包括的なドキュメントよりも個人と対話を」価値とする、と言われていますが、これほどまで対話(特に口頭での会話)に重きを置くソフトウェア開発組織はかなり珍しいのではないかと思います。

アジャイルソフトウェア開発宣言でも「ドキュメントは不要」とまでは言っていない、とはよく言われることで、個人的にも、安定して開発を進めるためには必要十分な量のドキュメントを書いた方がよいと考えていました。

では、なぜドキュメントを「最少限」と言い切れるほどのレベルにまで減らすのでしょうか?
現在の私の理解では、以下の理由があると考えています。

  • やる理由: ドキュメントを減らせば、会話せざるを得ないため。
    • やや本末転倒にも見えるが、知識が「流れる」ために必要な仕掛けと言える。
  • できる理由: 知識は撹拌されており、また常に会話する文化があるため。
    • 「その 1」で紹介したように、SPEEDA の製品についての知識や文化は常に流動し、撹拌されている。また、常時ペアプログラミングを行なっていてペア間の会話は絶えないほか、他ペアや他チームからの割り込みも奨励されており、「質問されたらすぐに答える」ことが徹底されている。

おそらくお気付きのように、ここにも正のフィードバックがあります。ドキュメントを減らせば会話が増え、会話が増えれば、さらにドキュメントを減らせるようになります。
よく「属人化を防ぐためにドキュメントを残す」と言われますが、私たちのチームでは、いわば知識が「チーム全体に属人化(属チーム化?)」したような状態といえます。

その 3: 担当者を「明確にしない」

SPEEDA 開発チームでは、「担当者を明確にしない」ことがよくあります。

たとえば、チームでのふりかえりを行なった際は次週に取り組むアクションを決めますが、私が初めてチームでのふりかえりに参加したとき、アクションの担当者を決めずにふりかえりが終わったことに驚きました。「ちゃんと決めておかないと、みんな忘れてしまったらどうするの?」と思ったのですね。

しかしこれは杞憂でした。当たり前といえば当たり前ですが、誰かが覚えているのですね。
アクションは次週にきちんと行われました。

とはいえ、一般論としてはアクションの担当者を決める方が確実です。私が初めて会ったチームのふりかえりのファシリテーターだったら、「誰か担当者になってくれますか?」と聞くと思います。

他にも、SPEEDA 開発チームでは、普通なら担当者を決めるであろう場面で、あえて決めない、とすることが多くあります。

これはなぜでしょうか?
私の考えでは、以下が理由です。

  • やる理由: 「活動の最小単位」をチームとし、何らかのタスクが個人に帰属することを防ぐため。
    • 何かを個人のタスクとしてしまうと、そのプロセスについての知識と、責任が個人に紐づいてしまう。そうならないよう、万事を個人ではなくチームの関心事にとどめるために、担当者を決めない。
  • できる理由: いつでも活動の最小単位をチームとしており、そうすることに慣れているから。
    • つまり、普段からそうする訓練をしているから。

「やる理由」についてはともかく、「できる理由」については「やっていたらできるようになった」という理由しか思いつきませんでした :)
チーム全体でこれを意識していると、不思議と補い合うようになります。失敗することも時にはありますが、その都度会話して対応します(ただし、できる限り「担当者を決める」以外の方法で)。

「その 1」と「その 2」では「知識」や「文化」が流れていましたが、ここでは「担当」が流れています。*2

そうやってどこへ行きたいのか、そしてこれから

ここまで紹介してきたように、SPEEDA の開発チームでは多くのものが「流れて」います。

私の個人的な感覚では、「ほとんど全てが流れている」と言ってもいいように思います。他にも、今回は紹介しなかったペアプログラミングのやり方や、ミーティングの進め方、製品のデザイン等々、多くの場面が「流れ」の中にあるように感じます。

では、「流れ」それ自体が目的なのでしょうか?
おそらく、Yes でもあり No でもある、と言えます。

ソフトウェア開発という営み自体が絶え間ない流れの中にあり、SPEEDA はソフトウェアサービスなので、その開発チームにあって流れは重要です。そのため、「流れ」はそれ自体として目的の一つになりえます。

一方で、「流れ」は究極の目的ではないはずです。
ユーザベースには「経済情報で、世界を変える」というミッションがあり、それを支える SPEEDA プロダクトチーム(開発チームもここに属する)のミッションは「技術力で、ビジネスをリードする」です。だとすれば、この「流れ」の文化はそれを支えるものであるはずだし、そうあるべきです。

たとえば、以下のインタビュー記事で CTO の林が掲げている「最高の開発チームをつくる」は、「流れ」によって支えられる大きな目標の一つなのでしょう。

journal.uzabase.com

私はまだチームに参加して 2 ヶ月足らずですが、これからもチームで仕事をしていく中でこの流れの文化の究極の意義を見つけ出し、発展させていくことを楽しみにしています!

*1:ちなみに入れ替えを行うこと自体は半ばルール化されていますが、誰が入れ替わるかはメンバー自身の意思によって決まります

*2:もしかしたら、チームの中を「漂っている」と言った方がより的確かもしれません。もっとも「チーム」という単位で見れば、担当は「定まっている」とも言えますが、そのチームのメンバーでさえ入れ替わるので、やはり流れている、漂っているという表現の方が的確に思えます

Istioでマイクロサービスのテスタビリティを向上させる

SPEEDAの開発チームの石橋です。

最近ではマイクロサービスでプロダクトを開発することが多くなってきていると思います。 そういった状況の中でマイクロサービスのテスト、特に異常系のテストをするコストがやや高いという話を何度か耳にしました。 本記事ではIstioのFault Injectionで「エラーが発生する」、「処理に時間がかかる」などの異常系のテストを容易に実現する方法を紹介します。

異常系のテストをする際の課題

サービスAとサービスBがあるとします。サービスAからサービスBにリクエストした際、サービスBがエラーになる可能性があります。 そうした場合、そのエラーが他のマイクロサービスに伝播して、障害がシステム全体へと波及しないよう適切に処理する必要があります。

適切な処理ができていることをテストするためは、「サービスAが正しいリクエストをしてもサービスBが必ずエラーを返す」状態を作らなければなりません。 このような状況を作るためにはいくつか方法が考えられます。

  • 必ずエラーを返すようにサービスBのコードを修正してデプロイする。
  • 必ずエラーを返すモックサーバーを用意し、サービスAの向き先をサービスBからモックサーバーに変更する。

これらの方法はやや面倒だと思います。特に前者はローカルで一時的に修正して確認する分にはよいかもしれませんが、正常系と混在している自動テストに組み込むことは困難です。 IstioのFault Injectionはこの課題を解決します。設定ファイルを適用するだけで「サービスAが正しいリクエストをしてもサービスBが必ずエラーを返す」状態を作ることができます。

環境構築

本記事ではバージョンが1.2.2のIstioを使用して動作確認しています。

まずはKubernetesに必要なリソースを作成していきます。Gatewayはdefault、ServiceとDeploymentとDestinationRuleとVirtualServiceはexample-nsというnamespaceに作成していきます。VirtualServiceはDestinationRuleの後に作成してください。*1 kubectl apply -f ファイル名を実行すれば、それぞれのリソースが作られます。

※それぞれのリソースの概要や設定ファイルの詳細な書き方については割愛します。

Gateway
Service
Deployment
DestinationRule
VirtualService

また、外部からアクセスするためのエンドポイントを環境変数で定義しておきます。後で何度もアクセスするためです。

export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
export GATEWAY=$INGRESS_HOST:$INGRESS_PORT

Fault Injection

まずはFault Injectionする前に上の環境構築で作ったPodに対してアクセスし、正常に処理されることを確認します。

$ for i in {1..10}; do sleep 1; curl -s -H 'Host: example-svc.example-ns.svc.cluster.local' $GATEWAY -o /dev/null -w '%{http_code}\n' ; done
200
200
200
200
200
200
200
200
200
200

10回リクエストし、HTTPのステータスコード200が10回返ってきているので正常に処理されたことがわかります。

Injecting HTTP Aborts

ここからが本題です。exampleというアプリケーションがHTTPのステータスコード500を返すようにします。virtual-service.yamlの内容を以下のように変更します。

もとのvirtual-service.yamlの最後にHTTPのステータスコード500を必ず返す設定を追加しました。

$ diff virtual-service.yaml 500-virtual-service.yaml -u
--- virtual-service.yaml    2019-07-30 17:21:55.000000000 +0900
+++ 500-virtual-service.yaml    2019-07-30 18:14:22.000000000 +0900
@@ -17,3 +17,7 @@
         port:
           number: 80
         subset: v1
+    fault:
+      abort:
+        httpStatus: 500     
+        percent: 100

500-virtual-service.yamlを適用し、上のcURLを再度実行します。

$ for i in {1..10}; do sleep 1; curl -s -H 'Host: example-svc.example-ns.svc.cluster.local' $GATEWAY -o /dev/null -w '%{http_code}\n' ; done
500
500
500
500
500
500
500
500
500
500

意図通り、すべてHTTPのステータスコード500が返ってきています。もちろんpercentを変更すれば、任意の割合でHTTPのステータスコード500を返すことができます。

Injecting HTTP Delays

次はレスポンスが返ってくるのに時間がかかるパターンです。500-virtual-service.yamlの内容のhttpStatus:fixedDelay:に変更しています。ここでは10sにしているので、レスポンスが10秒遅延します。

システム全体が遅くならないために、呼び出し側のマイクロサービスがタイムアウトなどを適切に行えているかをテストする際に有用です。

最後は少し応用的な例です。ヘッダーにx-e2e-case: errorが付いていれば、HTTPのステータスコード500が返ってきます。付いていなければ、exampleというアプリケーション本来のレスポンスが返ってきます。

1つ目のcURLはヘッダーにx-e2e-case: errorを付けています。2つ目のcURLはヘッダーにx-e2e-case: errorを付けていません。 それぞれのcURLを実行すると、期待通りのステータスコードが返ってきます。

$ curl -s -H 'x-e2e-case: error' -H 'Host: example-svc.example-ns.svc.cluster.local' $GATEWAY -o /dev/null -w '%{http_code}\n'
500
$ curl -s -H 'Host: example-svc.example-ns.svc.cluster.local' $GATEWAY -o /dev/null -w '%{http_code}\n'
200

また、VirtualServiceのmatchは強力で、ヘッダー以外にもURI、ポート番号、クエリパラメータなどでマッチさせることができます。*2

E2Eテストを実行する環境用のVirtualServiceを作り、そこに特定の条件でエラーや遅延が発生する設定を書いておけば、異常系のケースを正しくハンドリングできていることを確認するテストも容易に行えると思います。

まとめ

マイクロサービス化によって様々な恩恵を受けることができる一方で複雑度が上がるとことがあります。複雑度が上がったものの1つがネットワークです。 マイクロサービスではネットワーク越しの通信が当たり前になるので、通信が失敗することを前提として実装するべきです。そして、その実装をテストしやすくするのがFault Injectionです。 Istioの場合だと、VirtualServiceでFault Injectionの設定ができます。

参考

Clojure 1.10.x時代の新しいデバッグツール

こんにちは!こんにちは!SPEEDA開発チーム(通称PDT)に所属しているあやぴーid:ayato0211です。

弊チームでは新しいモノを開発するときに、よくClojureという言語が採用されています。だいたい言語別でシェア2位といったところでしょうか。1位はみんな大好き(?)Kotlinで、こちらはサーバーサイドでの利用が主になっていて、次にE2Eのテストコードを書くときに良く利用されています。

今日はそんな弊チームでよく使われているClojureについて、Clojure 1.10.x時代の新しいデバッグツールをお伝えできれば良いなと思い、この記事を書こうと思った次第です。

大きなデータ構造を簡単に把握したい

Clojureは素晴らしい言語です。Clojureはとても素晴らしい言語です。大事なことなので、2回言いました。それはさておき、Clojureでアプリケーションを書いていると、どうしても大きなデータ構造が出てくる瞬間があります。例えば、Ringのリクエストマップや、Ductのコンフィグマップなどが該当します。それ以外にもマップを引数に取る関数を書くことは往々にしてあるかと思います。

これらの大きなデータ構造というのは、実際に中身を確認するのが非常に面倒です。まず思いつくのは、伝統的なプリントデバッグだと思います。このとき、よくあるのはそのマップがどんなキーを持っているのか分からないので、①とりあえずマップ全体を出力してみて、②注目したい目的のキーをなんとか探し出し、③目的のキーと対応する値だけを出力するように修正して④再度確認を行うという①~④の繰り返しをすることです。

この伝統的な方法はデータ構造が大きければ大きいほど目当ての値を見つけるのが難しいです。僕はよく出力した後に迷子になっています。できればもっとインタラクティブに出力したデータ構造を把握しやすい方法が欲しいところです。そういうツールを今回は紹介したいと思います。

Cognitect's REBLを使う

インタラクティブにデータ構造を把握するためのツールとして、オススメしたいのがCognitectが開発しているREBLというツールです。

REBL、つまりRead Eval Browse Loopということで、その名前の通りただ標準出力に吐く代わりに値をブラウジング(走査)できるというわけです。REBLを使うために必要なのはClojureのバージョンが1.10.0以上であることです。Clojure 1.10.0で新しく追加されたtap>を使うと、REBL上に任意のデータを送ることができ、簡単にブラウジングすることができます(より厳密に言えばDatafyなどの話も出てくるんですが一旦脇に置いておく)。

このREBLをどうやって既存プロジェクトで利用できるようにするのか、Ductの簡単なアプリに組み込む例を見せながら解説したいと思います。

REBLのダウンロードとインストール

REBLは以下のページからダウンロードすることができます。

ライセンス条項をよく読んでほしいのですが、個人の趣味として利用する場合にはあまり問題ありませんが、仕事で利用する場合はDatomicのアクティブな有償ユーザーもしくは、REBLのパトロンでなければなりません。このことに注意してダウンロードしてください。

zipファイルをダウンロードしたら適当な場所に展開しておきます。今回は/home/{{username}}/opt/REBL-0.9.172/REBL-0.9.172.jarとなるようにしました。これでREBLのインストールは完了です。

プロジェクトの準備

次にREBLを使う対象のプロジェクトを準備します。今回はDuctのAPIを簡単に作成して、ついでにexampleハンドラーも生やしてしまいます。以下のコマンドでプロジェクトを作成します。

$ lein new duct demo --template-version 0.12.1 -- +api +ataraxy +example
$ cd demo
$ lein duct setup

普段、意識して--template-versionを指定することはありませんが、この例と全く同じ状況を作りたければ、このように指定することで同じ雛形のバージョンを利用できます。

REBLを利用できるようにする

まずは/home/{{username}}/.lein/profiles.cljに以下の情報を追記します。REBLは開発時に使うもので、開発環境(Javaのバージョン)によって必要となる依存関係が微妙に異なるので、開発者のマシン毎に以下の設定はあると良いでしょう(REBLのREADMEに書いてあるUsageを参照)。僕の手元の環境が今はJava 11になっているのでJava FX関連の依存関係が入っています。また先程インストールしたREBLのJarのパスを:resource-pathsに記述します。

{
 ;; 以下の部分を書き加える
 :tools/rebl
 {:dependencies [[org.clojure/core.async "0.4.500"]
                 [org.openjfx/javafx-fxml "11.0.1"]
                 [org.openjfx/javafx-controls "11.0.1"]
                 [org.openjfx/javafx-swing "11.0.1"]
                 [org.openjfx/javafx-base "11.0.1"]
                 [org.openjfx/javafx-web "11.0.1"]]
  :resource-paths ["/home/{{username}}/opt/REBL-0.9.172/REBL-0.9.172.jar"]}}

次に先程用意したプロジェクトのプロジェクトルート以下にあるprofiles.cljを以下のように書き換えます。profiles.clj.gitignoreされるので、個人用の設定を書く場所として適しています。

;; Local profile overrides
{:profiles/dev
 [:tools/rebl]}

最後にdev/src/local.cljを以下のように記述します。このように書くと、Ductのプロジェクトで最初に(dev)とするとこのファイルが自動的にロードされ、REBLの画面を立ち上げる関数(start-rebl)が使えるようになります。開発しているプロジェクトでチーム全員の合意がとれる場合は、dev/src/dev.cljなどに直接REBLを起動させるための関数を書いても良いかもしれません。

;; Local REPL configuration
(when-not (try
            (require 'cognitect.rebl)
            (catch Exception _))
  (defn start-rebl []
    ((resolve 'cognitect.rebl/ui))
    (add-tap clojure.pprint/pprint)
    (println "REBL started")))

ここまででREBLを利用する下準備が整いました。

REBLにデータを送信する

まずは普段どおりにREPLからシステムを起動をして、REBLもあわせて起動させておきます。

user> (dev)
;;=> :loaded
dev> (go)
:duct.server.http.jetty/starting-server {:port 3000}
;;=> :initiated
dev> (start-rebl)
REBL started
;;=> nil

このまま例えばターミナルなどからcurl localhost:3000/exampleとしても、REBLの方には何も出力されません。なので、src/demo/handler/example.clj:demo.handler/exampleコンポーネントを次のように少し書き換えます。

(defmethod ig/init-key :demo.handler/example [_ options]
  (fn [{[_] :ataraxy/result :as req}]
    (tap> req) ;; <- 追記
    [::response/ok {:example "data"}]))

リクエストマップをtap>に渡すようにしました。こうして、REPLなどからシステムを(reset)などを実行して再起動します。そして、先程と同様にcurl localhost:3000/exampleとターミナルから実行してみます。するとREBLの「tap」タブに次のようにリクエストマップが出力されていると思います。

f:id:ayato0211:20190702182751p:plain

この「tap」タブの画面下部にある「Browse」ボタンを押すと「browse」タブに表示が切り替わります。「nav->」入力欄に例えば0 :headersと入力してEnterを押してみましょう。すると次のような画面になっているはずです。nav->のところはget-inと同じ要領で書けると思えば問題ないと思います。

f:id:ayato0211:20190702182849p:plain

今までであれば出力したデータを見ることしかできませんでしたが、REBLを使えばこのように一度出力した値をREBL上で走査することができます。これにより今までより大きなデータ構造などを把握しやすくなり、デバッグなどもやりやすくなるはずです。

REBLのより具体的な使い方は実際に触るか、次の動画を見てもらえると良いかなと思います。

まとめ

今までプリントデバッグでprintlnpprintなどと書いていたところを、tap>と書くだけでREBLにデータの情報を送ることができ、REBL上でインタラクティブにデータを見ることができるようになりました。これにより、Clojureで開発されたアプリケーションをよりデバッグしやすくなったりするのではないでしょうか。

余談

今回は説明していませんが、Clojure 1.10.0で追加されたdatafyなどをうまく活用すると、REBL上で走査できる対象を広げることができます。実際、ネームスペース(clojure.lang.Namespace)などはDatafiableを実装しているため、REBL上でブラウジングすることができるようになっています。REBL左上のパネルに(the-ns 'dev)など入力して評価してみると分かると思います。このあたりの話もいずれ書けたら良いなーと思ったり思わなかったり。

Kubernetes + Istioでblue-green deploymentを実現する

こんにちは、SPEEDAのSREチームの阿南です。最近Kubernetes界隈が盛り上がっていますね。ここ一年で、各企業での利用事例やKubernetesを解説している書籍等もかなり増え、活用の仕方も徐々に確立されて来ているのではないでしょうか。一方Istioについては、色々できそうということはわかったんだけど、利用事例も少ないためどう使えばいいかわからない、本番運用しているという企業もまだあまり聞かないし導入に踏み切れない、という方も多いかと思います。弊社ではまだ2つのnamespaceのみですが、Istioで運用を開始しております。今回は、Istioで実現できることはなんとなく知っているが、具体的な設定方法がよくわからない方向けにblue-green deployの設定を参考に説明してみたいと思います。

Istioの通信について知りたい方はこちら

環境

GKE 1.9.7-gke.11 ,Istio1.0.2 を利用しています。

IstioのRouting Rule

IstioのRouting Ruleには大きく4つのリソースがあります。

resource 説明
Gateway HTTP/TCPのリクエストを受付. どのHost or Portのアクセスを許可するかのルールを記載。 Ingress / Egress のルールを適用できる
VirtualService ルールにマッチしたリクエストをKubernetesのサービスにルーティングする. weightやheaderの情報を利用した振り分けを定義でき、Istioの設定の要とも言える
DestinationRule trafficの振り分けルールを設定. (例: round robin, least connection 等)
ServiceEntry 外部サービスを登録. 例えば、Kubernetes(Istio)の外側にあるDBの接続先等

この4つが適用された通信のイメージを手書きして見ました。まず、クラスター外部から内部への通信です。

f:id:tanan55:20181118130152p:plain

Gatewayを通ったリクエストがVirtualServiceのルールに基づいて各サービスにルーティングされます。その際に、DestinationRuleに基づき最終的にリクエストが送られるpodが決まります。(DestinationRuleでsubsetが設定されていない場合は、RoundRobinで均等に分散される)

続いて、クラスター内部から外部への通信です。

f:id:tanan55:20181118132321p:plain

コンテナから外向きに通信が発生した後、ServiceEntryのルールに基づきRequestを許可するかどうか判断します。ルール次第で、Egressgatewayを通る場合とそうでない場合の2種類があります。個人的には、まだEgressgatewayを使ってないので、外部のエンドポイントを登録する際はServiceEntryに毎回登録しています。

blue-green deploymentの設定

まずは、Kubernetes のPodをサービスとして稼働させるためのリソースを作成します。

  • namespace

gist.github.com

Namespaceを作成する際に istio-injection: enabled を設定しておきます。この設定で自動的にistio-proxyがサイドカーコンテナとして起動するようになります。

  • deployment

gist.github.com

Deploymentでは、 version: blueversion: green の2つnginxを稼働させます。Istioの設定を行う際に、このlabelを元にBlue-Greenができるように設定します。

  • service

gist.github.com

serviceでは、port: 40001で待ち受け、app: nginxtargetPort: 80番へフォワードします。

続いて、Istioのリソースです。Istioのリソースについては、istioをインストールした際にCRDに登録されていますので、kubectl コマンドを利用して設定の反映が可能です。

  • gateway

gist.github.com

gatewayには許容するHostを指定します。正規表現も可能です。 今回は sample.hoge.com を登録します。

  • virtualservice

gist.github.com

gatewayのルールにマッチした通信が、virtualserviceのルールに基づいてkubernetesのServiceへルーティングされます。ポイントとして、headerに x-version: blue とあれば、subset: blue のdestinationruleが適用されるようにしています。このほかの通信については全てgreenにアクセスされます。この設定を利用してblue-greenの切り替え前にblue環境のテストに利用が可能です。

  • destinationrule

gist.github.com

subsetがblueであれば、version: blue のラベルを付与し、subsetがgreenであれば、 version: green のラベルを付与します。これによって、どのPodにアクセスが振り分けられるかが決まります。以上で、設定が完了です。設定を確認するには下記のコマンドを実行します。

$ kubectl get gateway
$ kubectl get virtualservice
$ kubectl get destinationrule

今回構築した環境のイメージは下記の通りです。

f:id:tanan55:20181118230108p:plain

では、実際にアクセスしてみます。今回は、nginxコンテナに出力されたログを見ることにより、どちらのPodにアクセスされたかを確認します。 下記のコマンドでコンテナのログをtailしておきます。

$ kubectl logs -f -n sample-ns $(kubectl get pod -n sample-ns | grep blue | cut -d' ' -f1) -c nginx
$ kubectl logs -f -n sample-ns $(kubectl get pod -n sample-ns | grep green | cut -d' ' -f1) -c nginx

まずは、headerにx-versionを記載せずアクセスします。

$ kubectl get svc istio-ingressgateway -n istio-system
// EXTERNAL-IP を確認
$ curl -XGET -H 'Host: sample.hoge.com' http://<EXTERNAL-IP>/

f:id:tanan55:20181119223402p:plain

最初にアクセスした際は、全てのリクエストがblueのPodにしかリクエストが送られません。

ここで、headerにx-version: green を付けてアクセスします。

$ curl -XGET -H 'Host: sample.hoge.com' -H 'x-version: green' http://<EXTERNAL-IP>/

f:id:tanan55:20181119223549p:plain

特別なheaderをつけることで、特定のリクエストのみを新規にリリースしたgreenに送ることができます。greenが正常なことを確認できたら、blueとgreenを切り替えます。切り替えの方法は、先ほど設定したvirtualserviceのsubsetのblue-greenを逆転させるだけです。

gist.github.com

上記のyamlを適用後、アクセスすると、blueとgreenが入れ替わり、Blue-Green Deploymentが出来ます。

Istioを使い始めてこれはいい!と思ったポイントとしては、本番環境と全く同じ環境でテストができるということです。検証環境と本番環境で差分があってリリースがうまく行かないというのはよくあることだと思いますが、Istioを使うことで、テストができている状態のPodにアクセスを切り替えることが簡単に実現できます。さらにこれを応用して、特定の割合を振り分けたり、社内ユーザのみに新しい環境にアクセスしたりといったことをPodに変更を加えることなく実現できるようになります。 今回は紹介していませんが、gateway や istio-proxy で telemetryを収集でき、grafana / jaeger 等でリクエストのトレースやレスポンス速度を簡単に可視化できるのでこの辺りをフルスタックで揃えているIstioには最初感動しました。ただし、ハマりどころの多さ(本当に多い)や安定性といった面ではまだまだ成熟していない(バグ結構ある)ので、まずは影響の少ないnamespaceから、かつ、メイン機能となるルーティング周りからIstioを使い始めて、運用ノウハウを貯めていくのがいいかなと個人的には思っています。

仲間募集!!

ユーザベースのSPEEDA SREチームは、 「No Challenge, No SRE, No SPEEDA」 を掲げて業務に取り組んでいます。

「挑戦しなければ、SREではないし、SREがなければ、SPEEDAもない」という意識の元、ユーザベースのミッションである 「経済情報で、世界をかえる」 の実現に向けて、日々邁進しています。

IstioやKubernetes以外にも様々なことにチャレンジしてますので少しでも興味を持ってくださった方はこちらまで!

Istioを使いこなすために知っておくこと

こんにちは、SPEEDAのSREチームの阿南です。最近Kubernetes界隈が盛り上がっていますね。ここ一年で、各企業での利用事例やKubernetesを解説している書籍等もかなり増え、活用の仕方も徐々に確立されて来ているのではないでしょうか。一方Istioについては、色々できそうということはわかったんだけど、利用事例も少ないためどう使えばいいかわからない、本番運用しているという企業もまだあまり聞かないし導入に踏み切れない、という方も多いかと思います。弊社ではまだ2つのnamespaceのみですが、Istioで運用を開始しております。今回は、Istioで実現できることはなんとなく知っているが、内部の通信の仕組みやどのようなコンポーネントがあるのかを追っていきたいと思います。その上でBlue-Green Deploymentを実現するための設定方法についても次回記事で触れていきます。

この記事で扱うこと

  • Istioを構成するコンポーネントについて
  • Istioの通信の流れ

Istioを構成するコンポーネント

Istioのコンポーネントについては、IstioのDocumentationに下記の図が紹介されています。

f:id:tanan55:20181125110511p:plain

図の上側はdata planeで、サービスのPodにサイドカーコンテナ(Envoy) が起動し、Podへのリクエストを中継しています。 図の下側はcontrol planeで、Pilot, Mixer, Citadel が稼働します。Pilotは各サイドカーコンテナにConfigを反映し、Mixerはtelemetry収集やPolicy check(アクセスコントロールや流量の制御等)を担います。Citadelは証明書の管理を担当します。

では、実際にIstioをデプロイしてみて確認してみます。

f:id:tanan55:20181008191459p:plain

デプロイの方法については省略しますが、コマンド一つで大量のPodが起動してきますので、一見面食らいますが、順に整理していきます。(grafana, prometheus, servicegraph, tracingについては実際のサービス通信とは関係が薄いため、省略します)

pod 役割
istio-citadel 証明書の発行、管理を実施
istio-egressgateway Istioの内部から外部へ通信するためのgateway
istio-galley ユーザが定義したIstio設定のvalidationを実施
istio-ingressgateway Istioの外部から内部へ通信するためのgateway
istio-pilot ユーザが定義したIstio設定を反映
istio-policy Mixerの一部. istio-proxyに来たrequestをチェック
istio-telemetry Mixerの一部. 各podからテレメトリを収集
istio-sidecar-injector Podが起動する際に、リクエストをhookしてサイドカーを auto Injectする

上記のコンポーネントでIstioの外からどのようにサービスのPodまでリクエストが到達しているのかを図で表現してみました。

f:id:tanan55:20181125114804p:plain

上図の番号順に処理内容を解説します。

  • リクエストが来る前にEnvoyをサイドカーコンテナとしてInjectしておく。(⓪)
  • ingress-gatewayへリクエストが到達。ここで、hostやpathベースで、どのサービスPodにリクエストをforwardするか決める。(①)
  • istio-proxyへリクエストが到達。実際には、サービスPodへのリクエストをPreroutingしている。例えば、サービスコンテナが80番で稼働していた場合、80番に来たリクエストを15001(Envoyポート)に流す。(②)
  • istio-proxyからistio-policyにアクセスし、Policyのチェックを実施。例えば、流量の制御(最大同時アクセス数100等)で条件にひっかかった場合は、サービスのコンテナに到達する前にその時点でリクエストが返される。(③)
  • Policyでチェックを通ったリクエストがサービスコンテナに到達。(④)

この辺りは、実際に通信の流れを理解するまでに時間がかかりました(今も勉強中です)。ご自身で確認したい方は、実際にistio-proxyのコンテナでshellを起動して、tcpdump, netstat等を取ってみると理解が進むと思います。istio-proxyにはデフォルトでこの辺りのコマンドがインストールされているので、スムーズに調査ができます。
今回、実際に通信をみていった結果、想像以上に色々なことをしてるなという印象でした。特に、PolicyチェックのためにMixerにアクセスしている点は結構重要で、istio-policyのPodがダウンするとサービスの通信もダウンしてしまいます。本番運用する際は、この辺りのConfigurationも注意して見ていきましょう。ちなみに、Istioは必要なコンポーネントに絞ってインストールが可能なので、最初はistio-policyなしで運用するのも十分ありだと思います。

今後Istioがどの程度、使われ広まっていくかはまだわかりませんが、Service Meshに必要な概念や機能を勉強するには良いソフトウェアだと思いますので、皆さんもぜひ一度触れてみてください。次回の記事では、通信の流れやコンポーネントを理解した上で、Istioを使ったBlue-Green Deploymentの方法をみていきます。

Kubernetes + Istioでblue-green deploymentを実現する

仲間募集!!

ユーザベースのSPEEDA SREチームは、 「No Challenge, No SRE, No SPEEDA」 を掲げて業務に取り組んでいます。

「挑戦しなければ、SREではないし、SREがなければ、SPEEDAもない」という意識の元、ユーザベースのミッションである 「経済情報で、世界をかえる」 の実現に向けて、日々邁進しています。

少しでも興味を持ってくださった方はこちらまで!

Vue.jsとFirebaseとGASとiPadで会議室表示板を作った

こんにちは、コーポレートエンジニアリングチームという新チーム所属のたけうち(@chimerast)です。ユーザベース社内ではレアポケモンと呼ばれています。

数ヶ月前、メンバーも数百人を超え、アメリカのQuartz社がユーザベースグループに加わったりして、業務改善を主として行う管理部門付けのエンジニアチームが欲しいという話になり、新しいチームが作られました。名前はなんでも良かったのですが、世の中的に流行っているのとエンジニア採用に効きそうなので、コーポレートエンジニアリングチームという名前になっています。

コーポレートエンジニアリングチームという名前がついてはいるものの、ユーザベース社の場合はその業務範囲は幅広く、業務改善、情報セキュリティ、内部統制、情報システム、全社リスク管理等々、管理部門でITが絡めば大体担当になります。

あと、普通の情シスチームでも面白くないので、

いいのがない、作ればいいじゃん、ホトトギス
使いにくい、作ればいいじゃん、ホトトギス
お金が無い、作ればいいじゃん、ホトトギス

の精神で、バックオフィス業務全般(経理・財務・法務・人事・労務・総務)や監査もわかり、システム開発できる情シスを目指しています。

業務改善軸で数ヶ月前に作ったもの: 会議室表示板

会議室が誰が使っているのか、いつからいつまで使うのかが一目見てわかるものを作りました。iPad用のシステムですが、iOSアプリではなくウェブアプリです。Google Calendarの会議室予約と連動します。

f:id:chimerast:20180724113649j:plain:w280f:id:chimerast:20180724113659j:plain:w280

作った経緯

ユーザベース社は今年2018年7月に六本木にオフィスが引っ越しました。

ピッカピカの新オフィスで、会議室も恵比寿オフィスの時の4部屋から9部屋に倍増、会議室からの眺めもよいという非常に良い環境でテンションも上がります。そして、そこには壁への埋め込み式のiPadが。創業期の狭い8畳ぐらいのオフィスから、数回のオフィス引越しを経て、ついに弊社オフィスにも近代化の波が押し寄せてきたのかとわくわくしたものです。

が、そこまでは良かったものの、オフィス引越チームが選定していた会議室表示システムを入れてみたところ、

  • iPadの画面をタッチしても反応が悪い・遅い、謎のスワイプさせるUI
  • 会議室名についている色に合わせて画面背景の色だけでも変更したいのにできない
  • 現在行っているミーティングの予定しか見れず、次に自分が使う会議室なのか分からない

という状況で使いにくい。社員は会議室を探してうろうろしているし、なにより自分が会議室を使おうとしたときにイライラするという状態でした。

サービスを提供している会社さんには悪いとは思いつつも、普通のiPadだしウェブアプリとして作ればそんなに時間がかからず作れるだろうと思い、強権発動して作って入れ替える事にしました。

これくらいの用途であれば、ウェブアプリとして作ってもサクサク動きます。また、作るのもデプロイするのもiOSアプリと比べると圧倒的に楽です。 一晩夜なべしたらできました。

f:id:chimerast:20181120020512p:plain:w280f:id:chimerast:20181120020518p:plain:w280

作り方および使った技術

Vue.js+TypeScript、Firebase、Google App Scriptを使って作りました。

細かい所は難しいものではないので、はしょります。流れとしては下記になります。

  1. 会議室カレンダーの追加や変更イベントをGoogle App Scriptのトリガーで捕捉できるように設定する
  2. Google App ScriptからCloud Firestoreにカレンダーの追加・変更を登録する
  3. iPad上のウェブアプリからFirestoreのonSnapshot()を呼び出して、リアルタイムにFirestore上の変更を監視する

f:id:chimerast:20181120022515p:plain:w400

GASからFirestoreへの登録にはこちらのGAS用ライブラリを使わせてもらってます。 https://github.com/grahamearley/FirestoreGoogleAppsScript

全体のソースコードは残念ながら現時点では公開していないです。

ウェブアプリをiPadホーム画面に登録する方法

Safariの共有メニューから「ホーム画面に追加」というボタンを押せば、普通のWebサイトをアプリっぽく登録できます。後述しますが、いろいろHTMLに細工をするとほぼネイティブアプリっぽく見えるようになります。

f:id:chimerast:20181120020448p:plain:w280f:id:chimerast:20181120020458p:plain:w280

ネイティブアプリっぽく見せる細かいテクニック

iPadでそのままウェブアプリを表示すると、ブラウザだなーと一目見て分かってしまうので、いくつかHTMLに細工をしています。

上部の時計やバッテリー表示部分の帯を透過させる & 全画面つかえるようにする

iOS標準の状態だと、ウェブアプリを起動すると黒い帯が表示されてしまいます。また全画面にもならないです。

f:id:chimerast:20181120020523p:plain:w280

そのままだとかっこ悪いので、下記のHTMLをHEADタグ内におまじないとして追加するといい感じになります。

<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no,viewport-fit=cover">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

f:id:chimerast:20181120020512p:plain:w280

ドラッグ操作をキャンセルする

iOSのブラウザの標準動作では、指でドラッグするとテキスト選択ができてしまいます。これができてしまうと一瞬でブラウザだとばれてしまい、見た目が悪いので、ontouchmoveのデフォルト操作を無効化します。

<body ontouchmove="event.preventDefault()">

タッチしたときに素早く反応するようにする

.rt-left(@touchstart="inuse = !inuse; return false" :style="{ backgroundColor: room.color }")

普通のPC用ブラウザでマウスクリックしたときのイベントとして利用する onclickonmousedownでも一応動くのですが、タップしても反応が悪かったり、微妙に遅れたりします。

元々入っていたシステムでもタッチ操作の反応が悪かったので、周りのアクリル板の静電気が悪さしてるのかなと思って、帯電防止スプレーを吹きかけてみたりしたのですが直らず、結局素直にスマホ用のontouchstartを使うことで今までの微妙な動作は何だったのかと思うぐらいキビキビ動くようになりました。

最近Safariのアップデートが進んで、onclickonmousedownもタップ操作で十分違和感なく動くようになったと思い込んでいたのですが、勘違いだったようです。素直にスマホ用のイベントを使いましょう。

その他iPadを使った社内システム向けテクニック

ホームボタンを押しても操作できないようにする

iOS標準のアクセスガイド機能を使います。暗証番号を入れないとホーム画面に戻れなくなります。

https://support.apple.com/ja-jp/HT202612

常につけっぱなしにする & 画面が暗くならないようにする

常につけっぱなしにするには、「設定」→「画面表示と明るさ」から、自動ロックを「なし」に設定すればOKです。

これだけだと明るさMAXにしておいても、周りの明るさによって微妙に暗くなったりします。これを避けるためには、「設定」→「一般」→「アクセシビリティ」→「ディスプレイ調整」→「明るさの自動調整」をオフにします。その上で明るさをMAXにします。

最後に

コーポレートエンジニアリングチームでは、業務改善と内部統制・情報セキュリティが表裏一体だということを熱く語れる人を募集中です!

また、12/4(火)に、この辺について熱く語れる人を集めて、情報交換するためのLT大会を開催します。もしご興味があればご参加ください!

お試し就職制度を導入した話と、導入するに至るまでの話

入社して約2ヶ月くらいしか経ってませんが、この技術ブログに初投稿です。皆さんご存知(?)あやぴーさんid:ayato0211です。 何を間違ったのか、社内では筋トレの人として名前が売れてしまいましたが、本業はClojureエンジニアです。所属しているのはSPEEDAの開発チームです。

さて、本業はClojureエンジニアです、と書きながら今日はタイトルにある通り、お試し就職制度を導入したよって話と、そこに至るまでのお話です。最近は有名なIT企業があちらこちらで行っているので、あまり珍しくはなくなったと思うのですが、弊社ユーザベースでもお試し就職制度を試験的に導入することになりました。いわばお試しのお試しですね。

お試し就職制度超概要

まずは端的にお試し就職の概要を簡単に書いておきます。

対象者

  • SPEEDAの開発エンジニアとして選考を受けている方
    • かつ、二次面接まで通過している方、で希望される方のみ
    • 残念ながらSREチームでは行なっておりません

もう少し条件を緩くしたい気持ちもありましたが、システムで扱っている情報が情報だけに選考をある程度進めた方のみを対象とさせてもらいました。

期間

  • 2,3日程度(これ以上の期間は応相談)

報酬

  • 要相談
  • 基本的に報酬は出ると考えてもらって大丈夫です

勤務形態

  • 8時間労働(短縮は応相談)
    • 実際の勤務時間は受け入れチームに依存します

勤務地

経験できること

  • SPEEDAの開発
  • アジャイル開発の現場
    • ペアプロ
  • 開発メンバーとのランチ(and/or ディナー?)
  • and more?

導入に至るまで

さて、本来であればこういった記事を書くのは、エンジニア職ではなくどちらかというと非エンジニア職(例えば広報や人事みたいな)なイメージがあると思います。ですが、これを書いているのがエンジニア職の僕である、というところにユーザベースの面白さというのがあると思うので、この記事の残りではこの制度を導入するに至るまでの経緯を書いていこうと思います。

きっかけ

話は少し遡るんですが、僕がユーザベースに入社するときに、最もネックに感じていたのは仕事の取り組み方のところでした。具体的には、僕が所属しているSPEEDAの開発チームでは、常にペアプロで開発を行なっています。僕にとってはこれが入社して、本当にうまくやっていけるのかと最も不安に感じたところだった、といっても過言ではありません。他にも本当にClojureのプロダクトがあるのか、都市伝説ではないのか、という不安などもありました(ちなみにClojureプロダクトはちゃんとありました!!)。といった感じで、一般的に同じエンジニア職だとしても、転職というのはそれなりにハードルや不安を感じるものだと思います(新しい会社に馴染めるのか、実はこわい会社じゃないのか、嘘ついてるんじゃないか、などなど)。

実際に入社して、数日ほど仕事をしていると徐々にこの開発チームの良さというか、素晴しさみたいなものを知ることができました。その中でもったいないなと思ったのは、この環境をあまり開発チームの面々が表立って 発信していない ということでした。また、こんなに素晴しいチームだともっと早く知ることができていたら、もう少し早く入社したいって思ったかもしれないのに、という気持ちもありました。

あ、ちなみに弊社CTO林のインタビュー記事で若干今のチームにも通じる話が書かれているので興味がある方は是非読んでみてください。

newspicks.com

実際に起こったこと

こういった想いがあり、自由を文化とする弊社であればお試し就職制度を作ることはできるだろうと考えました。そして、採用周りを担当してくれているカルチャーチームのメンバー(Kさん)とCTO林に、「どうですか、やってみませんか」と打診をしたのが導入開始に向けた動きのはじまりでした。このとき僕はまだ入社して3週間も経っていないくらいのときでした。

KさんもCTOの林も「いいですね、是非やりましょう」といった良い反応を示してくれたので幸先良いなと感じました。早速、Kさんに実現させたい場合どうしたら良いかと相談すると、簡単に総務と労務にコンタクトを取ってくれて、労務の方と話してみてくださいと道を作ってくれました。それから労務の方を捕まえて話をして、いくつかのアドバイスを貰うことができました。ここまでである程度の実現方法と課題は見えてきていて、とりあえずやるだけならやれそうというところまで形になりました。念の為、法務にも見てもらった方が良いだろうということで、法務の方に話をしてみると法務的な懸念点がいくつかゴロゴロでてきたので、ミーティングをして課題がクリアできることを確認してもらってokが出た、というのが先週、入社から1ヶ月半時点での話です。

伝えたかったこと

上の話を読んで「ふーん、それで?」という感想を持つ人はきっと多いだろうなと思います。ただ、僕はこの一連の話が実にユーザベースの文化を表わしていると感じています。具体的には以下のようなところです。

  • 入社して間もない人間の突飛な発言でも認めてくれる
  • 発言した人間が自分で動いていける(むしろ動かないといけない)
  • 様々な立場の人が行動をしている人間に手を貸してくれる
  • 現場レベルで相談して新しい制度/仕組みを作っていける

普段の仕事でも良いなあと感じることは多いですが、こういった経験は今までになかったのでとても新鮮でした。

最後に

今回は、お試し就職制度を導入したよって話と、そこに至るまでのお話を書きました。ということで、ユーザベースでは僕と一緒にClojureを書きたいエンジニアを募集しています。話だけでも聞いてみたいっていう方は僕に直接コンタクト取ってもらってもいいですし、下の募集から直接応募してくれても大丈夫です。

www.uzabase.com

【超新卒!イベントレポート】新卒入社した会社でモヤモヤしている君へ

f:id:hir023:20181012171750p:plain NewsPicksエンジニアの久保です。

10/4(木)に、第二新卒として転職を考えているエンジニアを応援するイベントとして、
「超新卒!〜活躍する第二新卒エンジニアの最前線〜」を開催しました!
転職を考えているエンジニアも企業側の参加者の方にも、かなり満足度が高かったので、こちらでも発信していこうと思います!

超新卒とは?

超新卒とは、"まだ新卒人材である""新卒という型にはまらず挑戦してほしい""新卒を超えた(第二新卒という)存在である" という想いを込めて、第二新卒として転職を考えている人のことを表現しています。
そのような超新卒なエンジニア向けに、第二新卒として転職を考えているエンジニアを後押ししたり、転職に悩むエンジニアの今後のキャリアを考える参考になる場になればと思い始めたイベントが、「超新卒!〜活躍する第二新卒エンジニアの最前線〜」になります。

なぜ開催するに至ったか?

新卒で入社後すぐに「思っていたのとは違う」「やりたいことができそうにない」とミスマッチを感じる人は少なくないと思います。
また、一方で少なくともまずは3年間は転職せずに働くべきという意見もあります。
しかし、ミスマッチ解消や早期のキャリアアップを目指して、新卒入社後すぐに第二新卒として転職し、活躍するエンジニアを取り上げることで、 「第二新卒」という選択肢を取ることを悩んでいるエンジニアへの後押しになればと思い、開催しました。

開催概要

下記の4社から1名ずつ登壇いただきました。

  • 株式会社エウレカ
  • 株式会社Gunosy
  • 株式会社scouty
  • 株式会社ニューズピックス

イベント詳細はこちらをご確認ください。 newspicks.connpass.com

f:id:hir023:20181011121638j:plain
エウレカ 恩田氏
新卒入社2年目で転職され、「エンジニアの市場価値」という観点や「その企業においてエンジニアがどのように優遇されるか」という観点から、転職先の企業選びをされた体験談を話していただきました。

f:id:hir023:20181011121632j:plain
Gunosy 岡田氏
老舗IT企業からGunosyに転職した経験を元に、「エンジニアにおける社内評価と市場価値の相違」「成長曲線を変えるための転職」という観点で 転職に対する考え方と、転職後、Gunosyでマネージャーになるまでに起こったスキル・価値観の変化について話していただきました。

f:id:hir023:20181011121646j:plain
Scouty 伊藤氏
scoutyでの新卒既卒や年齢を問わずに活躍できる組織体制から、学歴や職歴ではなくスキルを重視したエンジニア採用を実現するという同社のビジョン、第二新卒でも企業からスカウトされるために重要なことについて話していただきました。

f:id:hir023:20181015180302p:plain
ニューズピックス 久保(筆者)
大手SIerから、「技術を極めたい」「プロダクト作りに関わりたい」「もっと成長したい」という想いから転職した体験談をもとに、転職する上でどのようなアクションをしてきたのか、について話をしました。

f:id:hir023:20181015180801p:plain 各社の発表後には懇親会としてお酒とピザでパーティーが催され、参加者の方々と各企業担当者がカジュアルに会話をして、大いに盛り上がりました。

参加者特典

  • 特典として参加者の方全員に、各登壇企業へのカジュアル面談パスをお贈りしました。
    ニューズピックスの場合には、参加者の80%から面談の希望を頂戴しており、とてもよい出会いのかたちを作れたと思っています。

開催してみて

  • やはり新卒入社後すぐに転職をすることへの抵抗や一歩踏み出せないといった、同じような悩みを抱えている方が多いように思いました。
    今回のイベントに参加して、前向きに転職を考えたいという人もいた一方で、「現在の会社でまだまだできることがある。まずは頑張ってみるべきだと気付かされた。」といった方もおられ、転職するか否かはさておき、参加された方への気付きとなる会だったように思います。
  • 登壇企業側からも、次回以降もぜひ参加したいというお声もいただきました。
  • 総じて、参加者・企業側ともに満足度の高い会になりました。

今後について

  • ぜひとも第2回を開催したいなと思います。開催時期は12月を予定しております。
  • 新卒入社3年目以内、もしくは20代で少しでも悩んでいるエンジニアはぜひ次回参加してください!
    connpassのNewsPicksグループ にジョインいただければイベント開催時に通知が届きます。
  • また、登壇を希望される企業様はお気軽にご連絡ください。

GaugeのParameterを使いこなす

こんにちは! SPEEDA日本事業部でテストエンジニアをやっている工藤です。

Gaugeシリーズの第三回目です 第二回目の記事はこちらから

今回はGaugeの「Parameter」について書きます。 ParameterはGaugeでテストを書くにあたり、基礎的かつ重要な機能です。

Parameterとは

GaugeのStepはパラメータを受け取ることができます。 Parameterを使いこなすと、Stepの再利用性をさらに高めることができます。

GaugeのParameterの機能はかなり充実していて、主に下記のようなParameterがあります。

  • Simple Parameters
  • Dynamic Parameters
  • Table Parameters
  • Special Parameters

今回はSimple ParametersとDynamic Parametersについて書きます。

Simple Parameter

Simple Parameterはその名の通り一番シンプルで、Stepに渡したい値をダブルクォーテーションで囲みます。
* Go to "Top" page

例えば、下記のようなSpecファイルがあります。
login.spec

## 日本ユーザーとしてログイン
* ログインフォームに日本ユーザーのログイン名を入力
* ログインフォームに日本ユーザーのパスワードを入力

## 中国ユーザーとしてログイン
* ログインフォームに中国ユーザーのログイン名を入力
* ログインフォームに中国ユーザーのパスワードを入力

テストコードでは4つのStepに対応したメソッドを記述する必要があります。
login.kt

class login {
  @Step("ログインフォームに日本ユーザーのログイン名を入力")
  fun fillInJpnUserName() =
        `$`(".username").sendKeys("jpn_user")

  @Step("ログインフォームに日本ユーザーのパスワードを入力")
  fun fillInJpnUserPassword() =
        `$`(".password").sendKeys("passwprd_jpn")

  @Step("ログインフォームに中国ユーザーのログイン名を入力")
  fun fillInForeignUserName()  =
        `$`(".username").sendKeys("chn_user")

  @Step("ログインフォームに中国ユーザーのパスワードを入力")
  fun fillInForeignUserPassword() =
        `$`(".password").sendKeys("passwprd_chn")
}

※SPEEDA開発チームではSelenide × kotlinでテストコードを書いています。

そこで以下のようにパラメータを使えば同じStepを使いまわすことができます。
login.spec

## 日本ユーザーとしてログイン
* ログインフォームにユーザーのログイン名"jpn_user"を入力
* ログインフォームにユーザーのパスワード"passwprd_jpn"を入力

## 中国ユーザーとしてログイン
* ログインフォームにユーザーのログイン名"chn_user"を入力
* ログインフォームにユーザーのパスワード"passwprd_chn"を入力

そうするとテストコード側のStepの記述も減ります。
login.kt

class login {
  @Step("ログインフォームにユーザーのログイン名<userName>を入力")
  fillInUserName(userName: String) =
        `$`(".username").sendKeys(userName)

  @Step("ログインフォームにユーザーのパスワード<password>を入力")
  fillInUserPassword(password: String) =
        `$`(".password").sendKeys(password)
}

上記の例で示したようにParameterなしだとユーザー毎にStepを作成しなければいけません。 しかしParameterを利用することでステップの再利用性が上がり、結果としてテストコードの記述量も減らせます。

Dynamic Parameters

Simple Parametersと同じくらい多用するのが、Dynamic Parametersです。 Dynamic Parametersには主に下記二つの用途があります。

  1. Conceptに値を渡す
  2. Data Driven Executionをする際に、テーブルの値を参照する

Conceptに値を渡す

まずはこちらの用途から見ていきます。
Dynamic ParameterとConceptを使うと、Specファイルの可読性を上げることができます。 ConceptファイルでDynamic Parameterを利用してConceptを定義します。
<>内で指定したフィールド名を使うと、Concept下のStepでもその値を利用することができます。
login.cpt

# ユーザー<userName>とパスワード<password>でログインする
* ログインフォームにユーザーのログイン名<userName>を入力
* ログインフォームにユーザーのパスワード<password>を入力
* ログインボタンをクリック

Specファイルでは通常通りConceptを呼び出すのですが、その際に値を渡してあげます。
値の渡し方はSimple Parameterと変わらず、渡したい値をダブルクォーテーションで囲みます。
login.spec

## 日本ユーザーでログインする
* ユーザー"jpn_user"とパスワード"password"でログインする

## 海外ユーザーでログインする
* ユーザー"foreign_user"とパスワード"password"でログインする

SPEEDA開発でもDynamic ParametersとConceptを併用することで、よりSpecファイルのテストシナリオを仕様書のような記述になるようにしています。

Data Driven Execution

Data Driven Executionで、テーブルの値を参照する際にもDynamic Parameterを利用します。
Data Driven Executionを利用することで、同じようなStepを繰り返し記述する必要がなくなり、Specファイルの記述量をさらに減らすことができます。
例えば、下記のようなSpecファイルがあったとします。

# Simple Parameterのみを利用したログイン確認

## 日本ユーザーでログイン確認
* ユーザー"jpn_user"と"pass_jpn"でログインする

## 中国ユーザーでログイン確認
* ユーザー"chn_user"と"pass_chn"でログインする

## シンガポールユーザーでログイン確認
* ユーザー"sgp_user"と"pass_sgp"でログインする

Simple Parameterを利用してStepを再利用できていますが、全く同じようなテストシナリオが複数記述されていて冗長な感じがあります。 このようなケースではDynamic Parameterを使ってData Driven Executionにすることで、記述がスッキリします。

# Data driven executionを使ったログイン確認

     |id|userName |password|
     |--|---------|--------|
     |1 |jpn_user |pass_jpn|
     |2 |chn_user |pass_chn|
     |3 |sgp_user |pass_sgp|

## 各ユーザー毎にログイン確認
* ユーザー<userName><password>でログインする

上記の例だと、## 各ユーザー毎にログイン確認というテストシナリオが3回実施されます。
その際に、下記のテーブルで定義されているuserNamepasswordの値が行ごとに代入されて実行されます。
Data Driven Executionを使わない場合、テストシナリオの数が必要以上に多くなってしまい読む人にもストレスを与えてしまいます。
Data Driven Executionを利用した二つ目のSpecファイルの方が記述量が少なく、変数となるパラメータもテーブルにまとめられているので読みやすくなっています。

まとめ

  • ParameterでStepに値を渡すことができ、Stepの再利用性を高められる
  • ConceptとParameterを使えば、より可読性が高いテストシナリオを書くことが可能
  • Conceptに値を渡すときにDynamic Parameterを利用する
  • Dynamic Parameterを利用することで、Data Driven Executionをすることができる

Gauge正式バージョンがリリースされました!

Gaugeがβ版を終えて、正式バージョンの1.0がリリースされました!

GaugeのConceptを用いてテストシナリオをより仕様書のように記述する

こんにちは!
SPEEDA日本事業部でテストエンジニアをやっている工藤です。

前回の記事から、大分時間が経ってしまいましたがGaugeシリーズの第二回目です。
第一回目の記事はこちらから

今回はGaugeの「Concept」について書きます。 Conceptsを利用することで「実行可能なドキュメント(executable documentation)」という考え方をより実現しやすくなります。

Conceptとは

Conceptとは、Gaugeが提供する複数のStepをまとめて1つのStepとして記述することができる機能です。
ビジネス上使用する言語を複数のStepを使用して表現することができます。
例えば「ログイン」と一概に言っても、自動テストのStepで表現しようとすると下記のようになります。

  1. ログインページにアクセスする
  2. ログインIDを入力する
  3. パスワードを入力する
  4. ログインボタンをクリックする

Conceptを利用すると、上記4Stepを下記の1Stepにまとめることができます。
Specファイルの見た目上は1Stepになりますが、裏側では上記の4Stepが実行されます。

  • ログインする

Conceptの使い方

Conceptの定義の仕方ですが、まず .cpt ファイルをspecsディレクトリに作成します。
Conceptの定義に必要な記述は以下の2つになります。

  • Concept header
  • Step

Concept headerは以下のように文頭に # をつけて表現します。
# This is a concept header
Stepの記述方法は通常のテストシナリオと同じです。

以下に具体的な使用例を挙げます。
login.cptにConceptを定義します。

# Login as user A and go to page B // Concept header
* Login as user "user_a" and password "password" // Step1
* Navigate to page "B" // Step2

上記で定義したConceptはどのSpecファイルからでも利用することができ、通常のStepのように利用することができます。Conceptを利用するときは、cptファイルに定義したConcept headerで呼び出すことができます。

pageNaviagetion.spec

# Page Navigation Specification
## users can go to page B
* Login as user A and go to page B // Concept headerで呼び出す

特にStepを再利用可能なように細かい単位で書いている場合、Stepだけだと手順を羅列しているだけになってしまい仕様書のような形にするのが難しいです。
そんなときにConceptを利用することで、Step単体の再利用性を損なわずにSpecファイルの可読性を上げることができます。
例えば、下記のようなStepのみで記述されたシナリオがあったとします
login.spec

## 日本ユーザでログインした場合、TOP画面が日本語で表示される
* ログインIDに"japan_user"を入力する
* パスワードに"password"を入力する
* ログインボタンをクリックする
* TOP画面が表示される
* 言語で日本語が選択されている
* TOP画面の表記が日本語になっている

これだと手順の羅列のようになっていて、仕様書のような記述になっていません。 そこでConceptを下記のように定義します。
loginStep.cpt

# 日本語ユーザでログインすると
* ログインIDに"japan_user"を入力する
* パスワードに"password"を入力する
* ログインボタンをクリックする

# TOP画面が日本語で表示される
* TOP画面が表示される
* 言語で日本語が選択されている
* TOP画面の表記が日本語になっている

上記のConceptを利用すると、Specファイルを下記のように書き換えることができます。 より仕様のようになり、可読性も上がりました。
login.spec

## 日本ユーザでログインした場合、TOP画面が日本語で表示される
* 日本語ユーザでログインすると
* TOP画面が日本語で表示される

以下のようにConceptの中でConceptを使うこともできます。

# 日本語ユーザでログインすると、TOP画面が日本語で表示される
* 日本ユーザでログインすると
* TOP画面が日本語で表示される

HTMLレポート上のConceptの表示のされかた

Conceptを紹介するとよく聞かれるのが、下記のような質問です。

  • HTMLで出力されるレポートにはどう表示されるのか?
  • Conceptの定義(実際に実行しているStep)をHTMLレポート上で見れるのか?

上記のような点もGaugeのHTMLレポートはちゃんと考えられていて、下記画像のようにConceptは展開することができて、どんな手順が実行されているか確認することができます。

HTMLレポ―トの表示(Conceptが閉じた状態) f:id:kudogen:20180605115845p:plain

Conceptを展開したときの表示 f:id:kudogen:20180605115854p:plain

Conceptまとめ

  • 複数のStepをまとめて1つのStepとして扱える
  • Conceptを使用すると、SpecファイルでのStepの記述量が減らせる
  • SPEEDA開発ではテストシナリオの記述をより仕様書のようにし、可読性をあげるためにConceptを利用している

さいごに

SPEEDA開発チームでは現在テストエンジニアを絶賛募集中です。 少しでもご興味のある方は、こちらからご連絡ください。