SlideShare a Scribd company logo
1 of 95
Reladomo in Scala
株式会社FOLIO 伊藤博志
グッドフロー・テクノロジーズ 瀬良和弘
Scala関西 Summit 2017.9.9
Reladomo is an open source software Licensed under Apache 2.0 License,
Copyright 2016 Goldman Sachs, Its name may be a trademark of its owner.
X
1
Agenda
1. 自己紹介
2. 株式会社FOLIOでの開発とReladomo
3. scala-reladomoの紹介
4. バイテンポラルモデル
5. scala-reladomoの… OSS公開!!!!
hashtag: #scala_ks_main
2
自己紹介
Head of Engineering @ FOLIO
伊藤 博志
2015年末からEclipse Collections共同プロジェクトリード兼コミッター
をしています。
Reladomo/OpenJDKにもちょっとだけコントリビュートしたりしています。
2017年、Scalaはじめました。
JavaOne、Java Day Tokyo、JJUG CCC 登壇
瀬良 和弘
Goodflow Technologies
ScalikeJDBC や Skinny Framework などの Scala OSS を開発してい
ます。
グッドフロー・テクノロジーズ (http://good-flow.com/)の屋号で、技術
支援を承ったり、Scala の普及活動も行っています。
hashtag: #scala_ks_main
3
Reladomoとはなにか
hashtag: #scala_ks_main
4
を説明する前に
hashtag: #scala_ks_main
5
Reladomoに解決してほしい問題
の例を挙げてみます
hashtag: #scala_ks_main
6
株式会社FOLIOにおける開発
https://folio-sec.com/
hashtag: #scala_ks_main
7
証券システム開発の難しさ
hashtag: #scala_ks_main
8
いきなり難しい例を出します
hashtag: #scala_ks_main
9
たとえば株式分割等のコーポレートアクションの表現
1株A社 1株
10,000円
1株1株1株A社 1株
2,000円
1株 5株
X月Y日
コーポレートアクション
1:5の株式分割
X月Y日を境に起きる
10
たとえば株式分割等のコーポレートアクションの表現
1:5の株式分割
システム上のお客様の保有株数の変化
ある特定の日時X月Y日 S時T分に反映される
A社 10株 A社 50株
X月Y日 S時T分
バッチジョブによる株数変更
11
たとえば株式分割等のコーポレートアクションの表現
A社株
10,000円
A社株
2,000円
X月Y日 A時B分
DBに反映
1:5の株式分割
データソースベンダーから受け取る株価の変化
ある特定の日時X月Y日 A時B分に反映される
コーポレートアクション
12
たとえば株式分割等のコーポレートアクションの表現
システム反映のタイミングの違いで起きうる計算結果のズレに
どう対処すれば良いのか?
10株 50株
10,000円 2,000円
保有株数
株価
資産評価額
🤔
10株 x 10,000円
= 100,000円
50株 x 2,000円
= 100,000円
50株
x
10,000円
= 500,000円
X月Y日 S時T分 X月Y日 A時B分
13
RDBMSで履歴・有効期間データを扱う
hashtag: #scala_ks_main
14
RDBMSで履歴データを扱う
単純なシナリオを考えてみましょう
シンプルな人事システム。扱う情報は姓名のみ。
 4月1日に「鈴木花子」さん入社。3月1日にシステムに登録
 6月6日に結婚し、姓が「斎藤」に変更。同日システム上に
間違えて「斉藤」と登録
 6月8日にシステム上で修正(斉藤=>斎藤) 。事実としては
6月6日づけで直したい
 12月1日、退職にともない同日にシステム上で情報を無効化
hashtag: #scala_ks_main
15
RDBMSで履歴データを扱う
 シナリオをよく観察すると、2種類の履歴が存在
 2種類の時間表現なのでbi-temporal:バイテンポラル
3/1 4/1 6/6 6/8 12/1
鈴木花子
事実情報の
履歴
システムに
反映された
履歴
入社🎉
「鈴木花子」を
システムに登録
結婚して
斎藤になる👰
名字を
「斉藤」に変更
名字を
「斎藤」に変更
退職†
データを無効化
このような、履歴や有効期間情報を扱えるデータモデルを
テンポラルデータモデル、上記のような2種類の時間表現が
可能なモデルをバイテンポラルデータモデルと呼ぶ
hashtag: #scala_ks_main
16
バイテンポラルモデル
詳しくはJJUG CCCのプレゼン資料をごらんください
hashtag: #scala_ks_main
17
バイテンポラルデータモデルを使うと
hashtag: #scala_ks_main
18
トランザクション時間表現
たとえシステム反映のタイミングが違ったとしても
10株 50株
10,000円 2,000円
保有株数
株価
X月Y日 S時T分 X月Y日 A時B分
hashtag: #scala_ks_main
19
有効時間表現
ビジネス上で有効な時間を合わせることができる
10株 50株
10,000円 2,000円
保有株数
株価
資産評価額
10株 x 10,000円
= 100,000円
50株 x 2,000円
= 100,000円
X月Y日 0時0分
🤗
hashtag: #scala_ks_main
20
証券会社のバックエンド機能開発の難しさ
さまざまな側面で「履歴」や「有効期間」の表現が必要になる
 口座開設中の状態遷移の表現
 顧客情報の変更履歴の表現
 残高の履歴の表現
 株式分割・併合等のコーポレート・アクションが起きた際
の株価・株数変更における有効期間表現
 etc.
21
そこでReladomo
hashtag: #scala_ks_main
22
Reladomoとは
https://github.com/goldmansachs/reladomo
 ゴールドマン・サックス社が2016年9月にGitHubに
OSSとして公開したJava ORMフレームワーク
 Apache License 2.0
 ORMフレームワークであり、オブジェクト指向の徹底
 xmlからコード/DDLの自動生成
 バイテンポラルデータモデルをネイティブサポート
 強力に型付けられたクエリー言語(SQLは書かない)
 ユニットテストのフルサポート
 etc.
hashtag: #scala_ks_main
23
Reladomoの基本
Javaにおける基本的な使用法については
JJUGナイトセミナーのプレゼン資料をごらんください
hashtag: #scala_ks_main
24
株式会社FOLIOにおける開発
履歴や有効時間の概念が必要となる機能要件
 口座開設中の状態遷移の表現
 顧客情報の変更履歴
 残高の履歴の表現
 株式分割・併合等のコーポレート・アクションが起きた
際の株価・株数変更における有効期間表現
 etc.
技術要件
 Scala/Finatra/Finagleによるマイクロサービス構成
 現行のquillによるデータアクセスを置き換えたい
 Scalaから履歴や有効期間の自然なコード記述を実現した
い
hashtag: #scala_ks_main
25
ReladomoをScalaから自然に扱いたい
hashtag: #scala_ks_main
26
だから
hashtag: #scala_ks_main
27
reladomo-scalaを開発しました!
hashtag: #scala_ks_main
28
reladomo-scalaの紹介
hashtag: #scala_ks_main
29
reladomo-scala とは何か
以下の 2 つを提供する OSS ライブラリ
●Reladomo のコード生成に対応する sbt プラグイン
●Java コード生成
●Scala コード生成
●DDL 生成
●生成されたコードが依存する共通モジュール
●Reladomo の Scala ラッパー
●Twitter Future に対応した Scala ラッパー
hashtag: #scala_ks_main
30
lazy val root = (project in file(“.")).
settings(
libraryDependencies += "com.folio-sec" %% "reladomo-scala-common" % v
).enablePlugins(ReladomoPlugin)
addSbtPlugin("com.folio-sec" % "sbt-reladomo-plugin" % v)
reladomo-scala の使い方
●Reladomo オブジェクト定義ファイル
●コンパイル時に必要
●ランタイムコンフィグファイル
●実行時、DB 接続情報とオブジェクトのキャッシュ設定
hashtag: #scala_ks_main
31
作業フロー
●sbt compile 時
1. src/main/resources/reladomo/config 配下の
XML ファイルが scan される
2. target/scala-2.12/src_managed/main に Java
、Scala ソースコードを生成
3. src/main/java、src/main/scala にも編集可能な
コードを生成
●XML を編集して再コンパイルして、生成されたコードを
使って開発する
hashtag: #scala_ks_main
32
Inputファイル例( Customer.xml )
<MithraObject objectType="transactional"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="reladomoobject.xsd">
<PackageName>com.folio_sec.example.domain.simpleban</PackageName>
<ClassName>Customer</ClassName>
<DefaultTable>CUSTOMER</DefaultTable>
<Attribute javaType="int" name=”customerId" columnName=”CUSTOMER_ID"
primaryKey="true" primaryKeyGeneratorStrategy="Max"/>
<Attribute javaType="String" name=”name" columnName=”NAME"
nullable="false" maxLength="64"/>
</MithraObject>
hashtag: #scala_ks_main
33
ディレクトリ構成
├── build.sbt
├── project
│ └── plugins.sbt
├── src
│ ├── main
│ │ ├── java
│ │ ├── resources
│ │ │ └── reladomo
│ │ │ └── config
│ │ │ ├── Customer.xml
│ │ │ ├── CustomerAccount.xml
│ │ │ └── ReladomoClassList.xml
│ │ └── scala
│ └── test
└── target
└── scala-2.12
└── src_managed
└── main
sbtファイル
ファイル生成のための
inputファイル
hashtag: #scala_ks_main
34
ディレクトリ構成
├── build.sbt
├── project
│ └── plugins.sbt
├── src
│ ├── main
│ │ ├── java
│ │ ├── resources
│ │ │ └── reladomo
│ │ │ └── config
│ │ │ ├── Customer.xml
│ │ │ ├── CustomerAccount.xml
│ │ │ └── ReladomoClassList.xml
│ │ └── scala
│ └── test
└── target
└── scala-2.12
└── src_managed
└── main
ソースファイル
が生成される
hashtag: #scala_ks_main
35
Reladomoの検索
hashtag: #scala_ks_main
36
Finder API
Finderクラスを用いてOperationを生成
–型安全な検索条件のAPIを提供
SQLは一切書かない
–検索条件: Operation - Finder APIから作成
–1件検索:Finder.findOne(Operation)
–複数検索:Finder.findMany(Operation)
–Aggregationのサポート(max、sum等)
hashtag: #scala_ks_main
37
Finder API:一件検索
Operation findTaroOp =
PersonFinder.firstName().eq(“太郎");
Person taro =
PersonFinder.findOne(findTaroOp);
Finder APIを用いてOperationを作成
Finder.findOne()で一件検索
結果はEntityオブジェクトで取得
38
val taro: Option[Person] =
PersonFinder.findOne(findTaroOp)
val taro: Option[Person] =
PersonFinder.findOneWith(_.firstName.eq(“太郎”))
Finder API:一件検索
val findTaroOp =
PersonFinder.firstName.eq(“太郎")
Finder APIを用いてOperationを作成
Finder.findOne()で一件検索
結果はEntityオブジェクトで取得
39
Finder API:複数検索
Operation findAllOp = PersonFinder.all();
PersonList people =
PersonFinder.findMany(findAllOp);
Finder APIを用いてOperationを作成
Finder.findMany()で複数検索
結果はListオブジェクトで取得
40
Finder API:複数検索
val findAllOp = PersonFinder.all
val people = PersonFinder.findManyWith(_.all)
Finder APIを用いてOperationを作成
Finder.findMany()で複数検索
結果はListオブジェクトで取得
41
Finder API:Operationの例1
Operation op1 = PersonFinder.firstName().eq("大輔");
// SQL: WHERE first_name = '大輔’
Operation op2 = PersonFinder.lastName().endsWith("藤");
// SQL: WHERE last_name LIKE '%藤’
Operation op1OrOp2 = op1.or(op2);
// SQL: WHERE (( first_name = '大輔') OR ( last_name LIKE '%藤'))
Operation op1AndOp2 = op1.and(op2);
// SQL: WHERE (( first_name = '大輔') AND ( last_name LIKE '%藤'))
42
Finder API:Operationの例1
val op1 = PersonFinder.firstName.eq("大輔")
// SQL: WHERE first_name = '大輔’
val op2 = PersonFinder.lastName.endsWith("藤")
// SQL: WHERE last_name LIKE '%藤’
val op1OrOp2 = op1 || op2
// SQL: WHERE (( first_name = '大輔') OR ( last_name LIKE '%藤'))
val op1AndOp2 = op1 && op2
// SQL: WHERE (( first_name = '大輔') AND ( last_name LIKE '%藤'))
// Scalaでは and/or 条件が非常に柔軟に書ける!
Finder.findManyWith { q => (q.firstName.eq(”XXX") ||
q.firstName.eq(”YYY")) && (…)) }
43
Operation op3 =
PersonFinder.age().in(IntHashSet.newSetWith(22, 24, 30));
// SQL: WHERE age in (22, 24, 30)
Operation op4 =
PersonFinder.age().notIn(IntHashSet.newSetWith(22, 25));
// SQL: WHERE age in (22, 25)
Operation op5 =
PersonFinder.age().greaterThan(25);
// SQL: WHERE age > 25
その他複雑なクエリを型安全に記述することが可能
Finder API:Operationの例2
44
val op3 = PersonFinder.age.in(Set(22, 24, 30))
// SQL: WHERE age in (22, 24, 30)
val op4 = PersonFinder.age.notIn(Set(22, 25))
// SQL: WHERE age in (22, 25)
val op5 = PersonFinder.age.greaterThan(25)
// SQL: WHERE age > 25
その他複雑なクエリを型安全に記述することが可能
Finder API:Operationの例2
45
Reladomoのキャッシュ
hashtag: #scala_ks_main
46
ReIadomoのキャッシュ
●Reladomoは複数のキャッシュ戦略を持つ
–Partial Cache
–Full Cache
–None
●ランタイムの設定でエンティティごとにキャッシュ
戦略を選択可能
●クエリーキャッシュとオブジェクトキャッシュ
●キャッシュ機構は高度に最適化されており、データ
ベースへのアクセスを最小に保つことができる
hashtag: #scala_ks_main
47
val taro = PersonFinder.findOne(_.firstName.eq("太郎"))
val op1 = PersonFinder.firstName.eq("大輔")
val op2 = PersonFinder.lastName.endsWith("藤")
val people2 = PersonFinder.findMany(op1 || op2))
people2.forceResolve()
val op3 = PersonFinder.age.greaterThan(25)
val people3 = PersonFinder.findMany(op3)
people3.forceResolve()
3種類の条件の違うクエリーは直接DBを叩く
ReIadomoのキャッシュ
48
2017-07-23 18:02:06:881 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person -
connection:2005169944 find with: select t0.person_id,t0.first_name,t0.last_name,t0.age from person t0
where t0.first_name = '太郎’
2017-07-23 18:02:06:891 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - retrieved 1 objects,
83.0 ms per
2017-07-23 18:02:06:992 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person -
connection:2005169944 find with: select t0.person_id,t0.first_name,t0.last_name,t0.age from person t0
where (( t0.first_name = '大輔') or ( t0.last_name like '%藤'))
2017-07-23 18:02:06:994 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - retrieved 3 objects,
1.3333333333333333 ms per
2017-07-23 18:02:06:997 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person -
connection:2005169944 find with: select t0.person_id,t0.first_name,t0.last_name,t0.age from person t0
where t0.age > 25
2017-07-23 18:02:07:005 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - retrieved 1 objects,
8.0 ms per
ReIadomoのキャッシュ
3回のDBアクセス
hashtag: #scala_ks_main
49
val people = PersonFinder.findManyWith(_.all)
val findTaroOp = PersonFinder.firstName.eq(“太郎")
… 前ページと同じ3つのクエリー
前ページと同じ3種類のクエリーの直前に全選択の
クエリーを走らせると…
ReIadomoのキャッシュ
50
2017-07-23 19:34:04:415 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person -
connection:112049309 find with: select t0.person_id,t0.first_name,t0.last_name,t0.age from person
t02017-07-23 19:34:04:458 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - retrieved 4
objects, 25.5 ms per
ReIadomoのキャッシュ
1回のDBアクセスで全選択
●DBへのIOは全選択クエリーの1回のみ
●その後のクエリーはキャッシュから取得
hashtag: #scala_ks_main
51
Reladomoのトランザクション処理
hashtag: #scala_ks_main
52
Reladomoのトランザクション処理
トランザクション内で行う必要のある処理に関しては
ラムダ式内に記述しexecuteTransactionalCommand()
にわたす。
以下、例によってはこのトランザクションのコード
を省略している。
MithraManagerProvider.getMithraManager().executeTransactionalCommand(tx -> {
//検索・挿入・更新・削除処理の記述
return someObject;
});
53
Reladomoのトランザクション処理
Reladomo は ThreadLocal に MithraTransaction がいないと
実行時例外になる場合がある(ID 自動採番など)
reladomo-scala は更新系処理は全て implicit parameter を
要求するようにしてコンパイル時に気づけるようにした。
TranscationProvider.withTransaction { implicit tx =>
//検索・挿入・更新・削除処理の記述
// reladomo-scala では return null; する必要はない
});
54
Reladomoの挿入処理
hashtag: #scala_ks_main
55
Reladomoの挿入処理:単一挿入(Scala)
val jiro = NewPerson("二郎", "山田", 45)
jiro.insert()
Entityインスタンスを作成
Insert()メソッドで挿入
56
NewPersonList(Seq(
NewPerson(“二郎”, "山田", 45),
NewPerson("さくら", "鈴木", 28)
)).insertAll()
Reladomoの挿入処理:バッチ挿入
Listインスタンスを作成
57
Reladomoの更新処理
hashtag: #scala_ks_main
58
val tanaka = PersonFinder.findOneWith(_.lastName.eq("田中"))
tanaka.copy(age = 25).update()
Reladomoの更新処理:単一更新
Entityインスタンスを検索
setter で更新しない update/delete 呼ぶまでは DB
に反映はしない
バイテンポラルの場合も有効時間の指定以外はほぼ
同じコードで表現できる(後述)
59
Reladomoの更新処理:複数更新
複数検索でListオブジェクトを取得
val people = PersonFinder.findManyWith(_.all)
people.withAge(20).updateAll()
2017-07-23 21:45:08:489 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - multi update of 6
objects with: update person set age = ? where person_id in (?...)
2017-07-23 21:45:08:489 [main] DEBUG com.gs.fw.common.mithra.batch.sqllogs.Person - multi updating
with: update person set age = 20 where person_id in (0,1,2,3,4,5)
60
Reladomoの更新処理:バッチ更新
Entityインスタンスを検索
トランザクション内での複数更新はバッチ更新される
val tanaka = PersonFinder.findOneWith(_.lastName.eq(“田中”))
val sato = PersonFinder.findOneWith(_.lastName.eq(“佐藤”))
TransactionProvider.withTransaction { implicit tx =>
tanaka.copy(age = 25).update()
sato.copy(age = 23).update()
}
2017-07-23 21:38:39:403 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - batch update of 2
objects with: update person set age = ? where person_id = ?
2017-07-23 21:38:39:404 [main] DEBUG com.gs.fw.common.mithra.batch.sqllogs.Person - batch
updating with: update person set age = 25 where person_id = 0
2017-07-23 21:38:39:405 [main] DEBUG com.gs.fw.common.mithra.batch.sqllogs.Person - batch
updating with: update person set age = 23 where person_id = 1
61
Reladomoの削除処理
hashtag: #scala_ks_main
62
Reladomoの削除処理:単一削除
Entityインスタンスを検索
delete()メソッドで削除
val tanaka = PersonFinder.findOneWith(
_.lastName.eq(“田中”))
tanaka.delete()
63
Reladomoの削除処理:複数削除
複数検索でListオブジェクトを取得
Listに対してdeleteAll()メソッドで複数削除
val people = PersonFinder.findManyWith(
_.lastName.in(Set(“田中”, “佐藤"))
people.deleteAll()
64
Reladomoの関連
hashtag: #scala_ks_main
65
Reladomoの関連:サンプルモデル hashtag: #scala_ks_main
66
Reladomoの関連:Person.xml
<Relationship name="pets"
relatedObject="Pet"
cardinality="one-to-many"
relatedIsDependent="true"
reverseRelationshipName="owner">
this.personId = Pet.ownerId
</Relationship>
Person PetPetPet
pets
owner
hashtag: #scala_ks_main
67
Reladomoの関連:Pet.xml
<Relationship name="petType"
relatedObject="PetType"
cardinality="many-to-one">
this.petTypeId = PetType.petTypeId
</Relationship>
Pet PetTypepetType
hashtag: #scala_ks_main
68
Reladomoの関連:Finderによる柔軟な検索1
//犬を飼っている飼い主を取得
val op =
PersonFinder.pets.petTypeId.eq(PetType.DOG)
val dogOwner = PersonFinder.findOneWith(
_.pets.petTypeId.eq(PetType.DOG))
テーブル間のjoinを柔軟に記述
通常の一件検索と同様
69
Reladomoの関連:Finderによる柔軟な検索1
2017-07-24 21:51:55:924 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person -
connection:1954406292 find with: select t0.person_id,t0.first_name,t0.last_name,t0.age from person t0
inner join (select distinct t1.owner_id c0 from pet t1 where t1.pet_type_id = 0) as d1 on t0.person_id =
d1.c0
2017-07-24 21:51:55:977 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - retrieved 1 objects,
347.0 ms per
生成されるSQL
70
//佐藤さんが飼っているペットを取得
val op =
PetFinder.owner.lastName.eq("佐藤")
val satoPets = PetFinder.findManyWith(_.lastName.eq(“
佐藤"))
通常の複数検索と同様
Reladomoの関連:Finderによる柔軟な検索2
71
Reladomoの関連:Finderによる柔軟な検索2
2017-07-25 07:09:31:305 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Pet - connection:708533063
find with: select t0.pet_id,t0.name,t0.owner_id,t0.age,t0.pet_type_id from pet t0 inner join person t1 on
t0.owner_id = t1.person_id where t1.last_name = '佐藤’
2017-07-25 07:09:31:316 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Pet - retrieved 2 objects, 49.5
ms per
生成されるSQL
72
Reladomoの関連:deepFetch
Relationshipを解決する際のN+1問題を避けるための機構
//ペット飼っている人を取得
val op = PersonFinder.pets.exists()
val petOwners = PersonFinder.findMany(op)
petOwners.deepFetch(PersonFinder.pets)
petOwners.deepFetch(PersonFinder.pets.petType)
petOwners.foreach { petOwner =>
petOwner.getPets.forEach { pet =>
println(
petOwner.lastName + "さんは" +
pet.name + "という名の" +
pet.petType.petType + "を飼っています")
}
});
取得したい関連を
deepFetch指定
73
Reladomoの関連:deepFetch
deepFetchを使わない場合に発行されるSQL
2017-07-25 07:23:05:473 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - connection:576020159 find with:
select t0.person_id,t0.first_name,t0.last_name,t0.age from person t0 inner join (select distinct t1.owner_id c0 from pet
t1) as d1 on t0.person_id = d1.c
02017-07-25 07:23:05:493 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - retrieved 2 objects, 51.0 ms per
2017-07-25 07:23:05:604 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Pet - connection:576020159 find with: select
t0.pet_id,t0.name,t0.owner_id,t0.age,t0.pet_type_id from pet t0 where t0.owner_id = 1
2017-07-25 07:23:05:608 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Pet - retrieved 2 objects, 6.0 ms per2017-
07-25 07:23:05:645 [main] DEBUG com.gs.fw.common.mithra.sqllogs.PetType - connection:576020159 find with: select
t0.pet_type_id,t0.pet_type from pet_type t0 where t0.pet_type_id = 0
2017-07-25 07:23:05:647 [main] DEBUG com.gs.fw.common.mithra.sqllogs.PetType - retrieved 1 objects, 3.0 ms
per2017-07-25 07:23:05:658 [main] DEBUG com.gs.fw.common.mithra.sqllogs.PetType - connection:576020159 find
with: select t0.pet_type_id,t0.pet_type from pet_type t0 where t0.pet_type_id = 3
2017-07-25 07:23:05:658 [main] DEBUG com.gs.fw.common.mithra.sqllogs.PetType - retrieved 1 objects, 2.0 ms per
2017-07-25 07:23:05:659 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Pet - connection:576020159 find with: select
t0.pet_id,t0.name,t0.owner_id,t0.age,t0.pet_type_id from pet t0 where t0.owner_id = 2
2017-07-25 07:23:05:660 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Pet - retrieved 2 objects, 0.5 ms per
2017-07-25 07:23:05:661 [main] DEBUG com.gs.fw.common.mithra.sqllogs.PetType - connection:576020159 find with:
select t0.pet_type_id,t0.pet_type from pet_type t0 where t0.pet_type_id = 1
2017-07-25 07:23:05:662 [main] DEBUG com.gs.fw.common.mithra.sqllogs.PetType - retrieved 1 objects, 2.0 ms per
2017-07-25 07:23:05:663 [main] DEBUG com.gs.fw.common.mithra.sqllogs.PetType - connection:576020159 find with:
select t0.pet_type_id,t0.pet_type from pet_type t0 where t0.pet_type_id = 2
2017-07-25 07:23:05:664 [main] DEBUG com.gs.fw.common.mithra.sqllogs.PetType - retrieved 1 objects, 1.0 ms per
hashtag: #scala_ks_main
74
Reladomoの関連:deepFetch
deepFetchを使った場合に発行されるSQL
2017-07-25 07:27:16:540 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - connection:587153993 find with:
select t0.person_id,t0.first_name,t0.last_name,t0.age from person t0 inner join (select distinct t1.owner_id c0 from pet
t1) as d1 on t0.person_id = d1.c0
2017-07-25 07:27:16:564 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Person - retrieved 2 objects, 58.0 ms per
2017-07-25 07:27:16:650 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Pet - connection:587153993 find with: select
t0.pet_id,t0.name,t0.owner_id,t0.age,t0.pet_type_id from pet t0 where t0.owner_id in ( 1,2)
2017-07-25 07:27:16:652 [main] DEBUG com.gs.fw.common.mithra.sqllogs.Pet - retrieved 4 objects, 1.75 ms per
2017-07-25 07:27:16:661 [main] DEBUG com.gs.fw.common.mithra.sqllogs.PetType - connection:587153993 find with:
select t0.pet_type_id,t0.pet_type from pet_type t0 where t0.pet_type_id in ( 0,1,2,3)
2017-07-25 07:27:16:666 [main] DEBUG com.gs.fw.common.mithra.sqllogs.PetType - retrieved 4 objects, 1.25 ms per
hashtag: #scala_ks_main
75
reladomo-scalaのリリースポリシー
https://groups.google.com/forum/#!topic/finaglers/AaQsOXYm664
互換性のあるバージョンごとにビルド
–Reladomo version: 16.5.X
–twitter-util-core: 7.1.X
hashtag: #scala_ks_main
76
reladomo-scala ToDo
reverseRelationshipNameのサポート
Unit test サポート
Multi-Threaded matcher loaderのサポート
生成されたドメインクラスの拡張サポート
Business date指定もれのコンパイル時検知
hashtag: #scala_ks_main
77
バイテンポラルデータモデル
hashtag: #scala_ks_main
78
RDBMSで履歴データを扱う
単純なシナリオを考えてみましょう
シンプルな人事システム。扱う情報は姓名のみ。
 4月1日に「鈴木花子」さん入社。3月1日にシステムに登録
 6月6日に結婚し、姓が「斎藤」に変更。同日システム上に
間違えて「斉藤」と登録
 6月8日にシステム上で修正(斉藤=>斎藤) 。事実としては
6月6日づけで直したい
 12月1日、退職にともない同日にシステム上で情報を無効化
hashtag: #scala_ks_main
79
RDBMSで履歴データを扱う
 シナリオをよく観察すると、2種類の履歴が存在
 2種類の時間表現なのでbi-temporal:バイテンポラル
3/1 4/1 6/6 6/8 12/1
鈴木花子
事実情報の
履歴
システムに
反映された
履歴
入社🎉
「鈴木花子」を
システムに登録
結婚して
斎藤になる👰
名字を
「斉藤」に変更
名字を
「斎藤」に変更
退職†
データを無効化
hashtag: #scala_ks_main
80
バイテンポラルデータモデル
姓 名 FROM THRU IN OUT
鈴木 花子 2017/4/1 9999/12/1 2017/3/1 9999/12/1
 4月1日に「鈴木花子」さん入社。3月1日にシステムに登録
鈴木さん入社!
4月1日に入社したことも
わかるし、3月1日にシス
テムに反映されたこともわ
かる!
hashtag: #scala_ks_main
81
バイテンポラルデータモデル
姓 名 FROM THRU IN OUT
鈴木 花子 2017/4/1 9999/12/1 2017/3/1 2017/6/6
鈴木 花子 2017/4/1 2017/6/6 2017/6/6 9999/12/1
斉藤 花子 2017/6/6 9999/12/1 2017/6/6 9999/12/1
 6月6日に結婚し、姓が「斎藤」に変更。同日システム
上に間違えて「斉藤」と登録
最初の行が「システム上」無効になり、新し
い「事実」が2つの期間にわたって挿入されて
いるね。
hashtag: #scala_ks_main
82
バイテンポラルデータモデル
姓 名 FROM THRU IN OUT
鈴木 花子 2017/4/1 9999/12/1 2017/3/1 2017/6/6
鈴木 花子 2017/4/1 2017/6/6 2017/6/6 9999/12/1
斉藤 花子 2017/6/6 9999/12/1 2017/6/6 2017/6/8
斎藤 花子 2017/6/6 9999/12/1 2017/6/8 9999/12/1
 名字の漢字が間違っており、6月8日にシステム上で修正
(斉藤=>斎藤)
間違えた行が「システム上」無効になり、正しい
「事実」が挿入されているね。
3つ目の行は「斉藤」という間違った事実が
「システム上有効だった」期間が6/6から6/8の
間存在するという情報を表しているよ。
hashtag: #scala_ks_main
83
バイテンポラルデータモデル
姓 名 FROM THRU IN OUT
鈴木 花子 2017/4/1 9999/12/1 2017/3/1 2017/6/6
鈴木 花子 2017/4/1 2017/6/6 2017/6/6 9999/12/1
斉藤 花子 2017/6/6 9999/12/1 2017/6/6 2017/6/8
斎藤 花子 2017/6/6 9999/12/1 2017/6/8 2017/12/1
斎藤 花子 2017/6/6 2017/12/1 2017/12/1 9999/12/1
 12月1日、退職にともない同日に人事情報をシステム上
で無効化
無事、事実情報(入社、姓変更、退社)と変
更履歴がすべて記録されました!
hashtag: #scala_ks_main
84
<MithraObject objectType=“transactional”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:noNamespaceSchemaLocation=“reladomoobject.xsd”>
<PackageName>sample.domain</PackageName>
<ClassName>Employee</ClassName>
<DefaultTable>EMPLOYEE</DefaultTable>
<AsOfAttribute name=“processingDate” fromColumnName=“IN_Z” toColumnName=“OUT_Z”
toIsInclusive=“false”
isProcessingDate=“true”
timezoneConversion=“none”
infinityDate=“[com.gs.fw.common.mithra.util.DefaultInfinityTimestamp.getDefaultInfinity()]”
defaultIfNotSpecified=“[com.gs.fw.common.mithra.util.DefaultInfinityTimestamp.getDefaultInfinity()]”
/>
<AsOfAttribute name=“businessDate” fromColumnName=“FROM_Z” toColumnName=“THRU_Z”
toIsInclusive=“false”
isProcessingDate=“false”
timezoneConversion=“none”
infinityDate=“[com.gs.fw.common.mithra.util.DefaultInfinityTimestamp.getDefaultInfinity()]”
futureExpiringRowsExist=“true”
/>
・・・省略・・・
</MithraObject>
バイテンポラルを使用する際の設定例 hashtag: #scala_ks_main
トランザクション時間
有効時間
85
val saito = EmployeeFinder.findOneWith { q =>
q.lastName.eq("斉藤") && q.businessDate.eq(now())
}
saito.copy(lastName ="斎藤”).update()
バイテンポラルのケースでの単一更新例
有効時間の指定
通常の場合と同様にupdateを呼ぶだけで、
データモデル上のIN/OUT/THRU/FROMを自動で更新・挿入
86
バイテンポラルモデル(再掲)
詳しくはJJUG CCCのプレゼン資料をごらんください
hashtag: #scala_ks_main
87
reladomo-scalaのOSS公開!
hashtag: #scala_ks_main
88
https://github.com/folio-sec/reladomo-scala/
リアルタイムに公開します🤗
reladomo-scalaのOSS公開! hashtag: #scala_ks_main
89
株式会社FOLIOでの導入事例
 Dealing Engineのポジション履歴サービスのデータアクセス
のreladomo-scala導入
今後の株式会社FOLIOでの導入予定
 口座開設中の状態遷移の表現
 顧客情報の変更履歴
 残高の履歴の表現
 株式分割・併合等のコーポレート・アクションが起きた際の
株価・株数変更における有効期間表現
 etc.
reladomo-scala の導入事例 hashtag: #scala_ks_main
90
Reladomoを学ぶには
つづきはReladomo Kata / Reladomo Tourで
 Reladomo Kata GitHub (Reladomo チュートリアル)
 Guided Tour of Reladomo
Reladomo Kataは、JUnit上でテストをパスしながら学べる
トレーニング教材
Javaで試してみたい方はKata内のmini-kataで手を動かして
試してみることをおススメします
91
さらに reladomo-scala を学ぶには
giter8 templateで遊んで見てください!
(こちらもセッション中に公開されます)
https://github.com/folio-sec/reladomo-first-example.g8/
# sbt new folio-sec/reladomo-first-example.g8
92
株式会社FOLIO
https://www.wantedly.com/projects/151883
Scala エンジニア募集中!
hashtag: #scala_ks_main
93
APPENDIX
94
リンク集
 reladomo-scala
 reladomo-scala giter8 template
 データ履歴管理のためのテンポラルデータモデルと
Reladomoの紹介
 Reladomo入門
 Reladomo GitHub
 Reladomo Kata GitHub (Reladomo チュートリアル)
 Guided Tour of Reladomo
 Reladomo Documentations

More Related Content

What's hot

ステップ・バイ・ステップで学ぶラムダ式・Stream api入門 #jjug ccc #ccc h2
ステップ・バイ・ステップで学ぶラムダ式・Stream api入門 #jjug ccc #ccc h2ステップ・バイ・ステップで学ぶラムダ式・Stream api入門 #jjug ccc #ccc h2
ステップ・バイ・ステップで学ぶラムダ式・Stream api入門 #jjug ccc #ccc h2Masatoshi Tada
 
JavaScriptことはじめ
JavaScriptことはじめJavaScriptことはじめ
JavaScriptことはじめYuki Ishikawa
 
JavaScriptユーティリティライブラリの紹介
JavaScriptユーティリティライブラリの紹介JavaScriptユーティリティライブラリの紹介
JavaScriptユーティリティライブラリの紹介Yusuke Hirao
 
JavaScript入門-基礎編
JavaScript入門-基礎編JavaScript入門-基礎編
JavaScript入門-基礎編mactkg
 
モテる JavaScript
モテる JavaScriptモテる JavaScript
モテる JavaScriptOsamu Monoe
 
社内Java8勉強会 ラムダ式とストリームAPI
社内Java8勉強会 ラムダ式とストリームAPI社内Java8勉強会 ラムダ式とストリームAPI
社内Java8勉強会 ラムダ式とストリームAPIAkihiro Ikezoe
 
JavaScript超入門 基礎
JavaScript超入門 基礎JavaScript超入門 基礎
JavaScript超入門 基礎tetsu6
 
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門Kazunori Tatsuki
 
Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]Ra Zon
 
Java8のstreamをダラダラまとめてみる
Java8のstreamをダラダラまとめてみるJava8のstreamをダラダラまとめてみる
Java8のstreamをダラダラまとめてみるShinya Mochida
 
JavaのGenericsとは?
JavaのGenericsとは?JavaのGenericsとは?
JavaのGenericsとは?Kenji Nakamura
 
Why Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuriWhy Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuriYuta Okamoto
 
15分でざっくり分かるScala入門
15分でざっくり分かるScala入門15分でざっくり分かるScala入門
15分でざっくり分かるScala入門SatoYu1ro
 
ジェネリクスの基礎と クラス設計への応用
ジェネリクスの基礎とクラス設計への応用ジェネリクスの基礎とクラス設計への応用
ジェネリクスの基礎と クラス設計への応用nagise
 
rpscala35-scala2.9.0
rpscala35-scala2.9.0rpscala35-scala2.9.0
rpscala35-scala2.9.0Kenji Yoshida
 
JavaScriptCore.framework の普通な使い方 #cocoa_kansai
JavaScriptCore.framework の普通な使い方 #cocoa_kansaiJavaScriptCore.framework の普通な使い方 #cocoa_kansai
JavaScriptCore.framework の普通な使い方 #cocoa_kansaiTomohiro Kumagai
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8y_taka_23
 
最強オブジェクト指向言語 JavaScript 再入門!
最強オブジェクト指向言語 JavaScript 再入門!最強オブジェクト指向言語 JavaScript 再入門!
最強オブジェクト指向言語 JavaScript 再入門!Yuji Nojima
 

What's hot (20)

ステップ・バイ・ステップで学ぶラムダ式・Stream api入門 #jjug ccc #ccc h2
ステップ・バイ・ステップで学ぶラムダ式・Stream api入門 #jjug ccc #ccc h2ステップ・バイ・ステップで学ぶラムダ式・Stream api入門 #jjug ccc #ccc h2
ステップ・バイ・ステップで学ぶラムダ式・Stream api入門 #jjug ccc #ccc h2
 
JavaScriptことはじめ
JavaScriptことはじめJavaScriptことはじめ
JavaScriptことはじめ
 
JavaScriptユーティリティライブラリの紹介
JavaScriptユーティリティライブラリの紹介JavaScriptユーティリティライブラリの紹介
JavaScriptユーティリティライブラリの紹介
 
JavaScript入門-基礎編
JavaScript入門-基礎編JavaScript入門-基礎編
JavaScript入門-基礎編
 
モテる JavaScript
モテる JavaScriptモテる JavaScript
モテる JavaScript
 
社内Java8勉強会 ラムダ式とストリームAPI
社内Java8勉強会 ラムダ式とストリームAPI社内Java8勉強会 ラムダ式とストリームAPI
社内Java8勉強会 ラムダ式とストリームAPI
 
JavaScript超入門 基礎
JavaScript超入門 基礎JavaScript超入門 基礎
JavaScript超入門 基礎
 
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
 
Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]
 
Java8のstreamをダラダラまとめてみる
Java8のstreamをダラダラまとめてみるJava8のstreamをダラダラまとめてみる
Java8のstreamをダラダラまとめてみる
 
JavaのGenericsとは?
JavaのGenericsとは?JavaのGenericsとは?
JavaのGenericsとは?
 
Phantom Type in Scala
Phantom Type in ScalaPhantom Type in Scala
Phantom Type in Scala
 
Why Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuriWhy Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuri
 
15分でざっくり分かるScala入門
15分でざっくり分かるScala入門15分でざっくり分かるScala入門
15分でざっくり分かるScala入門
 
Java8勉強会
Java8勉強会Java8勉強会
Java8勉強会
 
ジェネリクスの基礎と クラス設計への応用
ジェネリクスの基礎とクラス設計への応用ジェネリクスの基礎とクラス設計への応用
ジェネリクスの基礎と クラス設計への応用
 
rpscala35-scala2.9.0
rpscala35-scala2.9.0rpscala35-scala2.9.0
rpscala35-scala2.9.0
 
JavaScriptCore.framework の普通な使い方 #cocoa_kansai
JavaScriptCore.framework の普通な使い方 #cocoa_kansaiJavaScriptCore.framework の普通な使い方 #cocoa_kansai
JavaScriptCore.framework の普通な使い方 #cocoa_kansai
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
 
最強オブジェクト指向言語 JavaScript 再入門!
最強オブジェクト指向言語 JavaScript 再入門!最強オブジェクト指向言語 JavaScript 再入門!
最強オブジェクト指向言語 JavaScript 再入門!
 

Viewers also liked

Non-Functional Programming in Scala
Non-Functional Programming in ScalaNon-Functional Programming in Scala
Non-Functional Programming in Scalatakezoe
 
チームをワークさせるために 最も大事なコミュニケーション 意識していますか? - XP祭り2017
チームをワークさせるために 最も大事なコミュニケーション 意識していますか? - XP祭り2017チームをワークさせるために 最も大事なコミュニケーション 意識していますか? - XP祭り2017
チームをワークさせるために 最も大事なコミュニケーション 意識していますか? - XP祭り2017Koichi Yoshida
 
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjugフロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjugItsuki Kuroda
 
Microsoft ではじめる AI DLラボ パートナープログラムご紹介
Microsoft ではじめる AI DLラボ パートナープログラムご紹介Microsoft ではじめる AI DLラボ パートナープログラムご紹介
Microsoft ではじめる AI DLラボ パートナープログラムご紹介Hirono Jumpei
 
ChainerMNが即座に使える環境を提供するXTREME DNA HPC Cloud
ChainerMNが即座に使える環境を提供するXTREME DNA HPC CloudChainerMNが即座に使える環境を提供するXTREME DNA HPC Cloud
ChainerMNが即座に使える環境を提供するXTREME DNA HPC CloudHirono Jumpei
 
一般社団法人 日本ディープラーニング協会の取り組み
一般社団法人 日本ディープラーニング協会の取り組み一般社団法人 日本ディープラーニング協会の取り組み
一般社団法人 日本ディープラーニング協会の取り組みHirono Jumpei
 
DLL Community Update 10月版
DLL Community Update 10月版DLL Community Update 10月版
DLL Community Update 10月版Hirono Jumpei
 
[Ridge-i] Deep Learning Lab - ディープラーニング 導入の課題と実例
[Ridge-i] Deep Learning Lab - ディープラーニング 導入の課題と実例[Ridge-i] Deep Learning Lab - ディープラーニング 導入の課題と実例
[Ridge-i] Deep Learning Lab - ディープラーニング 導入の課題と実例Ridge-i
 
Microsoft Ignite! AI ソリューションアップデート
Microsoft Ignite! AI ソリューションアップデートMicrosoft Ignite! AI ソリューションアップデート
Microsoft Ignite! AI ソリューションアップデートHirono Jumpei
 
20171024 DLLab#04_PFN_Hiroshi Maruyama
20171024 DLLab#04_PFN_Hiroshi Maruyama20171024 DLLab#04_PFN_Hiroshi Maruyama
20171024 DLLab#04_PFN_Hiroshi MaruyamaPreferred Networks
 

Viewers also liked (10)

Non-Functional Programming in Scala
Non-Functional Programming in ScalaNon-Functional Programming in Scala
Non-Functional Programming in Scala
 
チームをワークさせるために 最も大事なコミュニケーション 意識していますか? - XP祭り2017
チームをワークさせるために 最も大事なコミュニケーション 意識していますか? - XP祭り2017チームをワークさせるために 最も大事なコミュニケーション 意識していますか? - XP祭り2017
チームをワークさせるために 最も大事なコミュニケーション 意識していますか? - XP祭り2017
 
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjugフロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjug
 
Microsoft ではじめる AI DLラボ パートナープログラムご紹介
Microsoft ではじめる AI DLラボ パートナープログラムご紹介Microsoft ではじめる AI DLラボ パートナープログラムご紹介
Microsoft ではじめる AI DLラボ パートナープログラムご紹介
 
ChainerMNが即座に使える環境を提供するXTREME DNA HPC Cloud
ChainerMNが即座に使える環境を提供するXTREME DNA HPC CloudChainerMNが即座に使える環境を提供するXTREME DNA HPC Cloud
ChainerMNが即座に使える環境を提供するXTREME DNA HPC Cloud
 
一般社団法人 日本ディープラーニング協会の取り組み
一般社団法人 日本ディープラーニング協会の取り組み一般社団法人 日本ディープラーニング協会の取り組み
一般社団法人 日本ディープラーニング協会の取り組み
 
DLL Community Update 10月版
DLL Community Update 10月版DLL Community Update 10月版
DLL Community Update 10月版
 
[Ridge-i] Deep Learning Lab - ディープラーニング 導入の課題と実例
[Ridge-i] Deep Learning Lab - ディープラーニング 導入の課題と実例[Ridge-i] Deep Learning Lab - ディープラーニング 導入の課題と実例
[Ridge-i] Deep Learning Lab - ディープラーニング 導入の課題と実例
 
Microsoft Ignite! AI ソリューションアップデート
Microsoft Ignite! AI ソリューションアップデートMicrosoft Ignite! AI ソリューションアップデート
Microsoft Ignite! AI ソリューションアップデート
 
20171024 DLLab#04_PFN_Hiroshi Maruyama
20171024 DLLab#04_PFN_Hiroshi Maruyama20171024 DLLab#04_PFN_Hiroshi Maruyama
20171024 DLLab#04_PFN_Hiroshi Maruyama
 

Similar to Reladomo in Scala #scala_ks

イマドキの現場で使えるJavaライブラリ事情
イマドキの現場で使えるJavaライブラリ事情イマドキの現場で使えるJavaライブラリ事情
イマドキの現場で使えるJavaライブラリ事情takezoe
 
Spring Framework / Boot / Data 徹底活用 〜Spring Data Redis 編〜
Spring Framework / Boot / Data 徹底活用  〜Spring Data Redis 編〜Spring Framework / Boot / Data 徹底活用  〜Spring Data Redis 編〜
Spring Framework / Boot / Data 徹底活用 〜Spring Data Redis 編〜Naohiro Yoshida
 
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24Kazuhiro Sera
 
React Native GUIDE
React Native GUIDEReact Native GUIDE
React Native GUIDEdcubeio
 
Seasarプロジェクト徹底攻略
Seasarプロジェクト徹底攻略Seasarプロジェクト徹底攻略
Seasarプロジェクト徹底攻略takezoe
 
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方linzhixing
 
traceur-compilerで未来のJavaScriptを体験
traceur-compilerで未来のJavaScriptを体験traceur-compilerで未来のJavaScriptを体験
traceur-compilerで未来のJavaScriptを体験Toshio Ehara
 
はじめよう Backbone.js
はじめよう Backbone.jsはじめよう Backbone.js
はじめよう Backbone.jsHiroki Toyokawa
 
Apache Torqueについて
Apache TorqueについてApache Torqueについて
Apache Torqueについてtako pons
 
Infrastructure as code for azure
Infrastructure as code for azureInfrastructure as code for azure
Infrastructure as code for azureKeiji Kamebuchi
 
JavaScript.Next
JavaScript.NextJavaScript.Next
JavaScript.Nextdynamis
 
traceur-compilerで ECMAScript6を体験
traceur-compilerで ECMAScript6を体験traceur-compilerで ECMAScript6を体験
traceur-compilerで ECMAScript6を体験Toshio Ehara
 
【LT】 怖くない恐怖のScala.js
【LT】 怖くない恐怖のScala.js【LT】 怖くない恐怖のScala.js
【LT】 怖くない恐怖のScala.jsYuto Suzuki
 
ScaLa+Liftとか
ScaLa+LiftとかScaLa+Liftとか
ScaLa+Liftとかyouku
 
ScalaでAndroidアプリ開発
ScalaでAndroidアプリ開発ScalaでAndroidアプリ開発
ScalaでAndroidアプリ開発papamitra
 
Tech Fielders 2009/9/18 LT
Tech Fielders 2009/9/18 LTTech Fielders 2009/9/18 LT
Tech Fielders 2009/9/18 LTterurou
 

Similar to Reladomo in Scala #scala_ks (20)

イマドキの現場で使えるJavaライブラリ事情
イマドキの現場で使えるJavaライブラリ事情イマドキの現場で使えるJavaライブラリ事情
イマドキの現場で使えるJavaライブラリ事情
 
いまさらJavaScript
いまさらJavaScriptいまさらJavaScript
いまさらJavaScript
 
Spring Framework / Boot / Data 徹底活用 〜Spring Data Redis 編〜
Spring Framework / Boot / Data 徹底活用  〜Spring Data Redis 編〜Spring Framework / Boot / Data 徹底活用  〜Spring Data Redis 編〜
Spring Framework / Boot / Data 徹底活用 〜Spring Data Redis 編〜
 
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
 
React Native GUIDE
React Native GUIDEReact Native GUIDE
React Native GUIDE
 
Seasarプロジェクト徹底攻略
Seasarプロジェクト徹底攻略Seasarプロジェクト徹底攻略
Seasarプロジェクト徹底攻略
 
Driverについて
DriverについてDriverについて
Driverについて
 
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
 
traceur-compilerで未来のJavaScriptを体験
traceur-compilerで未来のJavaScriptを体験traceur-compilerで未来のJavaScriptを体験
traceur-compilerで未来のJavaScriptを体験
 
はじめよう Backbone.js
はじめよう Backbone.jsはじめよう Backbone.js
はじめよう Backbone.js
 
scala-kaigi1-sbt
scala-kaigi1-sbtscala-kaigi1-sbt
scala-kaigi1-sbt
 
Apache Torqueについて
Apache TorqueについてApache Torqueについて
Apache Torqueについて
 
Infrastructure as code for azure
Infrastructure as code for azureInfrastructure as code for azure
Infrastructure as code for azure
 
JavaScript.Next
JavaScript.NextJavaScript.Next
JavaScript.Next
 
AlfrescoとSolr(後編)
AlfrescoとSolr(後編)AlfrescoとSolr(後編)
AlfrescoとSolr(後編)
 
traceur-compilerで ECMAScript6を体験
traceur-compilerで ECMAScript6を体験traceur-compilerで ECMAScript6を体験
traceur-compilerで ECMAScript6を体験
 
【LT】 怖くない恐怖のScala.js
【LT】 怖くない恐怖のScala.js【LT】 怖くない恐怖のScala.js
【LT】 怖くない恐怖のScala.js
 
ScaLa+Liftとか
ScaLa+LiftとかScaLa+Liftとか
ScaLa+Liftとか
 
ScalaでAndroidアプリ開発
ScalaでAndroidアプリ開発ScalaでAndroidアプリ開発
ScalaでAndroidアプリ開発
 
Tech Fielders 2009/9/18 LT
Tech Fielders 2009/9/18 LTTech Fielders 2009/9/18 LT
Tech Fielders 2009/9/18 LT
 

Reladomo in Scala #scala_ks