UZABASE Tech Blog

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

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

モンスト、スマニュー、Wi2の運用秘話多数! 「SRE Lounge #3」レポート

株式会社ユーザベースのSPEEDA Japan Company、Site Reliability Engineering (SRE) Teamの川口です。 先日、「SRE Lounge #3」という勉強会を開催しました。 発表企業4社のみ参加の非公開な会でしたが、ここでしか聞けないようなディープな話題が満載でした。

目的

「SRE Lounge」は、

  • 各社SREチームの取り組み事例の共有(情報交換・発信)
  • SREそのものについて議論し、知見を深める

といったことを目指して行われている勉強会です。

開催の背景や、そもそもSREとは何かについては、「SRE Lounge #1」の記事を参照してください。

開催日時

2018年5月17日(木) 午後7時30分 開始

会場

今回は、ミクシィ様本社のコラボレーションスペースをお借りしました。 広くておしゃれなカフェのような雰囲気で、窓からの眺めも良く、渋谷の夜景がきれいでした。 ランチや社内の打ち合わせだけでなく、今回のようなセミナーやイベントにも使用されているということです。

f:id:uzabase:20180522233522j:plain
会場のミクシィ様本社コラボレーションスペース

参加企業

※発表順

発表内容

当日のスケジュールは以下の通りです。

  • 各社の取り組み事例等の発表と質疑応答(各社20分程度)
  • 発表を踏まえた意見交換会(30分程度)

ピザやお酒を取りながら、終始和やかな雰囲気で行いました。

f:id:uzabase:20180522234242j:plain
スマートニュース様の発表を真剣に聞く皆様

ユーザベース 

企業・業界情報プラットフォーム「SPEEDA」のシステム構成の変遷を紹介しました。

サービスの成長に伴い、プロダクトチーム(dev)とSREチーム(ops)のやり取りでのオーバーヘッドが多くなったため、 開発チームだけでCI/CDまで完結出来る環境を構築しました。 具体的には、Kubernetes+Rancherの構成となっています。 クラスタレベルロギングアーキテクチャを採用し、各APから出力されたJSON形式のログを、fluentd経由でバックエンドのBigQueryに格納していることも特長です。

質疑応答では、アラート発生時の一次調査担当や、システム環境の統制などが多く挙がり、どの企業でも苦労されているようです。

当日発表資料:SRE Lounge#3 UZABASE

ワイヤ・アンド・ワイヤレス様

「Wi2」などのWi-Fiサービスを提供されるワイヤ・アンド・ワイヤレス様には、 サービス提供環境のオンプレミス環境からクラウド環境移行への歩みについて、詳しく紹介いただきました。

オートスケーリングやコスト削減を期待してクラウドを導入したものの、なかなか思惑通りにいかず苦労されたそう。 しかし、少しずつ安定し、知識も得られてきたということで、サーバレス化やAWSの新しいサービスの利用も進めているとのことです。

Wi-Fiサービスならではの苦労も少なくない中、今後もアグレッシブに挑戦していきたいそうです。

当日発表資料:Sre wi2 20180517

f:id:uzabase:20180522234647j:plain
ワイヤ・アンド・ワイヤレス様発表中

スマートニュース様

ニュースアプリを提供されるスマートニュース様には、SREチームで担当されている膨大な業務範囲から、「モニタリング」「障害振り返り」の2つを紹介いただきました。

モニタリングでは、各リソースに適した様々なシステムを駆使しての監視を行っているということで、各社で参考になる部分も多かったと思います。

障害振り返りでは、障害発生時のインシデントレポート作成や、事後のインシデントレビューを行っており、再発防止策のトラッキングも工夫されているようです。 また、インシデントレビューの読書会も検討されているそうで、この辺りはまた詳しく聞いてみたいです。

質疑応答では、ニュースアプリならではの話題として、プッシュ通知時のアクセス集中対策の話が盛り上がりました。

当日発表資料:SRE at SmartNews

ミクシィ様

最後に、ミクシィ様のXFLAGスタジオから、「モンスターストライク」(モンスト)用に構築されているマルチクラウド環境について紹介いただきました。

