ニコニコandroid(サーバ編) - scalaを業務で使って

95
ニコニコAndroid - サーバ編 - 間島 大智

Upload: daichi-mashima

Post on 21-May-2015

12.047 views

Category:

Technology


3 download

DESCRIPTION

2013 JJUG(http://www.java-users.jp/?page_id=330) #jjug_ccc ※一部発表時と異なる点があります

TRANSCRIPT

Page 1: ニコニコAndroid(サーバ編) - Scalaを業務で使って

ニコニコAndroid- サーバ編 -

間島 大智

Page 2: ニコニコAndroid(サーバ編) - Scalaを業務で使って

目次

•ニコニコAndroidサーバって何?

• Scalaいいところ・わるいところ

•サーバチームの仕事の流れ

Page 3: ニコニコAndroid(サーバ編) - Scalaを業務で使って

間島 大智

•株式会社ドワンゴ

•ニコニコAndroidサーバチーム

• 2012年新卒入社

Page 4: ニコニコAndroid(サーバ編) - Scalaを業務で使って

間島 大智

•株式会社ドワンゴ

•ニコニコAndroidサーバチーム

• 2012年新卒入社

Page 5: ニコニコAndroid(サーバ編) - Scalaを業務で使って

間島 大智

•株式会社ドワンゴ

•ニコニコAndroidサーバチーム

• 2012年新卒入社

•化学の知識を活用できるWebサービスのプロジェクトまだですかね

Page 6: ニコニコAndroid(サーバ編) - Scalaを業務で使って

ニコニコAndroidサーバって?

社内向けAPI・DB

ニコニコAndroidサーバ

Androidアプリau STBアプリ

様々なアプリでニコニコを使うために

必要なAPIを提供

Page 7: ニコニコAndroid(サーバ編) - Scalaを業務で使って

プロジェクトの歴史

• 2012/02 プロジェクト発足

• 2012/08 au STBアプリリリース

• 2012/11 Androidアプリリリース

•74 API•330万リクエスト/日

Page 8: ニコニコAndroid(サーバ編) - Scalaを業務で使って

サーバ側メンバー

• mashijp (github)

• @kozo1215

• @mtgto

• @mitikage

• @kimwoonsung

• インフラ2人

Page 9: ニコニコAndroid(サーバ編) - Scalaを業務で使って

環境

•言語: Scala

•フレームワーク: Play Framework 2.0

• IDE: IntelliJ IDEA 11, 12• CI: Jenkins

社内初

Page 10: ニコニコAndroid(サーバ編) - Scalaを業務で使って

ニコニコAndroidサーバって?

Page 11: ニコニコAndroid(サーバ編) - Scalaを業務で使って

ニコニコAndroidサーバの役目

社内向けAPI・DB

ニコニコAndroidサーバ

Androidアプリau STBアプリ

この位置に求められることって…?

Page 12: ニコニコAndroid(サーバ編) - Scalaを業務で使って

ニコニコAndroidサーバに求められること

社内向けAPI・DB

ニコニコAndroidサーバ

Androidアプリau STBアプリ

アプリにとって使いやすいAPIを提供すること

Page 13: ニコニコAndroid(サーバ編) - Scalaを業務で使って

使いやすいAPIとは?

•用語が統一されている

•用語が直感的に理解できる

•内部的な細かい仕様を知らなくていい

•ドキュメント化されている

Page 14: ニコニコAndroid(サーバ編) - Scalaを業務で使って

•用語が統一されている

•用語が直感的に理解できる

•内部的な細かい仕様を知らなくていい

逆にこの3つを満たしていないAPIって?

Page 15: ニコニコAndroid(サーバ編) - Scalaを業務で使って

社内APIを変えればいい?

長い歴史があるもの(社内API)にはどうしてもわかりにくい用語・仕様がまじってしまう

社内APIを修正すればいい…?

Page 16: ニコニコAndroid(サーバ編) - Scalaを業務で使って

そう簡単には変えられない

•社内APIは多数の社内サービスが既に使っている

•仕様を変更するのは容易ではない

Page 17: ニコニコAndroid(サーバ編) - Scalaを業務で使って

サーバで内部仕様を吸収

mylist.list deflist.listmylist.remove deflist....

GET /xxx/mylists/:id

社内向けAPI・DB

ニコニコAndroidサーバ

Androidアプリau STBアプリ わかりやすい!

モデルもScalaで再定義

Page 18: ニコニコAndroid(サーバ編) - Scalaを業務で使って

ドメイン層

Androidアプリau STBアプリ

インフラストラクチャ層

社内向けAPI・DB

API層

ドメイン駆動設計による浄化

社内APIを叩くことだけに専念

ビジネスロジックだけに専念

リクエストの処理だけに専念

明確にレイヤー分離された設計をしています

Page 19: ニコニコAndroid(サーバ編) - Scalaを業務で使って

社内向けAPIドキュメント

• Confluence(Wikiみたいなもの)で管理

•全てのAPIについて細かく記述している

Page 20: ニコニコAndroid(サーバ編) - Scalaを業務で使って

ドキュメントの例

Page 21: ニコニコAndroid(サーバ編) - Scalaを業務で使って

ドキュメントの例

Page 22: ニコニコAndroid(サーバ編) - Scalaを業務で使って

ドキュメントの例

Page 23: ニコニコAndroid(サーバ編) - Scalaを業務で使って

ドキュメントの例共通で使うレスポンスの形は別ページにしている(多重管理を避けるため)

Page 24: ニコニコAndroid(サーバ編) - Scalaを業務で使って

APIドキュメントの記述

•社内向けAPIドキュメントだからといって決して手を抜いていない

•多重管理を避け、ドキュメントが古くなってしまうことを避けている

Page 25: ニコニコAndroid(サーバ編) - Scalaを業務で使って

使いやすいAPIが実現できた

•用語が統一され、直感的に理解できる

•内部的な細かい仕様を知らなくていい

•ドキュメント化されている

→Scalaでモデルを再定義しアプリに提供

→社内向けだからといって甘えていない 管理しやすく見やすいドキュメント作成

Page 26: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Scalaの良い所・悪い所

Page 27: ニコニコAndroid(サーバ編) - Scalaを業務で使って

環境

•言語: Scala

•フレームワーク: Play Framework 2.0

• IDE: IntelliJ IDEA 11, 12• CI: Jenkins

Page 28: ニコニコAndroid(サーバ編) - Scalaを業務で使って

•昨年6月、新卒研修が終わりニコニコAndroidチームに配属された

•入社前

• Javaは趣味で触ってた

•が、 “Scala”は名前すら知らない

Scala…?!

Page 29: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Java利用者にとってのScala実体験をふまえて

Page 30: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Scalaって?•静的型付け言語

•関数型言語とオブジェクト指向言語のハイブリッド

• JVM上で動く

• Javaのコードも簡単に混ぜられる

Page 31: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Scalaって?•静的型付け言語

•関数型言語とオブジェクト指向言語のハイブリッド

• JVM上で動く

• Javaのコードも簡単に混ぜられる

って言われても何が良いのかわからん!

Page 32: ニコニコAndroid(サーバ編) - Scalaを業務で使って

便利やでScala

•型推論

•コレクション関数

•対話環境

• Option型

Page 33: ニコニコAndroid(サーバ編) - Scalaを業務で使って

型推論String str = “fugahoge”;String piyo = str + “piyo”;

Java

Page 34: ニコニコAndroid(サーバ編) - Scalaを業務で使って

型推論String str = “fugahoge”;String piyo = str + “piyo”;

Java

Page 35: ニコニコAndroid(サーバ編) - Scalaを業務で使って

型推論String str = “fugahoge”;String piyo = str + “piyo”;

Java

↑書かなくても右辺見ればわかる

Page 36: ニコニコAndroid(サーバ編) - Scalaを業務で使って

型推論String str = “fugahoge”;String piyo = str + “piyo”;

Java

Scala

↑書かなくても右辺見ればわかる

Page 37: ニコニコAndroid(サーバ編) - Scalaを業務で使って

型推論String str = “fugahoge”;String piyo = str + “piyo”;

Java

Scala

↑書かなくても右辺見ればわかる

val str = “fugahoge”val piyo = str + “piyo”

Page 38: ニコニコAndroid(サーバ編) - Scalaを業務で使って

型推論String str = “fugahoge”;String piyo = str + “piyo”;

Java

Scala

↑書かなくても右辺見ればわかる

val str = “fugahoge”val piyo = str + “piyo”↑コンパイラが勝手にStringと推測

Page 39: ニコニコAndroid(サーバ編) - Scalaを業務で使って

型推論

Page 40: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Scala型推論

Page 41: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Scala型推論

def replaceAbc(str: String) = {str.replaceAll(“abc”, “def”)

}

val fuga = replaceAbc(“abcdef”)

Page 42: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Scala型推論

def replaceAbc(str: String) = {str.replaceAll(“abc”, “def”)

}

val fuga = replaceAbc(“abcdef”)

↑メソッドの返り値はStringと推測される

Page 43: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Scala型推論

def replaceAbc(str: String) = {str.replaceAll(“abc”, “def”)

}

val fuga = replaceAbc(“abcdef”)

↑メソッドの返り値はStringと推測される

↑よって、fugaもString

Page 44: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Scala型推論

def replaceAbc(str: String) = {str.replaceAll(“abc”, “def”)

}

val fuga = replaceAbc(“abcdef”)

↑メソッドの返り値はStringと推測される

↑よって、fugaもString

冗長な記述をしなくていい

Page 45: ニコニコAndroid(サーバ編) - Scalaを業務で使って

コレクション関数Java

String[] strs = {“a”, “fuga”, “bb”, “hogee”};List<String> result = new ArrayList<String>();for(String str : strs) { if (str.length >= 3) { result.add(str); }}return result;

Page 46: ニコニコAndroid(サーバ編) - Scalaを業務で使って

コレクション関数Scala

val strs = List(“a”, “fuga”, “bb”, “hogee”);return strs.filter(_.length >= 3)

強力なコレクション関数+型推論によりコード記述量を大幅に減らせる

Page 47: ニコニコAndroid(サーバ編) - Scalaを業務で使って

ちなみに

•ニコニコAndroidサーバのコードにはfor文は7つしかない

Page 48: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Scalaのfor使うときval list1 = List(“a”, “b”, “c”)val list2 = List(1, 2, 3)for(a <- list1; b <- list2) {println(a+b)

}

Page 49: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Scalaのfor使うときval list1 = List(“a”, “b”, “c”)val list2 = List(1, 2, 3)for(a <- list1; b <- list2) {println(a+b)

}

出力結果: a1 a2 a3 b1 b2 b3 c1 c2 c3

Page 50: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Scalaのfor使うときval list1 = List(“a”, “b”, “c”)val list2 = List(1, 2, 3)for(a <- list1; b <- list2) {println(a+b)

}

出力結果: a1 a2 a3 b1 b2 b3 c1 c2 c3

複数のコレクションの組み合わせを網羅するのに非常に便利

Page 51: ニコニコAndroid(サーバ編) - Scalaを業務で使って

強力なコレクション関数+for

•コード記述量が大幅に減った•単純なコレクションの処理をする際にfor文使うことほぼなし

•たまに「forどうやって書くんだっけ」という声がでるほど…

Page 52: ニコニコAndroid(サーバ編) - Scalaを業務で使って

対話環境

Page 53: ニコニコAndroid(サーバ編) - Scalaを業務で使って

強力なimport文

•ブロックの中にかける

•別名をかける

Scala

Page 54: ニコニコAndroid(サーバ編) - Scalaを業務で使って

importをブロックの中にかける

import java.util.Date;public void methodA(){ Date date = new Date(). .......}

public void methodB(){ java.sql.Date date = new java.sql.Date(..). .......}

Java

名前が衝突するのでimportできず、フルネームで書くしかない

Page 55: ニコニコAndroid(サーバ編) - Scalaを業務で使って

importをブロックの中にかける

def methodA() = { import java.util.Date val date = new Date(). .......}def methodB() = { import java.sql.Date val date = new Date(..). .......}

Scala

Page 56: ニコニコAndroid(サーバ編) - Scalaを業務で使って

別名をつけられるimport java.util.Dateimport java.sql.{Date => SqlDate}def methodA() = { val date = new Date(). .......}def methodB() = { val date = new SqlDate(..). .......}

Scala

Page 57: ニコニコAndroid(サーバ編) - Scalaを業務で使って

強力なimport文

•ブロックの中にかける&別名をつけることができる

•クラス名をつける際に「かぶりそうだな…」と怯えることがなくなった

•短いクラス名をどんどんつけちゃう

•例) Client (Redis接続用クラス)

