Movatterモバイル変換


[0]ホーム

URL:


Lintaro Ina, profile picture
Uploaded byLintaro Ina
PDF, PPTX72,668 views

はてなブックマーク in Scala

2015-08-01 Scala関西 Summit 2015 発表資料(関係モナドについて発表後に公開したコードなどへのリンクのスライドを追加)

Embed presentation

Download as PDF, PPTX
はてなブックマークin Scala伊奈 林太郎id:tarao @oarat2015-08-01@ Scala 関西 Summit 2015
自己紹介名前  い な伊奈   りんたろう林太郎  (id:tarao @oarat)2008-08 はてなインターン2008-10 はてなアルバイト (ブックマークチーム)2010-04 日本学術振興会 特別研究員 (DC1)2013-04 はてな正社員2013-12 ブックマークチーム◮ アルゴリズム屋さん◮ 検索技術 > 機械学習 ≫ アドテク◮ 最近は設計したり基盤寄りな部分を担当したり
自己紹介名前  い な伊奈   りんたろう林太郎  (id:tarao @oarat)Scala 歴: 4ヶ月◮ slick-jdbc-extension◮ 型レベルのラムダ計算◮ Software Design 2015 年 8 月号大学時代は◮ 研究室: 型理論, プログラム意味論, 証明支援系◮ OCaml が公用語◮  gradual typing漸進的型付け の Java 系言語への応用を研究
いちから作りなおし!
いちから作りなおし!Scalaで!
いちから作りなおし!Scalaで!ねらい◮ コードベースの肥大化・老朽化への対処◮ 根本的なアーキテクチャの再設計
DISCLAIMER◮ 内容は開発中のもの◮ 実際のリリース時には変更の可能性あり◮ 最終的にどうなったか公表するかどうか未定
構成◮ 前後で Perl/Scala に分割◮ コアは B!以外からも利用◮ Presso◮ B!KUMAビュー (Perl)◮ ユーザ認証◮ HTML のレンダリングコア (Scala)◮ API サーバ◮ 社内基盤的側面
Why Scala?◮ 変更の少ない重要部分は堅牢にしたい◮ 型安全性◮ ドメイン駆動設計◮ Mackerel チームでの使用実績◮ LL 勢にも書きやすい◮ エンジニアのチーム異動が容易になる◮ Perl との心中を避ける◮ 個人的には◮ 新言語を導入するなら関数型でないと許さん◮ 強い静的型付言語でないと許さん◮ 型推論ないと許さん
Why Perl?◮ 頻繁に変更があっても開発が楽◮ デザイナも HTML テンプレートを触る◮ コンパイルしなおさなくてよい◮ ローカル開発環境での作業が容易◮ 学習コスト 0◮ 認証まわりは共通 Perl モジュールでやりたい◮ あとで捨ててまた作り直すかもしれない
フレームワークフレームワークフレームワークフレームワークフレームワークフレームワークフレームワーク
これまで (Perl)第 1 世代 Apache mod perl 上の簡易的なもの第 2 世代 内製の Perl 版 RoR 的な重厚なもの◮ 学習コスト高◮ 自由がきかない第 3 世代 薄いフレームワークの集合◮ よくできた小モジュールの組み合わせ◮ 自由度が高く入れ替え可能◮ ≫ YAPC::Asia 2015 talk by id:hitode909
新コアサーバ (Scala)Web◮ Scalatra◮ APISchemaのScala 版 (予定)DB◮ Slick 3.0◮ slick-jdbc-extension◮ 独自のべんりに使う層テスト◮ ScalaTest
WebフレームワークScalatra◮ API サーバなので簡素でよい◮ 返り値が Any なの嫌なのでラップして利用APISchema◮ Perl での実績を元に Scala 版を実装予定◮ 簡単な DSL で定義◮ JSON Schema によるリソース定義◮ パスごとのリクエストとレスポンス定義◮ 同じ定義から自動生成◮ ドキュメント◮ ルーティング処理
DBフレームワークSlick 3.0◮ 非同期 DB アクセスも利用したい◮ 文字列補間による生 SQL のみで利用◮ 予想外のクエリが生成されるのを防ぐ◮ インフラエンジニアでも読めるように◮ (あとでクエリビルダ導入の可能性はある)◮ 拡張モジュール slick-jdbc-extension◮ 文字列補間のリストの扱いなどを強化◮ カラム名での結果型へのマッピング◮ ≫ 『Scala で生 SQL - Slick の SQL 補間子にリストを渡す 他』
DBフレームワーク独自層◮ DB インスタンス管理◮ マスター/スレーブ切り替え◮ テスト時のプロセス毎 DB 分離◮ モード管理 (トランザクション, 非同期)◮ リクエストスレッドごとの非同期接続数管理
ドメイン駆動設計ドメイン駆動設計ドメイン駆動設計ドメイン駆動設計ドメイン駆動設計ドメイン駆動設計ドメイン駆動設計
旧ブックマークではDDDっぽいこともやられていた◮ アプリケーションサービス◮ ドメインサービス◮ ドメインモデル◮ CQRS (コマンドクエリ責務分離)
旧ブックマークでは失敗◮ ユビキタス言語がないまま進んだ◮ e.g. お気に入り or フォロー◮ e.g. 3 つの「インタレスト」概念◮ 方針が徹底されなかった◮ アプリ層とコントローラ層が互いに侵食◮ 内製の Perl 版 Active Record 的 O/R マッパ◮ モデル, サービス, リポジトリが渾然一体◮ 近頃の他 Perl プロダクトではまともになった◮ Perl の限界◮ インタフェースが言語機能にない
きちんとDDDしたい!◮ 有志の社内勉強会を実施◮ 非エンジニアメンバーとも共有・議論◮ Scala でのよいやり方を模索
方針◮ リポジトリはインタフェース (依存関係逆転の原則)◮ ドメインに実装上の都合を持ち込まない
悩んだ点と作戦◮ 依存性の注入どうするか◮ Cake Pattern を積極採用◮ has-a 関係を引くときの N+1 問題◮ 関係モナドを定義◮ トランザクションどこで張るか◮ いったん極小な範囲 (インフラ層) で◮ 全体的に結果整合性
悩んだ点と作戦◮ 依存性の注入どうするか◮ Cake Pattern を積極採用◮ has-a 関係を引くときの N+1 問題◮ 関係モナドを定義◮ トランザクションどこで張るか◮ いったん極小な範囲 (インフラ層) で◮ 全体的に結果整合性
Cake Patternpackage repotrait SomeComponent {def someLoader: SomeLoader// リポジトリインタフェースtrait SomeLoader {def find(...) = ...} }package dbtrait SomeComponentextends repo.SomeComponent {def someLoader: SomeLoader =SomeLoader// 実装object SomeLoaderextends SomeLoader { ... }}package apptrait ServiceComponent {// 依存の明示self: repo.SomeComponent =>trait SomeService {...someLoader.find(...)...} }package mainobject AppRootextends db.SomeComponentwith app.ServiceComponentwith ...
Cake Patternポイント◮ trait を入れ子にしておく◮ 使う側は自分型アノテーションで依存を明示◮ AppRootには実装コンポーネントを結合◮ TestRoot等を用意して別実装に入れ替えも可◮ 単体テストでコンポーネント単位で入れ替え◮ 全体でテスト用 DB ハンドラ実装に入れ替えobject TestRootextends repo.SomeMockedComponentwith app.ServiceComponentwith ...
N+1問題1 件の場合val bookmark: Bookmark = ...val locaiton: Location = bookmark.toLocation// SELECT * FROM location WHERE ...n 件の場合: n + 1 回のクエリが必要val bookmarks: Seq[Bookmark] = ...// SELECT * FROM bookmark WHERE ...val locations: Seq[Location] = bookmarks.map(_.toLocation)// SELECT * FROM location WHERE ...// SELECT * FROM location WHERE ...//... × n本当はせいぜい 2 回で済むval locations: Seq[Location] =locationLoader.findAll(bookmarks.map(_.locationId))// SELECT * FROM location WHERE location_id IN (...)
N+1問題回避策(1) JOIN解決方法◮ bookmarksと locaitonsをいっぺんに引く◮ JOIN して引けば可能問題点◮ 一般的には JOIN したくない場合もある◮ e.g. bookmarksが入力となるサービス内◮ NG: 実装上の都合がモデルの引き方を左右する
N+1問題回避策(2) 愚直に解決方法◮ ていねいに関係先を引いてくる問題点◮ 元の要素と対応づけたい場合に面倒val bookmarks: Seq[Bookmark] = ...val locations: Seq[Location] =locationLoader.findAll(bookmarks.map(_.locationId))val id2loc = locations.map{ l => l.id -> l }.toMapval bookmarkAndLocationList: Seq[(Bookmark, Location)] =bookmarks.map{ b => (b, id2loc(b.locationId)) }
関係モナドclass BookmarkRelation(b: Bookmark) {def toLocation: Monad[Location, Bookmark] =HasA.Monadic(b, new HasA[Bookmark, Location] { ... }) }implicit def bookmarkRel(b: Bookmark) =new BookmarkRelation(b)val bookmark: Bookmark = ... // 1 件の場合val location: Option[Location] = bookmark.toLocationval bookmarks: Seq[Bookmark] = ... // n 件の場合val locations: Seq[Location] = bookmarks.map(_.toLocation)
関係モナドclass BookmarkRelation(b: Bookmark) {def toLocation: Monad[Location, Bookmark] =HasA.Monadic(b, new HasA[Bookmark, Location] { ... }) }implicit def bookmarkRel(b: Bookmark) =new BookmarkRelation(b)val bookmark: Bookmark = ... // 1 件の場合val location: Option[Location] = bookmark.toLocationval bookmarks: Seq[Bookmark] = ... // n 件の場合val locations: Seq[Location] = bookmarks.map(_.toLocation)◮ toLocationの返り値はモナドのインスタンス
関係モナドclass BookmarkRelation(b: Bookmark) {def toLocation: Monad[Location, Bookmark] =HasA.Monadic(b, new HasA[Bookmark, Location] { ... }) }implicit def bookmarkRel(b: Bookmark) =new BookmarkRelation(b)val bookmark: Bookmark = ... // 1 件の場合val location: Option[Location] = bookmark.toLocationval bookmarks: Seq[Bookmark] = ... // n 件の場合val locations: Seq[Location] = bookmarks.map(_.toLocation)◮ toLocationの返り値はモナドのインスタンス◮ クエリはモナドから結果への暗黙変換で発生
関係モナドclass BookmarkRelation(b: Bookmark) {def toLocation: Monad[Location, Bookmark] =HasA.Monadic(b, new HasA[Bookmark, Location] { ... }) }implicit def bookmarkRel(b: Bookmark) =new BookmarkRelation(b)val bookmark: Bookmark = ... // 1 件の場合val location: Option[Location] = bookmark.toLocationval bookmarks: Seq[Bookmark] = ... // n 件の場合val locations: Seq[Location] = bookmarks.map(_.toLocation)◮ toLocationの返り値はモナドのインスタンス◮ クエリはモナドから結果への暗黙変換で発生◮ 関係の引き方はモナド生成時に指定
関係モナドモナドのパラメータ◮ 複数件の引き方のみを実装new HasA[Bookmark, Location] {def map(bookmarks: Seq[Bookmark]): Seq[Location] =locationLoader.findAll(bookmarks.map(_.locationId)) }暗黙変換◮ Seq[] を一気に変換して N+1 問題を解決implicit def run[R, Q](ms: Seq[Monad[R, Q]]): Seq[R] = ... // HasA.map を使った処理implicit def toResultOption[R, Q](m: Monad[R, Q]): Option[R] = run(Seq(m)).headOption
関係モナド元の要素と対応づける場合type JoinBookmarkLocation =Join[(Bookmark, Location), LocationId, Bookmark, Location]def withLocation = Join.Monadic(b, new JoinBookmarkLocation {def map(bs: Seq[Bookmark]): Seq[Location] = ...def leftKey(b: Bookmark): LocationId = b.locationIddef rightKey(l: Location): LocationId = l.iddef merge(b: Bookmark, l: Location) = (b, l)})val bookmarks: Seq[Bookmark] = ...val bookmarkAndLocationList: Seq[(Bookmark, Location)] =bookmarks.map(_.withLocation)◮ ID による紐づけは変換時にやってくれる
詳しくはOSS 化された実装◮ github.com/tarao/bullet-scala日本語での解説◮ bullet-scala: N+1 クエリ問題を回避する
CICICICICICICI
CIdocker で◮ 単一の.jar ファイルを生成◮ テストを実行◮ 開発用ホスト環境 (予定)◮ chrootして本番環境に?生成した.jar ファイル◮ テストに使用 (本番と同一バイナリ)◮ デプロイに使用
まとめ◮ はてなブックマークを作りなおし◮ Perl と Scala のハイブリッド◮ 薄いフレームワークを採用◮ Scala での DDD 実践方法を模索◮ docker でモダンな CI
WE ARE HIRING◮ Scala エンジニア 絶賛募集中◮ 東京 / 京都 どちらの勤務でも可

Recommended

PDF
Scalaで型クラス入門
KEY
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
PDF
はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化
PDF
あなたのScalaを爆速にする7つの方法(日本語版)
PPTX
Tagless Final DSL
PDF
Scala2.8への移行
PDF
ScalaMatsuri 2016
PDF
Thinking in Cats
PDF
Scalaで萌える関数型プログラミング[完全版]
 
PDF
これから Haskell を書くにあたって
PPT
Rpscala2011 0601
PDF
Phantom Type in Scala
PDF
今から始める Lens/Prism
PDF
Scala の関数型プログラミングを支える技術
PDF
なぜリアクティブは重要か #ScalaMatsuri
PDF
C++コミュニティーの中心でC++をDISる
PDF
197x 20090704 Scalaで並行プログラミング
PDF
これからのJavaScriptー関数型プログラミングとECMAScript6
PPTX
【java8 勉強会】 怖くない!ラムダ式, Stream API
PDF
rpscala35-scala2.9.0
PDF
JavaScript 講習会 #1
 
PDF
Why Reactive Matters #ScalaMatsuri
PPTX
Sns suite presentation
PDF
BOF1-Scala02.pdf
PPTX
LINQ 概要 + 結構便利な LINQ to XML
PDF
Frege, What a Non-strict Language
PDF
15分でざっくり分かるScala入門
PDF
Java SE 8 lambdaで変わる プログラミングスタイル
PDF
Kotlin Meets Data-Oriented Programming: Kotlinで実践する「データ指向プログラミング」
PDF
めんどくさくない Scala #kwkni_scala

More Related Content

PDF
Scalaで型クラス入門
KEY
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
PDF
はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化
PDF
あなたのScalaを爆速にする7つの方法(日本語版)
PPTX
Tagless Final DSL
PDF
Scala2.8への移行
PDF
ScalaMatsuri 2016
PDF
Thinking in Cats
Scalaで型クラス入門
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化
あなたのScalaを爆速にする7つの方法(日本語版)
Tagless Final DSL
Scala2.8への移行
ScalaMatsuri 2016
Thinking in Cats

What's hot

PDF
Scalaで萌える関数型プログラミング[完全版]
 
PDF
これから Haskell を書くにあたって
PPT
Rpscala2011 0601
PDF
Phantom Type in Scala
PDF
今から始める Lens/Prism
PDF
Scala の関数型プログラミングを支える技術
PDF
なぜリアクティブは重要か #ScalaMatsuri
PDF
C++コミュニティーの中心でC++をDISる
PDF
197x 20090704 Scalaで並行プログラミング
PDF
これからのJavaScriptー関数型プログラミングとECMAScript6
PPTX
【java8 勉強会】 怖くない!ラムダ式, Stream API
PDF
rpscala35-scala2.9.0
PDF
JavaScript 講習会 #1
 
PDF
Why Reactive Matters #ScalaMatsuri
PPTX
Sns suite presentation
PDF
BOF1-Scala02.pdf
PPTX
LINQ 概要 + 結構便利な LINQ to XML
PDF
Frege, What a Non-strict Language
PDF
15分でざっくり分かるScala入門
PDF
Java SE 8 lambdaで変わる プログラミングスタイル
Scalaで萌える関数型プログラミング[完全版]
 
これから Haskell を書くにあたって
Rpscala2011 0601
Phantom Type in Scala
今から始める Lens/Prism
Scala の関数型プログラミングを支える技術
なぜリアクティブは重要か #ScalaMatsuri
C++コミュニティーの中心でC++をDISる
197x 20090704 Scalaで並行プログラミング
これからのJavaScriptー関数型プログラミングとECMAScript6
【java8 勉強会】 怖くない!ラムダ式, Stream API
rpscala35-scala2.9.0
JavaScript 講習会 #1
 
Why Reactive Matters #ScalaMatsuri
Sns suite presentation
BOF1-Scala02.pdf
LINQ 概要 + 結構便利な LINQ to XML
Frege, What a Non-strict Language
15分でざっくり分かるScala入門
Java SE 8 lambdaで変わる プログラミングスタイル

Similar to はてなブックマーク in Scala

PDF
Kotlin Meets Data-Oriented Programming: Kotlinで実践する「データ指向プログラミング」
PDF
めんどくさくない Scala #kwkni_scala
PDF
scala+liftで遊ぼう
 
PPTX
明日から業務で使うScala
PDF
実装(2) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第31回】
PDF
セマンテックウェブとRDFDB
PPTX
Apache Spark チュートリアル
PDF
Scala with DDD
PPTX
Play2 scalaを2年やって学んだこと
PDF
Scalaプログラミング・マニアックス
PDF
Trait in scala
PDF
Scala2.8への移行
PPTX
Rawlerフレームワーク(全体)
PDF
プログラミング言語Scala
PPTX
Reladomo in Scala #scala_ks
PDF
設計/ドメイン設計(5) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第27回】
PDF
Refactoring point of Kotlin application
PDF
Scalaでプログラムを作りました
PDF
クラウド・アプリケーション・モデリングへのアプローチ
PPTX
Struggle against crossdomain data complexity in Recruit Group
Kotlin Meets Data-Oriented Programming: Kotlinで実践する「データ指向プログラミング」
めんどくさくない Scala #kwkni_scala
scala+liftで遊ぼう
 
明日から業務で使うScala
実装(2) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第31回】
セマンテックウェブとRDFDB
Apache Spark チュートリアル
Scala with DDD
Play2 scalaを2年やって学んだこと
Scalaプログラミング・マニアックス
Trait in scala
Scala2.8への移行
Rawlerフレームワーク(全体)
プログラミング言語Scala
Reladomo in Scala #scala_ks
設計/ドメイン設計(5) 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第27回】
Refactoring point of Kotlin application
Scalaでプログラムを作りました
クラウド・アプリケーション・モデリングへのアプローチ
Struggle against crossdomain data complexity in Recruit Group

More from Lintaro Ina

PDF
HTMLからの本文抽出
PDF
Emacs上のターミナルを最強に
PDF
論理と計算のしくみ 5.3 型付きλ計算 (前半)
PDF
『BrandSafe はてな』のアドベリフィケーションのしくみ
PDF
Gradual Typing for Generics
PDF
『BrandSafe はてな』のアドベリフィケーションのしくみ
HTMLからの本文抽出
Emacs上のターミナルを最強に
論理と計算のしくみ 5.3 型付きλ計算 (前半)
『BrandSafe はてな』のアドベリフィケーションのしくみ
Gradual Typing for Generics
『BrandSafe はてな』のアドベリフィケーションのしくみ

はてなブックマーク in Scala


[8]ページ先頭

©2009-2025 Movatter.jp