第一回 目黒スタートアップ勉強会
Takuma Morikawa / eureka, inc.
Copyright © 2009-2015 eureka, inc. All rights reserved.
じこしょうかい
About me
Copyright © 2009-2015 eureka, inc. All rights reserved.
なまえ Takuma Morikawa
しょぞく
たんとう (Go, JS, たまにインフラ)
じこしょうかい
エウレカについて
About eureka
株式会社エウレカ
専門分野以外の領域
でも活躍できる
エンジニア!
  50人
非エンジニア!
  25人
事業内容
自社サービスの企画・開発・運営
・ オンライン・デーティング・サービス「pairs」
・ カップル専用アプリ「Couples」
海外拠点
・ 唯麗家股份有限公司(台湾)
・ EUREKA SG Pte. Ltd.(シンガポール)
社員数: 75名
インターン・業務委託含む
オンライン・デーティング・サービス「pairs」
12年9月 13年3月 13年9月 14年3月 14年9月 15年3月
225万
。゚+\200万会員突破//+.゚
リリース 2012年 10月
会員数 210万人
プラットフォーム PC/SP/iOS/Android
135万
45万
90万
190万
2年で
200万人
カップル専用アプリ「Couples」
。゚+\200万DL突破//+.゚
リリース 2014年 5月
DL数 210万DL
プラットフォーム iOS/Android
14年5月 14年10月 15年3月
215万
170万
130万
85万
45万
国内
No.1
Today's Talk
pairs golang development from scratch
Go言語でいかにして新しいpairsを作っているのか
pairs golang development from scratch
Go言語でいかにして新しいpairsを作っているのか
AngularJS x TypeScript
x
AngularJS x TypeScript
x
Why AngularJS?
・おそらく採用の第一候補に上がるJS FW
・元々pairsでも使っていた
 - メンバーはみんな書ける(はず)
・状態遷移が非常に楽
- pairsと相性が良い
・SPAにしたい
 - アクション増加 => マッチング数増加