Page 58: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Option型Java

・このメソッドってnull返すことあるっけ? えーとドキュメント...・あ、そうだ nullチェックしないと... if (result != null) { ....

Page 59: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Option型Java

・このメソッドってnull返すことあるっけ? えーとドキュメント...・あ、そうだ nullチェックしないと... if (result != null) { .... Null

PointerE

xception

Page 60: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Javaでぬるぽを起こす例

Java

Map<String, String> map = getMap();String result = map.get(fieldName);if (result.length() >= 3) { return “長さは”+result.length();} else { return “短い!!”;}

Mapからとってきたものが3文字以上かどうかチェックするメソッド

Page 61: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Javaでぬるぽを起こす例

Java

Map<String, String> map = getMap();String result = map.get(fieldName);if (result.length() >= 3) { return “長さは”+result.length();} else { return “短い!!”;}

Mapからとってきたものが3文字以上かどうかチェックするメソッド

Page 62: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Javaでぬるぽを起こす例

Java

Map<String, String> map = getMap();String result = map.get(fieldName);if (result.length() >= 3) { return “長さは”+result.length();} else { return “短い!!”;}

NullPointerException!!!   ( ・∀・)   | | ガッ  と    )    | |    Y /ノ    人     / )    <  >__Λ∩   _/し' //. V`Д´)/  (_フ彡        /