「モンスト」のようなソーシャルゲームでは、例えばイベント期間だけ爆発的にアクセスが増えるため、サーバを短期間だけ増強する必要があります。 元々はオンプレミス環境で運用していましたが、最適な構成を模索するうちに、複数のクラウド環境を併用するに至ったそうです。 そのためのネットワーク構成や管理面での工夫や、各クラウドごとの癖についての話もありました。

SNSからの大規模サービス構築・運用ノウハウのあるミクシィ様ならではの内容で、当社とはスケールの違う話にワクワクしました。

当日発表資料:モンストのマルチクラウドについて / sre-lounge-at-xflag

発表を終えて

各企業のサービス内容やSREチームの守備範囲、SREに対する考え方など、これまでのSRE Lounge以上にバラエティーに富んでいて、とても興味深かったです。 また、各社の発表内容がディープで、質疑応答や意見交換会も大変活発でした。 当初予定していた時間を大幅に超えてしまいましたが、皆様多くのものを得られたのではないかと思います。ありがとうございました。

「SRE Lounge」は、今後も開催していく予定です。 興味を持たれた方や、発表してみたいという企業の方は sre@uzabase.com までメールにてご連絡ください。 また、Facebookの「SRE community」でも情報共有、交流を行っています。非公開グループですが、お気軽にご参加いただければ幸いです。

f:id:uzabase:20180522231824j:plain
今回参加いただいた各社の皆様

仲間募集!!

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

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

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

JaSST'18 Tokyoに参加してきました!!

こんにちは、ユーザベースのPDT(Product Development Team)です。

我々PDTは今年3月7日と8日にJasst’18 Tokyoに参加してきました。 今年のJaSSTではユーザベースはスポンサーとして協賛したので、私たち社員は無料で参加することができました。大変ありがたい話です。 今年もたくさんのセッションがあり、たくさん有用なお話が聞けました。 今回は私たちが参加したセッションについて紹介していきたいと思います。

各セッションの紹介

A1. 基調講演 「Advances in Continuous Integration Testing at Google」

Googleで長年CI/CDに取り組んできたJohn Micco 氏による講演でした。

Testing Scale at Google :

  • 420万件のテストが継続的に実行されている
  • 1日に1億5000万件のテストが実行されている(1日平均35回テスト実行)
  • 99%のテストがパスする

講演資料の2Pより http://jasst.jp/symposium/jasst18tokyo/pdf/A1.pdf

まず規模感とテスト文化の説明があり、Googleは翻訳関連とUX関連のテスト以外はすべて自動テスト化されているらしく本当に圧倒的でした。。。 次に、これだけのテストをどうやって実行するのかのための施策として、必要なリグレッションテストケースの選定の話。 そして2日目のTutorialの内容でもあるテストメトリクスの分析について説明されていました。 定期的に実行される自動テストの結果から、バグを生んだコミットを探す方法やFlakyTests(不安定なテスト)を探すためのアプローチをかなり詳しく聞けてとても興味深かったです。

質疑応答では、マニュアルと自動テストの費用対効果の質問が結構出ていましたが、自動テストは当然なのでマニュアルテストとかありえない的な回答。日本のソフトウェア開発にこの文化が根付く日が早く来てほしいです。

E2. やってみよう!探索的テスト〜ハイクオリティな妄想の高速ループ〜

Jasst ’17 Hokkaidoの実行委員中岫さんと根本さんによる、ハンズオン形式の探索的テストのセッションでした。

このセッションではherokuに設置されたWebアプリケーションに対して、実際にみんなで探索的テストをやってみるといった内容でした。私は開発者なので、普段は「期待通りに動いていること」を保証するテストなら自動テストで行なっています。しかし、バグを叩き出すことを目的としたテストはあまり経験がないので非常に新鮮な体験なりました。ちなみに多い人は20個ほどバグを発見できたそうですが、私は2個でした(笑)。

最後に他の方達とどんなバグを出したかを話す時間がありましたが、そこで出たバグの内容の違いに驚きました。私が見つけようとしていたバグは、システム自体が使い物にならなくなるようなバグのみでした。しかし、他の方はユーザにとって使い勝手が悪いと感じる仕様や、通常の運用ではしないような入力を与えたことで発生する事象もバグとして記録していました。開発のエンジニアとテストエンジニアとの間でテストの視点が全く違うのだなぁと感じました。

C4-1. 探索的テストにおけるストーリーベースのアプローチ