Why AngularJS?
AngularJS x TypeScript
x
Why TypeScript?
・話せば長くなります。
Why TypeScript?
あるよく晴れた日の午後…
one day, very sunny day afternoon…
ʕº̫͡ºʔ<「うーん今日もいい天気」
Why TypeScript?
ʕº̫͡ºʔ<「うーん今日もいい天気」
ʕº̫͡ºʔ<「こんな日はJavaScriptに限る」
Why TypeScript?
ʕº̫͡ºʔ<「うーん今日もいい天気」
ʕº̫͡ºʔ<「こんな日はJavaScriptに限る」
ʕº̫͡ºʔ<「ん…なんだこれは…」
Why TypeScript?
Why TypeScript?
ʕº̫͡ºʔ<「shit…!」
Why TypeScript?
ʕº̫͡ºʔ<「shit…!」
ʕº̫͡ºʔ<「どうしたもんか…」
Why TypeScript?
ʕº̫͡ºʔ<「shit…!」
ʕº̫͡ºʔ<「どうしたもんか…」
ʕº̫͡ºʔ<「 」
Why TypeScript?
ʕº̫͡ºʔ<「shit…!」
ʕº̫͡ºʔ<「どうしたもんか…」
ʕº̫͡ºʔ<「 コミット時に強制lintだ!」
Why TypeScript?
$ jshint
Why TypeScript?
$ jshint
hoge.js: line 17, col 187, Line is too long.
hoge.js: line 25, col 174, Line is too long.
hoge.js: line 27, col 126, Line is too long.
hoge.js: line 31, col 126, Line is too long.
hoge.js: line 145, col 124, Line is too long.
hoge.js: line 22, col 42, Expected '===' and instead saw '=='.
hoge.js: line 24, col 44, Expected '===' and instead saw '=='.
hoge.js: line 306, col 11, Missing semicolon.
…
Why TypeScript?
$ jshint | wc -l
Why TypeScript?
ʕº̫͡ºʔoo0(…)
Why TypeScript?
ʕº̫͡ºʔoo0(…)
ʕº̫͡ºʔoo0(さて、日報書いて帰りますか…)
Why TypeScript?
そして月日は流れ…
someday…
2014年 10月
Oct, 2014
ʕº̫͡ºʔ(私=森川)      (ボス)ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
Why TypeScript?
「森川さん」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
Why TypeScript?
「森川さん」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
「pairsっていうサービスがあるので」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
Why TypeScript?
「森川さん」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
「pairsっていうサービスがあるので」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
「Goで書き直して下さい」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
Why TypeScript?
ʕº̫͡ºʔoo0(shit…)
Why TypeScript?
ʕº̫͡ºʔoo0(shit…)
ʕº̫͡ºʔ<「は、はい!分かりました!」
Why TypeScript?
「DBスキーマはこんな感じで。」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
Why TypeScript?
「DBスキーマはこんな感じで。」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
「APIの定義はJSON Schema見てください」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
Why TypeScript?
「DBスキーマはこんな感じで。」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
「APIの定義はJSON Schema見てください」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
「リリースはX月Y日です」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
Why TypeScript?
「リリース日は何としても死守して下さい」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
Why TypeScript?
「リリース日は何としても死守して下さい」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
「さもなくばサービスが死にます」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
Why TypeScript?
「リリース日は何としても死守して下さい」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
「さもなくばサービスが死にます」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
(私の首も飛びます)0ooʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
Why TypeScript?
「リリース日は何としても死守して下さい」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
「さもなくばサービスが死にます」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
(私の首も飛びます)0ooʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
「それとGWに合宿入れておきましたw」>ʕ̡̢̡ʘ̅͟͜͡ʘ̲̅ʔ̢̡̢
Why TypeScript?
ʕº̫͡ºʔoo0(目が笑ってない…)
Why TypeScript?
ʕº̫͡ºʔoo0(目が笑ってない…)
ʕº̫͡ºʔoo0(うう…デスマは嫌だ…)
Why TypeScript?
ʕº̫͡ºʔoo0(目が笑ってない…)
ʕº̫͡ºʔoo0(うう…デスマは嫌だ…)
ʕº̫͡ºʔ<「 」
Why TypeScript?
ʕº̫͡ºʔ<「そうだ!」
Why TypeScript?
ʕº̫͡ºʔ<「そうだ!」
ʕº̫͡ºʔ<「iOS/Androidと同じAPI使って」
Why TypeScript?
ʕº̫͡ºʔ<「そうだ!」
ʕº̫͡ºʔ<「iOS/Androidと同じAPI使って」
ʕº̫͡ºʔ<「PCとスマホで同じJSコード使えば」
Why TypeScript?
ʕº̫͡ºʔ<「そうだ!」
ʕº̫͡ºʔ<「iOS/Androidと同じAPI使って」
ʕº̫͡ºʔ<「PCとスマホで同じJSコード使えば」
ʕº̫͡ºʔ<「工数を削減できるぞ!」
Why TypeScript?
SPA
therefore SPA
ここまで一切TypeScriptの話 無し
TypeScript
ʕº̫͡ºʔ<「型が欲しい。」
ʕº̫͡ºʔ<「コンパイルしたい。」
ʕº̫͡ºʔ<「無駄な学習コスト払いたくない。」
ʕº̫͡ºʔ<「でもいざとなったらJSに戻すかも」
Why TypeScript?
「でも、お高いんでしょ?」
「でも、お高いんでしょ?」
「お任せ下さい!」
ʕº̫͡ºʔ<「型が欲しい。」
=> いざとなったらanyも使えて良い。
Why TypeScript?
ʕº̫͡ºʔ<「コンパイルしたい。」
=> コンパイルの安心感。
Why TypeScript?
ʕº̫͡ºʔ<「無駄な学習コスト払いたくない。」
=> ES6のシンタックス。
Why TypeScript?
ʕº̫͡ºʔ<「でもいざとなったらJSに戻すかも」
=> おまかせくだ(ry
Why TypeScript?
AngularJS x TypeScript
x
・ディレクトリ構成
↓を参考にしています
Best Practice Recommendations for Angular App Structure
AngularJS
app/
- 機能群/
- ログイン/
- 検索/
- controller/
- service/
- directive/
- routing.ts
- 共通ライブラリ/
- e2eテスト/
AngularJS directory structure
AngularJS route
module pairs.search {!
!angular.module('pairs.search', [!
! !'ui.router',!
! !'ipCookie',!
!]).config([!
! !'$stateProvider', !
! !'$urlRouterProvider', !
! !'$locationProvider', !
! !states!
!]).service('SearchService', [!
! !'HttpService', !
! !'$q', !
! !'ipCookie', !
! !SearchService!
!]).controller(controller)!
!.directive(directive);!
AngularJS route
!function states(!
! !$stateProvider: ng.ui.IStateProvider,!
! !$urlRouterProvider: ng.ui.IUrlRouterProvider,!
! !$locationProvider: ng.ILocationProvider!
!) {!
! !$stateProvider!
! ! !.state('search', {!
! ! ! !url: '^/search/:type/{page:int}',!
! ! ! !controllerAs: 'ctrl',!
! ! ! !controller: controller.SearchController,!
! ! ! !templateUrl: '/search/hoge'!
! ! !});!
!}
・ロジックは、ほぼ書かない前提
・ディレクティブ用のshared controllerな感じ
=> RIP controller in Angular2
AngularJS controller
・可搬性の高いテンプレートにしたい
・インタラクティブなイベント・発火処理はこちら
・必要なデータだけコントローラーからもらう
AngularJS directive
・色んなロジックを書く
・様々なdirective間で使い回しできるようにする
AngularJS service
・色んなロジックを書く
・様々なdirective間で使い回しできるようにする
=> テストがしやすくなる
AngularJS service
・ベーシックにKarma & Jasmine
AngularJS unit testing
・ベーシックにKarma & Jasmine(の予定)
AngularJS unit testing
・ベーシックにKarma & Jasmine(の予定)
=> 実はまだ整っていない…
AngularJS unit testing
・ベーシックにKarma & Jasmine(の予定)
=> 実はまだ整っていない…
・TSコンパイルは通るけど、karma実行時にTSエラーになる
・駄目だったらJSで書く予定
AngularJS unit testing
・ベーシックにKarma & Jasmine(の予定)
=> 実はまだ整っていない…
・TSコンパイルは通るけど、karma実行時にTSエラーになる
・駄目だったらJSで書く予定(来週のタスク)
AngularJS unit testing
・Protractor
AngularJS e2e testing
・Protractor
AngularJS e2e testing
・Protractor
- AngularJS用のe2eテストFW
- 非同期処理をいい感じで待ってくれる
AngularJS e2e testing
【ディレクトリ構成】
- 機能テスト/ // 単体テスト
- シナリオテスト/ // 結合テスト
- ページオブジェクト/
- ログインページ/
- 検索ページ/
- helper.js
- config.js
AngularJS protractor directory
【ディレクトリ構成】
- 機能テスト/ // 単体テスト
- シナリオテスト/ // 結合テスト
- ページオブジェクト/
- ログインページ/
- 検索ページ/
- helper.js
- config.js
AngularJS protractor directory
・特定のHTMLの塊の機能に関する処理を書く
・テストコードから直接HTML elementは操作しない
・HTMLに関する処理はページオブジェクトに書く
・1ページ1オブジェクトじゃなくてもOK
AngularJS page object
AngularJS page object
var LoginPage = function() {!
!// ログインボタンのエレメント!
this.loginButton = element(by.id('login'))!
!
!// ログインページを開く!
this.open = function(){!
browser.get('/#/login');!
}!
!
!// ログインボタンを押下する!
this.clickLoginButton = function(){!
var loginButton = new LoginPage().loginButton;!
return browser.wait(function(){!
return loginButton.isPresent();!
}).then(function(){!
return loginButton.click();!
});!
};!
};!
module.exports = new LoginPage();
【ディレクトリ構成】
- 機能テスト/ // 単体テスト
- シナリオテスト/ // 結合テスト
- ページオブジェクト/
- ログインページ/
- 検索ページ/
- helper.js
- config.js
AngularJS protractor directory
AngularJS helper
// time_helper.js!
!
var TimeHelper = function(){!
!// 現在のUNIXTIMEを取得する!
!this.getCurrentUnixtime = function(){!
! !return Math.floor(new Date/1000);!
!};!
!!
};!
!
module.exports = TimeHelper;
AngularJS helper
// helper.js!
!
var Helper = function(){};!
!
// 外部で定義したヘルパー関数をHelperへ詰め込む(mixin的な?)!
require('./time_helper').call(Helper.prototype);!
require('./selectbox_helper').call(Helper.prototype);!
require('./hoge_helper').call(Helper.prototype);!
!
module.exports = new Helper();
AngularJS page object w/ helper
// login.po.js!
!
var LoginPage = function() {!
// load helper!
!var helper = require('../helper');!
!// 都道府県のセレクトボックス !
this.stateSelect = element(by.model('vm.state_id'));!
!
!// セレクトボックスから指定した都道府県を選択する!
this.selectStateByName = function(name){!
var el = new LoginPage().stateSelect;!
helper.selectDropdownByText(el, name);!
}!
};!
!
module.exports = new LoginPage();
・TSじゃなくてJS
- jQueryの型定義ェ…
・CircleCIでも回す
- ローカルだとこけないのに、CircleCIだと失敗
AngularJS e2e testing
・CircleCIの失敗
AngularJS e2e w/ CI
・CircleCIの失敗
- Slackに通知行く
- エラーに慣れる
- 非常に困る
AngularJS e2e w/ CI
・CircleCIの失敗
- Slackに通知行く
- エラーに慣れる
- 非常に困る
・なんで失敗するのか
AngularJS e2e w/ CI
・CircleCIの失敗
- Slackに通知行く
- エラーに慣れる
- 非常に困る
・なんで失敗するのか
- e2eがタイムアウトしてる
- Angular以外のページ
AngularJS e2e w/ CI
・CircleCIの失敗
- Slackに通知行く
- エラーに慣れる
- 非常に困る
・なんで失敗するのか
- e2eがタイムアウトしてる
- Angular以外のページ
=> Facebookのログインポップアップ
AngularJS e2e w/ CI
ʕº̫͡ºʔ<「Facebookのポップアップだって?!」
AngularJS e2e w/ CI
ʕº̫͡ºʔ<「Facebookのポップアップだって?!」
ʕº̫͡ºʔ<「よーし、おじさん頑張っちゃうぞ」
AngularJS e2e w/ CI
5時間後…
5 hours later…
ʕº̫͡ºʔ<「無理」
AngularJS e2e w/ CI
ʕº̫͡ºʔ<「無理」
ʕº̫͡ºʔ<「ログアウト機能追加しても無理」
AngularJS e2e w/ CI
ʕº̫͡ºʔ<「無理」
ʕº̫͡ºʔ<「ログアウト機能追加しても無理」
ʕº̫͡ºʔ<「クッキー全削除でも無理」
AngularJS e2e w/ CI
ʕº̫͡ºʔ<「無理」
ʕº̫͡ºʔ<「ログアウト機能追加しても無理」
ʕº̫͡ºʔ<「クッキー全削除でも無理」
ʕº̫͡ºʔ<「シークレットモード(Chrome)でも無理」
AngularJS e2e w/ CI
3時間後…
3 hours later…
ʕº̫͡ºʔoo0(…)
AngularJS e2e w/ CI
ʕº̫͡ºʔoo0(…)
ʕº̫͡ºʔoo0(さて、日報書いて帰りますか…)
AngularJS e2e w/ CI
ʕº̫͡ºʔoo0(…)
ʕº̫͡ºʔoo0(さて、日報書いて帰りますか…)
(再掲)
AngularJS e2e w/ CI
解決策
q.e.d.
・複数のテストタスクをgulpに登録する
=> 違うテストタスクとして起動させる
- ブラウザが起動し直される
- ちゃんとCookie削除されます
AngularJS e2e w/ CI
AngularJS e2e w/ CI
// circle.yml!
!
test:!
override:!
!# Goのテスト!
- gvm use stable; ginkgo -tags=tests -r . -cover!
!# メインのe2e!
- gulp e2e!
- sleep 2!
!# ログインページ その1!
- gulp e2e:login_success!
- sleep 2!
!# ログインページ その2!
- gulp e2e:login_error1!
- sleep 2!
!# ログインページ その3!
- gulp e2e:login_error2
AngularJS e2e w/ CI
(e2e失敗のデモ)
tl;dr
ʕº̫͡ºʔ<「TypeScriptの安心感」 // 全然触れてない
ʕº̫͡ºʔ<「テストコードの安心感」
ʕº̫͡ºʔ<「CIの安心感」
tl;dr
第一部 完
fin.
「世界で愛されるサービス」を一緒に作りませんか?
セグメントNo1 サービス
グローバルビジネス
Business!
pairs Goフルスクラッチ
Engineering!
マッチングアルゴリズム
Big Data!
✕
ハイブリッドエンジニア 大規模行動データ解析
CONFIDENTIAL!
Thank you :)!
Thank you :)!

pairsでのAngularJS x TypeScript x e2e @めぐすた#1