そんなキーねえよ

Mapからとってきたものが3文字以上かどうかチェックするメソッド

Page 63: ニコニコAndroid(サーバ編) - Scalaを業務で使って

nullチェック追加

Map<String, String> map = getMap();String result = map.get(fieldName);if (result != null && result.length() >= 3) { return “長さは”+result.length();} else { return “短い!!”;}

Java

Page 64: ニコニコAndroid(サーバ編) - Scalaを業務で使って

nullチェック追加

Map<String, String> map = getMap();String result = map.get(fieldName);if (result != null && result.length() >= 3) { return “長さは”+result.length();} else { return “短い!!”;}

Java

どうしてもnullチェック忘れてしまう…!

Page 65: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Option型って?

Option[T]

Some[T] None

値がある 値がない

値がある・ないを型で表現している

Scala

Page 66: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Option型の挙動Scalaval map = Map("key1" -> "value1", "key2" -> "value2")// Map#getの返り値はOption型(ここではOption[String])println(map.get(“key1”))//→ Some(value1)println(map.get(“fuga”))//→ Nonemap.get(“key1”).getOrElse(“ないとき”)//→ value1map.get(“fuga”).getOrElse(“ないとき”)//→ ないとき

Someのときは中身を取り出し、Noneのときは引数を返す