NTTデータ熊川さんによる探索的テストに関する研究発表でした。

タイトル的にアジャイル開発でよく聞く「ストーリー」のことかと思いましたが、ここでのストーリーは本来の意味の物語をさしています。人間は自身の体験を物語形式のパターンとして当てはめる傾向があるらしいです。熊川さんの手法は探索的テストで利用するチャーターを物語の形式にすることで、テスターの知識や経験を探索的テストに反映させやすくするというアプローチを取っていました。

結果としては、従来手法より圧倒的に優れた訳ではありませんでしたがアプローチそのものは非常に面白いと思いました。

C4-2. NGT記法を応用した不具合分析からのテスト補強

ベリサーブ吉川さんによる、足りないテストケースを補うためのアプローチに関するセッションでした。

NGTとはテスト観点図を作成するための表記法です。吉川さんはテスト観点ではなく、発見した不具合の持つ要素にたいしてNGTを適用して不具合分析を行い、導出した要素から別のテストケースを作る手法を提案していました。結果としては提案手法を使うことで、既存のテストケースだけでは取り逃がしていた可能性のある不具合を見つけることができていました。

個人的には不具合の持つ要素も結局はテスト観点になるのではないかと思います。本来、テストに必要になりそうな要素ならなんでもテスト観点になり得ます。なので不具合そのものはテスト観点でないにしてもそこから導出される要素はやはりテスト観点だと考えられます。そういう意味では、このセッションの本質はテストフェーズでテストアーキテクチャを見直しませんか?という提案ではないかと思いました。

D4.「無料で始める!「龍が如く」を面白くするための高速デバッグログ分析と自動化」

元ゲームプログラマであり「龍が如くスタジオ」専属QAエンジニアの阪上さんによる、テストの自動化とそのログ解析方法についてのセッションでした。

セッションのメイントピックは kibana + fluentd + elasticsearch を組み合わせたデバッグログの分析だったのです、その前段として、自動テストでゲームを全クリできるほど自動化されているというのが衝撃でした。実際にキャプチャ/リプレイでオートメーションされたテストのデモも見れて面白かったです。 自動テストをバグ出しのために使うだけでなく、テスト結果を分析してゲームのチューニングに利用しているという1つ上のレベルの取り組みをされていて日本企業でここまで成功している事例があることに驚きました。

B5. ケーススタディで学ぶ仕様の書き方

川口さんによる、形式手法に関するセッションでした。

形式手法は仕様を厳密なルールで記述することで、仕様の曖昧さを排除できたり、仕様の矛盾をプログラムで自動的に発見できるなど非常に高度な手法です。川口さんは組み込みシステムの振る舞いの仕様を状態遷移図を使って形式化し、それに対してモデル検査をかけて曖昧な点や矛盾をなくすアプローチについて説明していました。

しかし、このセッションで最も有用だったのは形式手法そのものより、既存のシステムにたいして新しい機能を追加しなければならない状況で、1から仕様書を作成するときのノウハウを共有していただけたことだと思います。具体的にどうするかというと、新しい仕様については全て状態遷移図を書きます。その時に既存の部分と密接な関わりがあるならば、新しい仕様の状態遷移図に対して既存の仕様の要素を追加します。つまり、新しい部分は全て記述し、既存の部分は必要な分のみ追加するということです。既存の部分に対してまで、網羅的に仕様書を作っているとコストがかかりすぎるのでこのようなアプローチが重要なようでした。

E5. 海外のテスト技術動向 ~カンファレンス、国際会議、海外テストチームの現場から~

パネリスト:辰巳さん、松尾さん、山口 さんによる海外のカンファレンスや海外でのテストチームの編成に関するセッションでした。

辰巳さんのパートでは、海外のソフトウェアテストのカンファレンスについて概要と歴史などを紹介されていました。 2018年も海外でこんなにカンファレンスがあるようです。http://www.softwaretestingmagazine.com/software-testing-conferences/

やはり日本よりも海外のほうがだいぶ先行していることを改めて感じました。 印象に残ったのは、どうやって情報収集しているのかという質問に対して「SNSやネットでひたすら追いかけている」と応えていらっしゃったことです。興味があるものに関して言語を超えて情報収集し、そこから更に発信していく姿勢にとても刺激を受けました。

