SlideShare a Scribd company logo
Kotlin Meets Data-Oriented
Programming
Kotlinで実践する「データ指向プログラミング」
1
のシニアエンジニア
主要技術スタック
のたまごスポンサー
の運営企業
関数型⾔語 関数型プログラミングが⼤好き
仕事や趣味で などに⻑く
触れてきた
現職で初めて を仕事で読み書きするように
なって半年ほど
lagénorhynque カマイルカ
株式会社スマートラウンド
2
Kotlin Fest 2024への私 のCfP
3
書籍 は、プログラミン
グ⾔語 において典型的なプログラミングスタ
イルの根幹にある考え⽅を他⾔語でも応⽤できる形で
抽出し紹介する試みであるということができます。
を実務や趣味で継続的に利⽤するとともに⽐
較的最近 に再⼊⾨した⽴場から、この本で提⽰
されている「データ指向プログラミング」というプロ
グラミングスタイルを概説しながら らしい実践
の可能性について考察します。
Kotlin Meets Data-Oriented Programming:
Kotlinで実践する「データ指向プログラミング」
『データ指向プログラミング』
4
データ指向プログラミングとは
への適⽤可能性を探る
まとめ
5
1. データ指向プログラミングとは
6
書籍 まえがき
『データ指向プログラミング』
特別なのは機能ではなく原則だと
いうことで意⾒が⼀致した。
の基本原則を抜き出そうとしていた
私たちは、実際には、それらの原則
を他のプログラミング⾔語に応⽤で
きることに気づいた。本書の構想が
沸いてきたのはそのときだった。私
が でとても気に⼊っている点
を世界中の開発者コミュニティに伝
えたかった。
7
に魅了された著者が ⾔語 コミュニテ
ィで⼀般的なプログラミングスタイルのエッセンス
を他⾔語でも応⽤できる形で抽出しようとした本
古典的な に対するアンチテーゼといえる
他の⾔語や設計思想と必ずしも馴染まず批判され
ることもある 批判も理解できる
である の視点から捉え直し、 での
現実的な応⽤の可能性を考えたい
8
(ちなみに) Clojureとは
動的型付き ⾮オブジェクト指向
年に登場した
年〜
年〜
作者 のプレゼン は他
のコミュニティでも多少知られているかも
⾔語の設計にも⾊濃く反映されている、
の重要性について語っている
関数型⾔語
古典的な には当初から批判的
モダンに再設計された 系⾔語
⾔語
9
データ指向プログラミングの背景
古典的な のアプローチに対する問題意識
必要以上の複雑さを⽣みがち
いろいろな要素が絡み合っている
硬直的で柔軟性に⽋けることがある
フレームワークに頼らざるを得なかったり
→ もっとシンプル に情報を扱うアプローチ
があるはず
そうして⽣まれたのが ⾔語でもある
10
データ指向プログラミングの原則
原則 コードをデータから切り離す
原則 データを汎⽤的なデータ構造で表す
原則 データはイミュータブルである
原則 データスキーマをデータ表現から切り離す
のプログラミングスタイルそのもの
11
データ指向プログラミングと親和性の⾼い技術
ロックフリー な楽観的並⾏性制御
の
純粋な関数、不変なデータとの相性が良い
状態変化のタイムトラベル、リプレイ
状態が不変の汎⽤データ構造で表現されていれば
極めて簡単
永続データ構造
不変 かつ永続的 であれば
効率も犠牲になりにくい
『純粋関数型データ構造』
12
2. Kotlinへの適⽤可能性を探る
13
データ指向プログラミングの原則(再掲)
原則 コードをデータから切り離す
原則 データを汎⽤的なデータ構造で表す
原則 データはイミュータブルである
原則 データスキーマをデータ表現から切り離す
のプログラミングスタイルそのもの
14
原則 #1: コードをデータから切り離す
15
Clojureの場合
関数の定義 データはマップ { } で表す
(ns dop-examples) ; 名前空間(namespace)の定義
(defn make-author [first-name last-name num-of-books]
{:first-name first-name
:last-name last-name
:num-of-books num-of-books})
(defn full-name [{:keys [first-name last-name]}]
(str first-name " " last-name))
(defn prolific? [{:keys [num-of-books]}]
(or (some-> num-of-books (> 100))
false))
16
利⽤例
;; FYI: プロンプトの `dop-examples` は現在の名前空間(モジュール)
;; そこでdef/requireされているものは⾮修飾名で参照できる
dop-examples> (let [data (make-author "Isaac" "Asimov" 500)]
(full-name data))
"Isaac Asimov"
17
「レコード」 ≒ を定義することもできる
マップとレコードはインターフェースが共通している
ため、関数 full-name はそのまま使える
(defrecord Author
[first-name
last-name
num-of-books])
(defn make-author' [first-name last-name num-of-books]
(->Author first-name last-name num-of-books))
dop-examples> (let [data (make-author' "Isaac" "Asimov" 500)]
(full-name data))
"Isaac Asimov"
18
(書籍より) 利点とコスト
主な利点
コードをさまざまなコンテキストで再利⽤できる
コードを単体でテストできる
システムがあまり複雑にならない傾向にある
主なコスト
どのコードがどのデータにアクセスできるのかを
制御できない
パッケージ化がない
システムを構成するエンティティの数が増える
19
Kotlinの場合
データと関数の定義
クラス オブジェクトは「モジュール」でもある
data class Author(
val firstName: String,
val lastName: String,
val numOfBooks: Int?,
)
object NameCalculation {
fun fullName(data: Author): String =
"${data.firstName} ${data.lastName}"
}
object AuthorRating {
fun isProlific(data: Author): Boolean =
data.numOfBooks?.let { it > 100 } ?: false
}
20
利⽤例
らしい ドット記法が必要であれば
> val data = Author("Isaac", "Asimov", 500)
> NameCalculation.fullName(data)
res2: kotlin.String = Isaac Asimov
> fun Author.fullName(): String =
NameCalculation.fullName(this)
> data.fullName()
res4: kotlin.String = Isaac Asimov
21
や
の代わりに
インターフェースを定義することで特定の具象型
Author2 に縛られなくすることはできる
構造的型 拡張可能レコード
interface Namable {
val firstName: String
val lastName: String
}
data class Author2(
override val firstName: String,
override val lastName: String,
val numOfBooks: Int?,
) : Namable
object NameCalculation2 {
fun fullName(data: Namable): String =
"${data.firstName} ${data.lastName}"
}
原則 #2: データを汎⽤的なデータ構造で表す
23
Clojureの場合
連想データに対するあらゆるオペレータ 関数 マクロ
特殊形式 が利⽤できる
;; マップ(リテラルで作成)
dop-examples> {:first-name "Isaac"
:last-name "Asimov"
:num-of-books 500}
{:first-name "Isaac", :last-name "Asimov", :num-of-books 500}
;; レコード(コンストラクタ関数で作成)
dop-examples> (->Author "Isaac" "Asimov" 500)
{:first-name "Isaac", :last-name "Asimov", :num-of-books 500}
;; どちらも Associative (連想データ)インターフェースを実装している
dop-examples> (associative? {:first-name "Isaac"
:last-name "Asimov"
:num-of-books 500})
true
dop-examples> (associative? (->Author "Isaac" "Asimov" 500))
true
24
(書籍より) 利点とコスト
主な利点
特定のユースケースに限定されないジェネリック
関数を利⽤できる
柔軟なデータモデル
主なコスト
パフォーマンスが少し低下する
データスキーマがない
コンパイル時にデータの有効性が確認されない
静的に型付けされる⾔語では、明⽰的な型変換
キャスト が必要になることがある
25
Kotlinの場合
構造的型や拡張可能レコードのサポートがなく、後
述のデータスキーマを記述するのも⼀般的ではない
主体で具体的な型としてデータを定義
するのが妥当そう 適宜インターフェース化しうる
> data class Author(
val firstName: String,
val lastName: String,
val numOfBooks: Int?,
)
> Author("Isaac", "Asimov", 500)
res6: Line_0.Author = Author(firstName=Isaac, lastName=Asimov
, numOfBooks=500)
26
原則 #3: データはイミュータブルである
27
Clojureの場合
マップほか は不変
安全であり 実⽤上 ⼗分に効率的でもある
ネイティブのデータ構造
;; 関数 assoc は連想データのエントリーをupsertする
dop-examples> (assoc {:first-name "Isaac"
:last-name "Asimov"
:num-of-books 500}
:num-of-books 100)
{:first-name "Isaac", :last-name "Asimov", :num-of-books 100}
dop-examples> (let [data {:first-name "Isaac"
:last-name "Asimov"
:num-of-books 500}
data' (assoc data
:num-of-books 100)]
(identical? data data'))
false ; 参照が異なる別のデータ(永続データなので内部的には共有がある)
28
(書籍より) 利点とコスト
主な利点
すべての関数から⾃信を持ってデータにアクセス
できる
コードの振る舞いが予測可能である
等価のチェックが⾼速である
並⾏処理の安全性が⾃動的に確保される
主なコスト
パフォーマンスが低下する
永続的なデータ構造のためのライブラリが必要で
ある
29
Kotlinの場合
再代⼊不可な プロパティとほぼ不変単に の場合あり な
データ構造を利⽤することはできる
> val data1 = Author("Isaac", "Asimov", 500)
> val data2 = data.copy(numOfBooks = 100)
> data1 === data2
res9: kotlin.Boolean = false // 参照が異なる別のデータ
ミュータビリティとイミュータビリティの狭間 関
数型⾔語使いから⾒た コレクション
30
原則 #4: データスキーマをデータ表現から切り離す
31
Clojureの場合
ライブラリ が標準で
含まれており、広く使われている
契約プログラミング
(ns dop-examples
(:require
[clojure.spec.alpha :as s] ; clojure.specの導⼊
[clojure.string :as str]))
(defn make-author [first-name last-name num-of-books]
{:first-name first-name
:last-name last-name
:num-of-books num-of-books})
(defn full-name [{:keys [first-name last-name]}]
(str first-name " " last-name))
(defn prolific? [{:keys [num-of-books]}]
(or (some-> num-of-books (> 100))
false))
32
データの仕様
述語 により値レベルの制約まで記述できる
(s/def ::name
(s/and string?
(complement str/blank?) ; 空⽂字列/空⽩のみでない
#(<= (count %) 100))) ; ⻑さが100以下
(s/def ::first-name ::name)
(s/def ::last-name ::name)
(s/def ::num-of-books
(s/nilable ; nilになりうる
(s/and nat-int? ; (0を含む)⾃然数
#(<= % 10000)))) ; 10000以下
(s/def ::author
(s/keys :req-un [::first-name ; 列挙したキーを必ず含む
::last-name]
:opt-un [::num-of-books])) ; 列挙したキーを任意で含む
33
関数の仕様
データの仕様で関数の⼊出⼒仕様を記述できる
(s/fdef make-author
:args (s/cat :first-name ::first-name ; 第1引数
:last-name ::last-name ; 第2引数
:num-of-books ::num-of-books) ; 第3引数
:ret ::author) ; 戻り値
(s/fdef full-name
:args (s/cat :data (s/keys :req-un [::first-name
::last-name]))
:ret string?)
(s/fdef prolific?
:args (s/cat :data (s/keys :req-un [::num-of-books]))
:ret boolean?)
34
データに対する検証
;; 必須の :last-name キーが⽋けたマップの場合
dop-examples> (s/explain ::author {:first-name "Isaac"
:num-of-books 500})
{:first-name "Isaac", :num-of-books 500} - failed:
(contains? % :last-name) spec: :dop-examples/author
nil
35
;; :num-of-books の値が負の数の場合
dop-examples> (s/explain ::author {:first-name "Isaac"
:last-name "Asimov"
:num-of-books -1})
-1 - failed: nat-int? in: [:num-of-books] at: [:num-of-books
:clojure.spec.alpha/pred] spec: :dop-examples/num-of-books
-1 - failed: nil? in: [:num-of-books] at: [:num-of-books
:clojure.spec.alpha/nil] spec: :dop-examples/num-of-books
nil
36
関数 引数 に対する検証
;; 関数の引数に対するチェックを有効化
dop-examples> (clojure.spec.test.alpha/instrument)
[dop-examples/make-author dop-examples/full-name
dop-examples/prolific?]
;; 第1引数(first-name)が空の場合
dop-examples> (make-author "" "Asimov" 500)
Execution error - invalid arguments to
dop-examples/make-author at (REPL:103).
"" - failed: (complement blank?) at: [:first-name] spec:
:dop-examples/name
37
;; キーにtypoがある(必須の :first-name キーがない)場合
dop-examples> (full-name {:fist-name "Isaac"
:last-name "Asimov"})
Execution error - invalid arguments to dop-examples/full-name
at (REPL:106).
{:fist-name "Isaac", :last-name "Asimov"} - failed:
(contains? % :first-name) at: [:data]
38
(書籍より) 利点とコスト
主な利点
検証すべきデータを⾃由に選択できる
オプションフィールドを利⽤できる
⾼度なデータ検証条件を利⽤できる
データモデルを⾃動的に可視化できる
主なコスト
データとスキーマの結び付きが弱い
パフォーマンスが少し低下する
39
Kotlinの場合
などのサポートはないので、
型で表現しがたい仕様はアサーションで検証
プリミティブなデータをリッチにすることもできる
依存型
data class Author3(
val firstName: String,
val lastName: String,
val numOfBooks: Int?,
) {
init {
require(firstName.isNotBlank()
&& firstName.length <= 100)
require(lastName.isNotBlank()
&& lastName.length <= 100)
require(numOfBooks?.let { it in 0..10000 } ?: true)
}
}
40
3. まとめ
41
「データ指向プログラミング」は ⾔語 コミ
ュニティに由来するプログラミングスタイル
その⼒が最も効果的に発揮されるのは
を使うときかも もいいぞ
のような静的型付きオブジェクト指向⾔語で
も こそ 参考になる⽰唆を含んでいる
そもそも近年の新興⾔語ではクラスベースの
を押し出していない印象がある。クラスと
いう枠組みでのモデル化に囚われる必要はない
42
Further Reading
データ指向プログラミング
本発表のサンプルコード
『データ指向プログラミング』
新刊『データ指向プログラミング』から「はじめ
に」を公開! オブジェクト指向との対⽐も語ら
れる (コードジン)
データ指向プログラミングの真実をお話しします
43
Clojure
による解説
公式サイト
と はどう違う?
を解説 ログミー
の設計に⾒る という考え⽅
を解説 ログミー
の世界観 紙箱
44

More Related Content

PDF
メタメタプログラミングRuby
emasaka
 
PDF
Rでreproducible research
Shintaro Fukushima
 
PDF
関数型言語テイスティング: Haskell, Scala, Clojure, Elixirを比べて味わう関数型プログラミングの旨さ
Kent Ohashi
 
PDF
ECMAScript6による関数型プログラミング
TanUkkii
 
PDF
Elasticsearchプラグインの作り方
Shinsuke Sugaya
 
PDF
RとSQLiteで気軽にデータベース作成
弘毅 露崎
 
PDF
Scala の関数型プログラミングを支える技術
Naoki Aoyama
 
PDF
ふぉとぶらり+LODAC -iPhoneアプリでのSPARQLでの活用事例-
uedayou
 
メタメタプログラミングRuby
emasaka
 
Rでreproducible research
Shintaro Fukushima
 
関数型言語テイスティング: Haskell, Scala, Clojure, Elixirを比べて味わう関数型プログラミングの旨さ
Kent Ohashi
 
ECMAScript6による関数型プログラミング
TanUkkii
 
Elasticsearchプラグインの作り方
Shinsuke Sugaya
 
RとSQLiteで気軽にデータベース作成
弘毅 露崎
 
Scala の関数型プログラミングを支える技術
Naoki Aoyama
 
ふぉとぶらり+LODAC -iPhoneアプリでのSPARQLでの活用事例-
uedayou
 

Similar to Kotlin Meets Data-Oriented Programming: Kotlinで実践する「データ指向プログラミング」 (20)

PPTX
BPStudy32 CouchDB 再入門
Yohei Sasaki
 
PDF
20170618 Google I/O報告会in福岡
mokelab
 
PPTX
Lambda in template_final
Cryolite
 
PDF
Thinking in Cats
Eugene Yokota
 
PDF
Rあんなときこんなとき(tokyo r#12)
Shintaro Fukushima
 
PPTX
Nds meetup8 lt
ushiboy
 
PDF
Python 機械学習プログラミング データ分析ライブラリー解説編
Etsuji Nakai
 
PDF
名前重要 超重要
baban ba-n
 
PDF
TypeScript & 関数型講座 第2回 TypeScript という言語
gypsygypsy
 
PPTX
R6パッケージの紹介―機能と実装
__nakamichi__
 
PDF
C++ lecture-0
sunaemon
 
PDF
Tokyor23 doradora09
Nobuaki Oshiro
 
PDF
DataStax EnterpriseでApache Tinkerpop入門
Yuki Morishita
 
PDF
[第2版]Python機械学習プログラミング 第8章
Haruki Eguchi
 
PDF
20110820 metaprogramming
Masanori Kado
 
PDF
Scalaプログラミング・マニアックス
Tomoharu ASAMI
 
PDF
Tokyo r 25_lt_isobe
Masayuki Isobe
 
PDF
Everyday Life with clojure.spec
Kent Ohashi
 
PDF
TypeScript 1.0 オーバービュー
Akira Inoue
 
PPTX
[機械学習]文章のクラス分類
Tetsuya Hasegawa
 
BPStudy32 CouchDB 再入門
Yohei Sasaki
 
20170618 Google I/O報告会in福岡
mokelab
 
Lambda in template_final
Cryolite
 
Thinking in Cats
Eugene Yokota
 
Rあんなときこんなとき(tokyo r#12)
Shintaro Fukushima
 
Nds meetup8 lt
ushiboy
 
Python 機械学習プログラミング データ分析ライブラリー解説編
Etsuji Nakai
 
名前重要 超重要
baban ba-n
 
TypeScript & 関数型講座 第2回 TypeScript という言語
gypsygypsy
 
R6パッケージの紹介―機能と実装
__nakamichi__
 
C++ lecture-0
sunaemon
 
Tokyor23 doradora09
Nobuaki Oshiro
 
DataStax EnterpriseでApache Tinkerpop入門
Yuki Morishita
 
[第2版]Python機械学習プログラミング 第8章
Haruki Eguchi
 
20110820 metaprogramming
Masanori Kado
 
Scalaプログラミング・マニアックス
Tomoharu ASAMI
 
Tokyo r 25_lt_isobe
Masayuki Isobe
 
Everyday Life with clojure.spec
Kent Ohashi
 
TypeScript 1.0 オーバービュー
Akira Inoue
 
[機械学習]文章のクラス分類
Tetsuya Hasegawa
 
Ad

More from Kent Ohashi (20)

PDF
純LISPから考える関数型言語のプリミティブ: Clojure, Elixir, Haskell, Scala
Kent Ohashi
 
PDF
From Scala/Clojure to Kotlin
Kent Ohashi
 
PDF
TDD with RDD: Clojure/LispのREPLで変わる開発体験
Kent Ohashi
 
PDF
🐬の推し本紹介2024: 『脱・日本語なまり 英語(+α)実践音声学』
Kent Ohashi
 
PDF
do Notation Equivalents in JVM languages: Scala, Kotlin, Clojure
Kent Ohashi
 
PDF
map関数の内部実装から探るJVM言語のコレクション: Scala, Kotlin, Clojureコレクションの基本的な設計を理解しよう
Kent Ohashi
 
PDF
RDBでのツリー表現入門2024
Kent Ohashi
 
PDF
ミュータビリティとイミュータビリティの狭間: 関数型言語使いから見たKotlinコレクション
Kent Ohashi
 
PDF
インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPC
Kent Ohashi
 
PDF
Team Geek Revisited
Kent Ohashi
 
PDF
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
Kent Ohashi
 
PDF
Clojureコレクションで探るimmutableでpersistentな世界
Kent Ohashi
 
PDF
英語学習者のためのフランス語文法入門: フランス語完全理解(?)
Kent Ohashi
 
PDF
JavaからScala、そしてClojureへ: 実務で活きる関数型プログラミング
Kent Ohashi
 
PDF
実用のための語源学入門
Kent Ohashi
 
PDF
メタプログラミング入門
Kent Ohashi
 
PDF
労働法の世界
Kent Ohashi
 
PDF
Clojureで作る"simple"なDSL
Kent Ohashi
 
PDF
RDBでのツリー表現入門
Kent Ohashi
 
PDF
GraphQL入門
Kent Ohashi
 
純LISPから考える関数型言語のプリミティブ: Clojure, Elixir, Haskell, Scala
Kent Ohashi
 
From Scala/Clojure to Kotlin
Kent Ohashi
 
TDD with RDD: Clojure/LispのREPLで変わる開発体験
Kent Ohashi
 
🐬の推し本紹介2024: 『脱・日本語なまり 英語(+α)実践音声学』
Kent Ohashi
 
do Notation Equivalents in JVM languages: Scala, Kotlin, Clojure
Kent Ohashi
 
map関数の内部実装から探るJVM言語のコレクション: Scala, Kotlin, Clojureコレクションの基本的な設計を理解しよう
Kent Ohashi
 
RDBでのツリー表現入門2024
Kent Ohashi
 
ミュータビリティとイミュータビリティの狭間: 関数型言語使いから見たKotlinコレクション
Kent Ohashi
 
インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPC
Kent Ohashi
 
Team Geek Revisited
Kent Ohashi
 
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
Kent Ohashi
 
Clojureコレクションで探るimmutableでpersistentな世界
Kent Ohashi
 
英語学習者のためのフランス語文法入門: フランス語完全理解(?)
Kent Ohashi
 
JavaからScala、そしてClojureへ: 実務で活きる関数型プログラミング
Kent Ohashi
 
実用のための語源学入門
Kent Ohashi
 
メタプログラミング入門
Kent Ohashi
 
労働法の世界
Kent Ohashi
 
Clojureで作る"simple"なDSL
Kent Ohashi
 
RDBでのツリー表現入門
Kent Ohashi
 
GraphQL入門
Kent Ohashi
 
Ad

Kotlin Meets Data-Oriented Programming: Kotlinで実践する「データ指向プログラミング」