Page 67: ニコニコAndroid(サーバ編) - Scalaを業務で使って

型で値がないことに気づける

val map = getMap()val result = map.get(fieldName)

↑resultの型は Option[String]この時点で「値がないこともありうる」ということに気づける

Scala

Page 68: ニコニコAndroid(サーバ編) - Scalaを業務で使って

val map = getMap()val result = map.get(fieldName)result.filter(_.length > 3).map(e => “長さは”+e.length).getOrElse(“短い”)

さっきの例をScalaで実装

Scala

Page 69: ニコニコAndroid(サーバ編) - Scalaを業務で使って

ぬるぽがない安心感

• Scalaの標準ライブラリは原則nullを返さない(Scalaはnullを使わない文化)

•つまりnullチェックを書く必要がない

Page 70: ニコニコAndroid(サーバ編) - Scalaを業務で使って

社内向けAPIドキュメント

Page 71: ニコニコAndroid(サーバ編) - Scalaを業務で使って

社内向けAPIドキュメント

nullがありうるものをドキュメントに残すのに苦労しなかった

Page 72: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Scalaの悪いところ...

•コンパイル遅すぎ!

•社内にScalaについて聞ける人が少ない

Page 73: ニコニコAndroid(サーバ編) - Scalaを業務で使って

コンパイル

•遅い!!とにかく遅い!!

•メモリ食い過ぎー!

•ビルド時のJavaの設定-Xms512m -Xmx1024m -XX:MaxPermSize=512m

Scala

Page 74: ニコニコAndroid(サーバ編) - Scalaを業務で使って

コンパイル

•遅い!!とにかく遅い!!

•メモリ食い過ぎー!

•ビルド時のJavaの設定-Xms512m -Xmx1024m -XX:MaxPermSize=512m

Scala

Jenkinsで並行ビルドするとスワップアウト...→ Jenkinsサーバのメモリ増設(4GB → 8GB)

Page 75: ニコニコAndroid(サーバ編) - Scalaを業務で使って

社内に聞ける人が少ない

•弊社内でScalaのプロジェクトはニコニコAndroidサーバが初めて

•社内ノウハウが少ない…

• Scala書ける人もあんまりいない…

Page 76: ニコニコAndroid(サーバ編) - Scalaを業務で使って

学習コストはそんなにかからない

開発メンバー5人中4人がScalaをはじめて1年たっていない

Page 77: ニコニコAndroid(サーバ編) - Scalaを業務で使って

学習コストはそんなにかからない

開発メンバー5人中4人がScalaをはじめて1年たっていない