続いて、山口さんのパートではSTARWESTとAgileTestingDaysに実際に参加した感想を発表されていました。 STARWESTはディズニーランドホテルでやってるとのこと。参加費がJaSST’の8倍くらいかかってるのに参加者は同じくらいいるそうです。 ソフトウェアテスト製品のベンダーがスポンサーにたくさんついていて、講演者も多いとのこと。講演者と講演後に個別に質問などができる機会が設けられているが質問というより営業に近いと言っていたのも日本とは違うなという印象でした。

最後に、松尾さんが海外にテストチームを組成する際の経験談についてお話しされていました。Uzabaseでも海外開発チームの組成を進めていますが、やはり大変なところは採用というのは共通してるようです。実際に自分で海外企業の面接を受けてみて知見をつけてから採用活動に取り組んでいるというお話もされてました。優秀な人材を見つけるにはちゃんと調査や準備が大事ということですね。

セッションを通じていえるのは、日本にとどまらず海外の事例に学ぶ姿勢を持つのが大切だということです。パネラーの方々のように積極的に良いものを探し出して取り込んでいけると理想的ですね。

A7. 招待講演 「私が経験したソフトウェアテストの変遷」

現在のソフトウェア開発にいたるまでの「技術的変遷」とTDD、CI/CDのお話し。柴田さんご自身の富士ゼロックス、リコーでデジタル複合機の開発をされた際の経験談についての講演でした。

前半では、過去の偉大なエンジニアたちがいかにしてTDDにいったたのかをわかりやすく説明されていて、その意義を再認識しました。最初にテストコードを実装してからプロダクトコードの実装をすることで、開発者へのフィードバックループをいかに短くし、すぐにバグや設計ミスをすぐに修正できるようにする、というTDDの手法はUzabaseでも導入していますが、品質とスピードを担保するためにすごく考えられて作られた手法なのですね。過去の偉人に感謝。

後半のご自身のマルチスレッドプログラミングに関するトライ&エラーの経験談で印象にのこったのが、開発者全員が毎晩自動テストを実行していたところ、3か月前にコミットされたコードに問題があることが発見されてとのお話しでした。これも自動テストがなければ絶対見つからないよねって感じで自動テストってほんとに大事だと思わされました。 自動テストを大切な資産ととらえて開発チームみんなで認識してメンテナンスしGREENにし続けていかなければと強く感じました。

終わりに

いかがだったでしょうか。 JaSSTでは本当にたくさんのセッションがあり、非常に勉強になります。 周りきれなかったセッションもありますがそちらもきっと為になる話が聞けのではないかと思います。

JaSST'18 Tokyoゴールドスポンサーとして協賛しました!

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

ユーザベースとして、2018/03/07(水)ー03/08(木)に開催された JaSST'18 Tokyo を協賛いたしました。
今回は協賛した理由とそこから読み取れる弊社でテストエンジニアとして働くことの価値を書きます。

f:id:kudogen:20180320101504j:plain

JaSST Tokyoとは

JaSST Tokyoとは業種や職種を問わずソフトウェアテストに関心がある方が一同に集まる、国内最大のソフトウェアテストシンポジウムです。
JaSST’18 Tokyoには2日間で延べ1600人を超えるエンジニアが参加し、一時Twitterのランキングで6位になるなど大盛り上がりのカンファレンスでした。
当日盛会の様子は下記からご覧ください。
JaSST Tokyo実行委員ブログ
JaSST'18 Tokyoレポートページ

ゴールドスポンサーとして協賛した理由

この度は、

SPEEDA開発でも様々なOSSを利用したりとコミュニティ活動の恩恵を受けているので、このような活動をサポートすることでコミュニティに還元していきたい。

という想いでゴールドスポンサーとして協賛いたしました。

元々SPEEDA開発では、エンジニアがコミュニティ活動などに積極的に関わることが推奨されています。
そんな背景もあり、私(工藤)もJaSST Tokyoの実行委員として活動しておりました。

特にテストはSPEEDA開発において最も大事にしていることの一つなので、ゴールドスポンサーという形でソフトウェアテストのシンポジウムを協賛できたことはとてもうれしく思っています。

SPEEDAプロダクトチームでテストエンジニアとして働くことの価値