でも1ヶ月勉強したら業務で書けるようになった

Page 78: ニコニコAndroid(サーバ編) - Scalaを業務で使って

どうやって勉強?

•おすすめ本「JavaプログラマのためのScalaプログラミング」

•疑問は社内IRCでブツブツ言う

•誰か答えてくれる

• #scalaというチャンネルもできた

Page 79: ニコニコAndroid(サーバ編) - Scalaを業務で使って

少しずつ広まっている...!

最近は社内でもScalaを使う流れができつつあり、今後は改善されそう!

ドワンゴでは4プロジェクトがScala使ってます

Page 80: ニコニコAndroid(サーバ編) - Scalaを業務で使って

チームの実際の仕事の流れ

Page 81: ニコニコAndroid(サーバ編) - Scalaを業務で使って

仕事のサイクル

計画

振り返り 実装

レビューリリース

マージ

1周=2週間のアジャイル開発

Page 82: ニコニコAndroid(サーバ編) - Scalaを業務で使って

開発メンバー全員で2週間にやることを計画誰がどの仕事をするか割り振る

全員で計画する

Page 83: ニコニコAndroid(サーバ編) - Scalaを業務で使って

計画の前準備

会議をする前に各自でやらないといけないことを洗い出し、チケットとして作成チケット管理にはAtlassian製品のJIRAを使っています

Page 84: ニコニコAndroid(サーバ編) - Scalaを業務で使って

全員で見積もるチケットを作った人がチケットの内容を説明

工数見積もり(予想)を各自で出す

見積もりがあわなかったら最大3回やる

全員でやることを共有できているので突然誰かが倒れても大丈夫なチームに

Page 85: ニコニコAndroid(サーバ編) - Scalaを業務で使って

実装する

• IntelliJ IDEA 12 Ultimate($200)使ってます

• キャンペーンのときに全員買った

• 買うまではCommunity Edition(無料)

• 会社で買ってくれるという話も出てる

• ScalaのIDEはIntelliJ IDEA一択

• EclipseでのScala開発はめっちゃ重い…

Page 86: ニコニコAndroid(サーバ編) - Scalaを業務で使って

テストに力を入れています

1000以上のテストケースによりコードカバレッジ80%以上を達成

Page 87: ニコニコAndroid(サーバ編) - Scalaを業務で使って

FishEyeでコードレビュー

全員が仕事を理解しているので誰でもレビューできるみんなで気軽にレビューコメントをつける

Page 88: ニコニコAndroid(サーバ編) - Scalaを業務で使って

GitHub:eよりFishEyeのほうが便利

•誰がレビューOK出しているのか、どれぐらい見ているのかがすぐ分かる!

全員のレビューOKが出ればマージする

Page 89: ニコニコAndroid(サーバ編) - Scalaを業務で使って

Jenkins•ビルド

•テストの実行

• developブランチにマージするとJenkinsが動き出す

•テストが落ちるとチームメンバーに罵られる

Page 90: ニコニコAndroid(サーバ編) - Scalaを業務で使って

振り返る(KPT)

毎週水曜日にKPTKeep(続けたいこと), Problem(困ったこと),Try(次やりたいこと) をみんなで自由に書く

Page 91: ニコニコAndroid(サーバ編) - Scalaを業務で使って

KPTで改善された例

Jenkins用サーバで並行ビルドできない

もっとスペックの高いJenkins用サーバを調達し、並行ビルド可能に

Problem

Try

Page 92: ニコニコAndroid(サーバ編) - Scalaを業務で使って

思ったことを気軽に書けるので「ちょっとした問題」を改善していく

流れを作ることができた

Page 93: ニコニコAndroid(サーバ編) - Scalaを業務で使って

強いチーム作りに成功

「全員で」計画し「全員で」振り返ることで常に意識を共有

全員が主体的に動く強いチームを作っています

Page 94: ニコニコAndroid(サーバ編) - Scalaを業務で使って

ドワンゴで働きませんか

• Scalaに興味のある人もない人も

• 「ドワンゴ 採用」で検索!

• http://info.dwango.co.jp/recruit/

• 7月から新オフィス(歌舞伎座)

お待ちしています!

Page 95: ニコニコAndroid(サーバ編) - Scalaを業務で使って

まとめ• 美しいAPIをアプリチームに提供できた• Scalaで再モデリング・ドキュメント整備

• Scalaを業務で楽しく使ってます!• 強力なScalaの機能で効率の良い開発が可能に

• 強いチームでやってます• 全員が仕様を理解できている

• 誰が風邪引いても困らない