今回、JaSST Tokyoを協賛・参加して改めて「SPEEDAプロダクトチームでテストエンジニアとして働くことの価値」について考え、以下に挙げてみました。

  • 基本的に各チームに権限が委譲されているので自動テストや新技術の導入はエンジニアドリブンで行うことができる
  • テストを下に見るような変な風潮はない
  • チームとしてテストを大事にしているからこそ、テストエンジニアとしては価値を出しやすい
  • 常にチームとして技術的なチャレンジを行っているので、エンジニアとして成長しやすい環境がある
  • テストエンジニアも開発チームの一員となって動くので、開発側の知識もつけていける
  • 前述の通り、コミュニティ活動などに理解があり、推奨されている

今後もSPEEDA開発として、JaSSTのみならず様々なコミュニティ活動に貢献していきたいと思っています。

現在、技術的にチャレンジしたい、成長したいテストエンジニアを募集しております!
少しでも気になった方はこちらまで

はじめてのDuct

 SPEEDA開発の中村です。今回の内容は,弊社主催のclj-ebisu #2で発表した「実践Duct(仮)」です。 ClojureのサーバサイドフレームワークDuctを業務で使って学んだことを紹介します。 connpass.com 勉強会で発表した資料はこちらです。

 はじめに,Ductのコアで使われているフレームワークIntegrantを紹介し, サーバサイドでIntegrantを使って感じた課題についてお話しします。 次に,課題に役立つDuctのmoduleのしくみと作り方を説明します。 想定読者は,Clojureを書いたことがあってDuctを使ったことがない方です。

目次

Integrantのつかいかた

 Integrantは,アプリケーションのモジュール構成をmapやednのようなデータで表現するためのDIフレームワークの一種です。 Integrantは,アプリケーション起動時にデータが示すモジュールの依存関係を解決し,アプリケーションを初期化します。 Integrantのドキュメントでは,データで構造が表現されたアプリケーションをデータドリブンアーキテクチャと呼んでいます。

 まず,例題を通してIntegrantのイメージをつかみましょう。とりあげる例題は,ヘルスチェックを行うringサーバのハンドラを初期化する処理です。 get-healthは引数に与えられたURL先のステータスを問い合わせる関数と考えてください。

(def endpoint “http://localhost/health”)

(defn handler [request]
  (get-health endpoint))

(defn -main []
  (jetty/run-jetty handler {:port 3000}))

なんてことはないプレーンなコードですが,変数や関数のスコープが必要以上に大きいという問題があります。 mainhandlerに,handlerendpointに依存しており,本来mainからendpointが見える必要はありません。 しかし,mainendpointがグローバルなスコープを持っているため,お互いに参照できるようになっています。 関数のスコープは呼び出される関数だけから見える大きさで十分です。

 Integrantは,このスコープと依存解決の問題をクロージャで解決します。 次の2つのコードは上のコードをIntegrantで再実装したものです。 この2つのコードは,上段がdefmethodで囲まれたモジュールの実装で,下段がモジュール間の依存関係の定義するednです。 依存するオブジェクトをdispatchの引数として関数に与えることで,Integrantはスコープを小さくします。

(defmethod ig/init-key :ebisu/hanlder
  [_ endpoint]
  (fn [request] (get-health endpoint)))

(defmethod ig/init-key :ebisu/jetty
  [_ {:keys [handler] :as options}]
  (jetty/run-jetty handler options))
{:ebisu/handler “http://localhost/health”
 :ebisu/jetty {:handler #ig/ref :ebisu/handler
               :port 3000}}

 この依存関係を宣言するednが,コンフィグレーションマップと呼ばれるアプリケーションの構造を定義するデータです。 マップの最上位の各キーはそれぞれモジュールであり,キーの値はモジュールの初期化に必要な別モジュールや値です。 #ig/refを使えば別のキーワードを参照できます。 ここでは,ハンドラはURLに依存し,jettyサーバはハンドラとポート番号に依存するという関係があります。

 アプリケーションを初期化するには,コンフィグレーションマップをintegrant.core/initに渡します。

(integrant.core/init 
  (integrant.core/read-string (slurp "config.edn")))

initは,最上位のキーの値がマルチメソッドの返り値に置き換わったマップを返します。 上の例であれば,initは,マップにある:ebisu/handlerget-healthを本体で呼び出す高階関数に置き換わったマップを返します。

 余談ですが,IntegrantもDuctもClojureのライブラリをたくさん作られているweavejester先生の作品です。 本稿ではDuctより先にIntengrantについて説明しますが,IntegrantはDuctより後に生まれたフレームワークです。 Integrantが担っているDuctの機能には,もともとComponentが使われていました。 後に,先生は何かに不満を覚えたのか,Componentを使っていた部分をIntegrantに置き換えました。

Integrantなせかい

 これまでみたように,Integrantは,モジュールの実装(defmethodの本体)とアプリケーションの構造(コンフィグレーションマップ)にプログラムを分離します。 次は,分割の後ろにある考え方を説明します。

 Integrantは,Arachneから影響を受けて作られたため,Arachneの考えを受け継いでいます。 Arachneの世界観を詳しく知りたい方は,Clojure eXchange 2016での作者によるプレゼンテーションを観るとよいでしょう。 プレゼン前半のテーマは,フレームワークとライブラリの違いです。 自分たちのコードを呼び出す側にあるのがフレームワークで呼び出される側にあるのがライブラリ, そしてフレームワークはアプリケーションの構造を規定する,という主張でした。 テーマの後ろには制御の反転やハリウッドの法則があります。

 IntegrantはArachneのアイデアをベースにしているので,Integrantにも,アプリケーションの構造を定義する役割があります。 モジュールを指すシグネチャがあれば,アプリケーションの構造(モジュールの依存関係)を宣言できます。 モジュールの実装はアプリケーションを実際に起動するまでいりません。 このように,モジュールの実装とモジュール間の依存関係は別の関心事とみなせることができます。 それゆえに,関心の分離にしたがって,Integrantは,モジュールの実装とモジュールの依存関係をマルチメソッドとコンフィグレーションマップに分けています。

Integrantでこまること

 弊社では,Clojureで作るものは主にWebアプリケーションです。 Webアプリケーションには,ルーティングやDBアクセスなどドメインを問わず実装すべきものがあります。 フルスタック系のWebフレームワークであればこれらをサポートしているものもありますが,Integrantにはありません。 使いたい機能があれば,自分でそれをIntegrantのモジュールにする必要があります。

Ductのmodule

 DuctはIntegrantをベースとするサーバサイドのフレームワークです。 フレームワークとしてIntegrantと同じ役割を果たし, module1と呼ばれる形式でアプリケーションを問わずよく使われる機能を提供しています。 moduleを使えば,Integrantで必要だったボイラープレートコードを減らせることができます。 有名なmoduleはductのリポジトリのREADMEで紹介されています。 github.com

Ductでこまること

 上のサイトを見た方は気づいたかと思いますが,執筆時点においてmoduleの数は多くありません。 moduleを使えばボイラープレートコードを減らすことができますが,なければどうしようもありません。 アプリケーション間で再利用したいコードがあり,その機能を担うmoduleがないのであれば,moduleを自分で作るしかないでしょう。

 ところが,module同様に,moduleを作るための参考資料もまた少ないのです。 いざmoduleを自作してみようとしたところ,情報が少なくて困りました。 そこで,moduleの作成する上で知っておくと役立つmoduleの振る舞いと作り方について紹介します。

Ductによるコンフィグレーションマップの展開

 moduleのしごとは,アプリケーションのig/init-keyマルチメソッドを呼び出す前にコンフィグレーションマップにエントリを追加したり, 追加したエントリに対応する実装(マルチメソッド)を提供したりすることです。 Integrantではアプリケーションの初期化手順は

  1. (read step) コンフィグレーションマップを読み込み
  2. (init step) init-keyマルチメソッドを呼び出す

という2手順に分解できます。 Ductにはread stepとinit stepの間にprep stepがあり,prep stepでコンフィグレーションマップが展開されます。

 一例として,logging moduleが,コンフィグレーションマップを書き換える過程を追ってみましょう。 moduleは,自分たちで作るモジュールと同様,Integrantのキーワードにすぎません。 logging moduleの場合は:duct.module/loggingです。 以下では,devで開発環境用のコンフィグレーションマップを読み込んで初期化処理をread stepまで進めています。

$ cat resources/ebius/config.edn
{:duct.module/logging {}
  ...}
$ lein repl
user => (dev)
:loaded

 次にprepでprep stepまで進めます。 configを評価すると展開後のコンフィグレーションマップを確認できます。

(dev) => (prep)
:prepped
dev => (pprint config)
{:duct.logger/timbre {:level :debug,
                             :appenders {: ...}
 :duct.logger.timbre/spit {:fname “logs/..”}
 :duct.module/logging {}
 ...}

コンフィグレーションマップにログのレベルや出力先が追加されました。 logging moduleはロギングライブラリtimbreを利用するため,追加されたキーワードにはtimbreが含まれています。

 最後にgoを呼び出すことで,展開後のコンフィグレーションマップに従い初期化されたWebサーバが起動します。

(go)
:duct.server.http.jetty/starting-server
{:port 3000}
:initiated

Ductのmoduleのつくりかた

 ここまでで,外から見たmoduleの振る舞いを確認しました。 次は,Google pubsubを非同期pullで購読するためのmoduleの実装duct.module/messageを作り,moduleの振る舞いの実装方法を紹介します。

 例題で扱うのは,公式のpull サブスクライバー ガイドにあるjavaコードです。 プロジェクトIDとサブスクリプションIDで指定したキューからのメッセージの受け取り処理を開始するプログラムです。 このJavaコードは,Clojureで次のように書き直せます。

(def s-name // -> moduleに
  (SubscriptionName/create “project-id” “subscription-id”))

(def receiver // -> ig/init
  (reify MessageReceiver
    (receiveMessage [this message consume]
      (println (. message getData)))))

(def subscriber
  (Subscriber/newBuilder s-name receiver))

(. (. subscriber build) startAsync) // -> protocol

s-nameで購読するキューを指定,receiverでメッセージを処理し, subscriberが受信したメッセージをreceiverに渡しています。 moduleが担う処理はドメインを問わず行うべき処理なので,s-nameを文字列から作る処理をmodule化することを目指しましょう。

 leiningenプロジェクトをDuctのmoduleにするには,srcに以下のようなマップが書かれたファイルduct_hierarchy.ednを作る必要があります。

{:duct.module/message [:duct/module]}

コンフィグレーションマップのキーワード間には継承関係を定義でき, これにより,クラスの継承と同じ考え方でコンフィグレーションマップの抽象度を上げることができます。 全てのmoduleのキーワードは,:duct/moduleを継承する必要があり, 上のコードはduct.module/messageduct/moduleの子キーワードであることを宣言しています。

 prep stepでは,duct/moduleを継承するキーワードのマルチメソッドが呼ばれます。 このマルチメソッドは次のように:fnをキーとするマップを返す必要があります。

(defmethod ig/init-key :duct.module/message
  [_ options]
  {:fn (fn [config]
    (core/merge-configs
      config ; ユーザが書いたコンフィグレーションマップ
        {:duct.message/pubsub ; 追加するキー
          {:logger (ig/ref :duct/logger)}}))})

:fnの設定すべき値は,コンフィグレーションマップを受取り新しいコンフィグレーションマップを返す関数です。 prep stepでのコンフィグレーションマップの書き換えは,:fnの関数適用の結果です。 上のコードは,ユーザが定義したコンフィグレーションマップに:duct.message/pubsubをキーとするエントリを追加しています。 merge-configsは引数に渡されたマップをマージし,マージ後のマップを返します。

 コンフィグレーションマップに追加したキーワード:duct.message/pubsubを追加したので, moduleには,このキーワードのマルチメソッドも含める必要があります。

(defmethod ig/init-key :duct.message/pubsub
  [_ {:keys [p-id s-id] :as opt}]
  (assoc
    opt
    :s-name
    (SubscriptionName/create p-id s-id)))

購読したいキューを指定するにはプロジェクトIDとサブスクリプションIDが必要なので, ユーザにはduct.message/pubsubの値にIDを書いてもらうようにします。 これでmoduleの出来上がりです。

 最後に,作ったmoduleを実際に使ってみます。 まず,キューのIDとmoduleのキーワードを含んだコンフィグレーションマップを作ります。

{:duct.message/pubsub {:p-id "project-id"
                       :s-id "subscription-id"}
 :duct.module/message {}
 :ebisu.boundary/message #ig/ref :duct.message/pubsub}

マルチメソッドでは,コールバックと購読の開始処理を書いています。 s-nameには,moduleにあるSubscriptionName/createの返り値が渡ります。

(defprotocol Receiver
  (start [this])
  (stop [this]))

(defrecord PubSubReceiver [subscriber]
    Receiver
    (start [this]
      (. subscriber startAsync))
    (stop [this]
        (. subscriber stopAsync)))

(defmethod ig/init-key :clj-ebis2.boundary/message [_ {:keys [s-name]}]
  (let [subscriber (. (Subscriber/newBuilder
                       subscription-name
                       (reify MessageReceiver
                         (receiveMessage [this message consumer]
                           (println (.. message getData toStringUtf8))
                           (. consumer ack)))) build)]
    (let [receiver (->PubSubReceiver subscriber)]
      (start receiver)
      receiver)))

参考資料

  1. Duct Framework and supporting libraries
  2. Arachne: building a framework in Clojure
  3. Productive Duct
  4. Enter Integrant: a micro-framework for data-driven architecture with James Reeves
  5. Duct, Covered

  1. 本稿の前半でモジュールと表現しているIntengrantのマルチメソッドとは異なるものなので,英語表記にして両者を区別します。

hbstudy#82 の「SRE大全:ユーザベース編」で話をしてきました。

こんにちは。ユーザベースのSPEEDAで、SREチーム内のソフトウェアエンジニアをしている @tkitsunai です。

f:id:kitslog:20180319164521j:plain

3月15日(木)に、株式会社ハートビーツ様が主催している「hbstudy#82」で、「SRE大全:ユーザベース編」というお題目の下に、弊社のSREチームの4人で様々なSREの取り組みについて発表してきました。

SRE大全というお題目は、日本企業でのSREチームを立ち上げたとして界隈で有名なメルカリさんも発表しており、前回はクックパッドさんの発表でした。 今回、日本企業のTech Companyとしても有名な方たちと肩を並べることができ、知名度がまだまだ低いユーザベースのSREチームにとっては身に余る光栄でした。

我々が今回SREチームとして発表してきた内容は以下となります。

  • 「UZABASEのSREについて」 羽山 雄偉
  • 「ソフトウェアエンジニアリングによるToil削減」 橘内 孝幸 ( @tkitsunai )
  • 「FullGCとの闘い」 久保 裕史 ( @hirofumikubo )
  • 「On-premise Kubernetes on Rancher」金屋 泰士

発表資料は1つだと長いので小分けにしています。

「UZABASEのSREについて」 羽山 雄偉

「ソフトウェアエンジニアリングによるToil削減」 橘内 孝幸 ( @tkitsunai )

「FullGCとの闘い」 久保 裕史 ( @hirofumikubo )

「On-premise Kubernetes on Rancher」金屋 泰士

会場の方から質問も頂きまして、

  • 「他のSRE大全では、10数名でもきついという話を聞いたが、10名で回すのはどうか。」
  • 「トイルの計測について、差し込みの割合について定義はあるか?また、計測の精度はどうか。」
  • 「K8SをPrometheusで監視しているということだが、Rancherの監視はどうしているか。」
  • 「Prometheus自体の監視は?」

などなど、10名での運用体制についてや後半ではRancher成分が多めな印象でした。

YoutubeLiveでの配信もあり、hbstudyさんのチャンネルにも公開されていますので、そちらから会場の様子などを含めた全編を閲覧することができます。

www.youtube.com

インフラエンジニア勉強会 hbstudy - YouTube

(余談)

私のパートでは、めちゃくちゃ緊張してしまって声が震えるし真っ白になるしで、軽くトラウマレベルでした。 スピーカ慣れしてる人たち、本当に尊敬します。精進あるのみ。。。

仲間募集中!

ユーザベースのSPEEDA SREチームは、No Challenge, No SRE, No SPEEDA を掲げて業務に取り組んでいます。 「挑戦しなければ、SREではないし、SREがなければ、SPEEDAもない」という意識で、日々ユーザベースのMissionである、「経済情報で、世界をかえる」の実現に向けて邁進しています。

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

SRE Loungeについて

昨日の記事のSRE Loungeについてもどんどん他社様を巻き込んでおり、コミュニティの活性化を進めています。 是非、うちのSREはこんなことやってるよーと共有して頂ける企業様が居ましたら sre@uzabase.com 宛にご一報下さい。