SlideShare a Scribd company logo
Spectacular	Future
with	clojure.spec
Self-introduction
	/laʒenɔʁɛ̃k/	カマイルカlagénorhynque
(defprofile lagénorhynque
:name "Kent OHASHI"
:languages [Clojure Haskell Python Scala
English français Deutsch русский]
:interests [programming language-learning mathematics]
:contributing [github.com/japan-clojurians/clojure-site-ja])
「Clojureをプロダクトに導⼊した話」
Clojure
Contents
1.	 Clojure	Quick	Intro
2.	 New	Feature:	clojure.spec
Clojure	Quick	Intro
Clojure
Lisp
S式,	マクロ,	etc.
REPL駆動開発
関数型プログラミング⾔語
動的⾔語
JVM⾔語	(cf.	ClojureScript)
⇒	シンプルで強⼒な⾔語
リテラル
type example
string "abc"
character a
number 1,	2.0,	3N,	4.5M,	6/7,	8r10
boolean true,	false
nil nil
keyword :a,	:user/a,	::a,	::x/a
symbol 'a,	'user/a,	`a,	`x/a
type example
list '(1 2 3),	'(+ 1 2 3)
vector [1 2 3]
set #{1 2 3}
map {:a 1 :b 2},	#:user{:a 1 :b 2},
#::{:a 1 :b 2},	#::x{:a 1 :b 2}
function (fn [x] (* x x))
シンタックス
オペレータ
関数
マクロ
特殊形式
(op arg1 arg2 ... argn)
New	Feature:
clojure.spec
例:	直⽅体の体積計算
直⽅体の体積	=	辺a	×	辺b	×	辺c
user> (defn cuboid-volume [{:keys [side-a side-b side-c]}]
(* side-a side-b side-c))
#'user/cuboid-volume
user> (cuboid-volume {:side-a 1 :side-b 2 :side-c 3})
6
エラー
Javaのスタックトレースが\(^o^)/……
;; マップの値の型が数値ではなく⽂字列
user> (cuboid-volume {:side-a 1 :side-b "2" :side-c 3})
ClassCastException java.lang.String cannot be cast to java.lang.
Number clojure.lang.Numbers.multiply (Numbers.java:148)
;; マップのキー名でtypo
user> (cuboid-volume {:side-a 1 :side-d 2 :side-c 3})
NullPointerException clojure.lang.Numbers.ops (Numbers.java:10
18)
;; マップに必須のキーがない
user> (cuboid-volume {:side-a 1 :side-c 3})
NullPointerException clojure.lang.Numbers.ops (Numbers.java:10
18)
問題点
動的⾔語なのでコンパイル時に引数の型の不整合が
検出されない
少なくとも実⾏時に分かりやすいエラーになって
ほしい
マップのkey-valueに対するチェックがない
動的なデータを柔軟に表現したい
cf.	
漸進的型付け(gradual	typing)
Clojureに静的型システムを追加
コンパイル時に型チェック
core.typed
(require '[clojure.core.typed :as t])
(t/ann cuboid-volume [(t/HMap :mandatory {:side-a t/Num
:side-b t/Num
:side-c t/Num})
:-> t/Num])
(defn cuboid-volume [{:keys [side-a side-b side-c]}]
(* side-a side-b side-c))
cf.	
データ記述/バリデーションDSL
独⾃DSLでデータ構造を表現
実⾏時にバリデーション
schema
(require '[schema.core :as s])
(s/defn cuboid-volume :- s/Num
[{:keys [side-a side-b side-c]} :- {:side-a s/Num
:side-b s/Num
:side-c s/Num}]
(* side-a side-b side-c))
clojure.spec
述語(predicate)を組み合わせて仕様(spec)を書いて
ドキュメント
バリデーション
詳細なエラー報告
パースと分配束縛
データ⽣成
プロパティベーストテスト
などを実現する仕組み
dependency
REPL
[org.clojure/clojure "1.9.0-beta1"]
user> (require '[clojure.spec.alpha :as s]
'[clojure.spec.test.alpha :as stest]
'[clojure.spec.gen.alpha :as gen])
nil
「⻑さ」をspecで表現
	でキーワード	:user/length	に述語
number?	を登録
user> (s/def ::length number?)
:user/length
user> (doc ::length)
-------------------------
:user/length
Spec
number?
nil
s/def
「⻑さ」に⼀致する値を調べる
	で	::length	のspecに具体的な値が
⼀致するか確認
⼀致しなければ	::s/invalid
user> (s/conform ::length 3)
3
user> (s/conform ::length "3")
:clojure.spec.alpha/invalid
s/conform
⼀致しない原因を調べる
	で⼀致しない詳細原因を確認
ここでは
値	"3"	がspec	:user/length	の述語	number?
に不⼀致
user> (s/explain ::length "3")
val: "3" fails spec: :user/length predicate: number?
:clojure.spec.alpha/spec :user/length
:clojure.spec.alpha/value "3"
nil
s/explain
「⻑さ」のサンプルを⽣成
	で	 	互換なジェネレータを取得
	でサンプルを⽣成
user> (s/gen ::length)
#clojure.test.check.generators.Generator{:gen #function[clojure.
test.check.generators/such-that/fn--13745]}
user> (gen/sample (s/gen ::length))
(0.5 -1.0 -1 0.5 3.25 0 -3 0.6875 0.25 0)
s/gen test.check
gen/sample
「⻑さ」に制約を加える
論理演算⼦で制約を追加
	は論理積
cf.	
user> (s/def ::length (s/and number? pos?))
:user/length
user> (doc ::length)
-------------------------
:user/length
Spec
(and number? pos?)
nil
user> (gen/sample (s/gen ::length))
(0.5 3.0 0.5 1.375 1.6875 3.0 0.625 1.25 0.41015625 0.25)
s/and
s/or
「⻑さ」で辺a,	b,	cを表現
user> (s/def ::side-a ::length)
:user/side-a
user> (doc ::side-a)
-------------------------
:user/side-a
Spec
(and number? pos?)
nil
user> (s/def ::side-b ::length)
:user/side-b
user> (s/def ::side-c ::length)
:user/side-c
辺a,	b,	cを持つマップとして直⽅体
を表現
	で必須のキーを持つマップを表現
user> (s/def ::cuboid (s/keys :req [::side-a ::side-b ::side-c])
)
:user/cuboid
user> (doc ::cuboid)
-------------------------
:user/cuboid
Spec
(keys :req [:user/side-a :user/side-b :user/side-c])
nil
s/keys
直⽅体に⼀致する値を調べる
user> (s/conform ::cuboid #::{:side-a 1
:side-b 2
:side-c 3})
#:user{:side-a 1, :side-b 2, :side-c 3}
user> (s/conform ::cuboid #::{:side-a 1
:side-b "2"
:side-c 3})
:clojure.spec.alpha/invalid
⼀致しない原因を調べる
:user/side-b	の値	"2"	がspec	:user/length
の述語	number?	に不⼀致
マップのキーに対応するspecもチェックされる
user> (s/explain ::cuboid #::{:side-a 1
:side-b "2"
:side-c 3})
In: [:user/side-b] val: "2" fails spec: :user/length at: [:user/
side-b] predicate: number?
:clojure.spec.alpha/spec :user/cuboid
:clojure.spec.alpha/value #:user{:side-a 1, :side-b "2", :side-
c 3}
nil
値	#:user{:side-a 1, :side-d 2, :side-c
3}	がspec	:user/cuboid	の述語	(contains? %
:user/side-b)	に不⼀致
user> (s/explain ::cuboid #::{:side-a 1
:side-d 2
:side-c 3})
val: #:user{:side-a 1, :side-d 2, :side-c 3} fails spec: :user/c
uboid predicate: (contains? % :user/side-b)
:clojure.spec.alpha/spec :user/cuboid
:clojure.spec.alpha/value #:user{:side-a 1, :side-d 2, :side-c
3}
nil
値	#:user{:side-a 1, :side-c 3}	がspec
:user/cuboid	の述語	(contains? %
:user/side-b)	に不⼀致
user> (s/explain ::cuboid #::{:side-a 1
:side-c 3})
val: #:user{:side-a 1, :side-c 3} fails spec: :user/cuboid predi
cate: (contains? % :user/side-b)
:clojure.spec.alpha/spec :user/cuboid
:clojure.spec.alpha/value #:user{:side-a 1, :side-c 3}
nil
直⽅体のサンプルを⽣成
複合的なデータのサンプルも⽣成できる
user> (gen/sample (s/gen ::cuboid))
(#:user{:side-a 0.5, :side-b 1.0, :side-c 0.625} #:user{:side-a
0.5, :side-b 1.5, :side-c 2} #:user{:side-a 2.0, :side-b 4, :sid
e-c 1} #:user{:side-a 1.5, :side-b 1.0, :side-c 1} #:user{:side-
a 0.5, :side-b 12, :side-c 1.125} #:user{:side-a 49, :side-b 0.3
59375, :side-c 0.765625} #:user{:side-a 2, :side-b 1, :side-c 1.
25} #:user{:side-a 3.0, :side-b 0.5, :side-c 2.0} #:user{:side-a
1.3125, :side-b 1.0, :side-c 1.0} #:user{:side-a 5.265625, :sid
e-b 1.0625, :side-c 2.73828125})
直⽅体の体積計算の仕様を表現
	で関数	cuboid-volume	の引数と戻り値
に対するspecを登録
引数:	::cuboid	1要素のシーケンス
	は正規表現演算⼦
cf.	 ,	 ,	 ,	 ,	
戻り値:	数値
user> (s/fdef cuboid-volume
:args (s/cat :cuboid ::cuboid)
:ret number?)
user/cuboid-volume
s/fdef
s/cat
s/* s/+ s/? s/& s/alt
仕様を満たすように関数を実装
user> (defn cuboid-volume [{::keys [side-a side-b side-c]}]
(* side-a side-b side-c))
#'user/cuboid-volume
引数に対するチェックを有効化
stest/instrument
user> (doc cuboid-volume)
-------------------------
user/cuboid-volume
([#:user{:keys [side-a side-b side-c]}])
Spec
args: (cat :cuboid :user/cuboid)
ret: number?
nil
user> (stest/instrument)
[user/cuboid-volume]
引数のspecを満たす値に適⽤すると期待した計算
結果が得られる
user> (cuboid-volume #::{:side-a 1
:side-b 2
:side-c 3})
6
パス	[0 :user/side-b]	の値	"2"	がspec
:user/length	の述語	number?	に不⼀致	⇒	例外
user> (cuboid-volume #::{:side-a 1
:side-b "2"
:side-c 3})
ExceptionInfo Call to #'user/cuboid-volume did not conform to sp
ec:
In: [0 :user/side-b] val: "2" fails spec: :user/length at: [:arg
s :cuboid :user/side-b] predicate: number?
:clojure.spec.alpha/spec #object[clojure.spec.alpha$regex_spec_
impl$reify__1200 0x57e771b6 "clojure.spec.alpha$regex_spec_impl$
reify__1200@57e771b6"]
:clojure.spec.alpha/value (#:user{:side-a 1, :side-b "2", :side
-c 3})
:clojure.spec.alpha/args (#:user{:side-a 1, :side-b "2", :side-
c 3})
:clojure.spec.alpha/failure :instrument
:clojure.spec.test.alpha/caller {:file "form-init41134222269549
81451.clj", :line 188, :var-scope user/eval14130}
clojure.core/ex-info (core.clj:4744)
関数の動作確認
	で引数のspecを満たすランダム
な値で動作確認
結果はベクター	[引数 戻り値]	のシーケンス
user> (s/exercise-fn `cuboid-volume)
([(#:user{:side-a 2.0, :side-b 0.5, :side-c 0.5}) 0.5] [(#:user{
:side-a 0.75, :side-b 1.5, :side-c 0.75}) 0.84375] [(#:user{:sid
e-a 2.0, :side-b 1, :side-c 1.75}) 3.5] [(#:user{:side-a 4, :sid
e-b 4, :side-c 2}) 32] [(#:user{:side-a 2, :side-b 6, :side-c 1.
0}) 12.0] [(#:user{:side-a 1, :side-b 3, :side-c 6}) 18] [(#:use
r{:side-a 20, :side-b 1.0, :side-c 99}) 1980.0] [(#:user{:side-a
12, :side-b 890, :side-c 1.25}) 13350.0] [(#:user{:side-a 4, :s
ide-b 0.99609375, :side-c 2.0}) 7.96875] [(#:user{:side-a 3, :si
de-b 6.0, :side-c 9}) 162.0])
s/exercise-fn
⾃動プロパティベーストテスト
stest/check
user> (stest/check `cuboid-volume)
({:spec #object[clojure.spec.alpha$fspec_impl$reify__1215 0x765acd43 "c
:cause "integer overflow"
:via
[{:type java.lang.ArithmeticException
:message "integer overflow"
:at [clojure.lang.Numbers throwIntOverflow "Numbers.java" 1526]}]
:trace
[[clojure.lang.Numbers throwIntOverflow "Numbers.java" 1526]
[clojure.lang.Numbers multiply "Numbers.java" 1892]
[clojure.lang.Numbers$LongOps multiply "Numbers.java" 472]
[clojure.lang.Numbers multiply "Numbers.java" 148]
[user$cuboid_volume invokeStatic "form-init4113422226954981451.clj" 1
[user$cuboid_volume invoke "form-init4113422226954981451.clj" 155]
[clojure.lang.AFn applyToHelper "AFn.java" 154]
[clojure.lang.AFn applyTo "AFn.java" 144]
[clojure.core$apply invokeStatic "core.clj" 657]
[clojure.core$apply invoke "core.clj" 652]
[clojure.spec.test.alpha$check_call invokeStatic "alpha.clj" 292]
ここでは
乗算でinteger	overflowが発⽣しうることが判明
:smallest	[(#:user{:side-a	1,	:side-b
23021144,	:side-c	400647858198})]
user> (cuboid-volume #::{:side-a 1
:side-b 23021144
:side-c 400647858198})
ArithmeticException integer overflow clojure.lang.Numbers.throw
IntOverflow (Numbers.java:1526)
integer	overflowしないように関数	*	を	*'	に変更
user> (defn cuboid-volume [{::keys [side-a side-b side-c]}]
(*' side-a side-b side-c))
#'user/cuboid-volume
user> (cuboid-volume #::{:side-a 1
:side-b 23021144
:side-c 400647858198})
9223372036867738512N
デフォルト1000回の試⾏で正常にテストをパス
user> (stest/check `cuboid-volume)
({:spec #object[clojure.spec.alpha$fspec_impl$reify__1215 0x765a
cd43 "clojure.spec.alpha$fspec_impl$reify__1215@765acd43"], :clo
jure.spec.test.check/ret {:result true, :num-tests 1000, :seed 1
505803853835}, :sym user/cuboid-volume})
user> (stest/summarize-results *1)
{:sym user/cuboid-volume}
{:total 1, :check-passed 1}
最終結果
(ns spec-examples.geometry
(:require [clojure.spec.alpha :as s]))
;; specs
(s/def ::length (s/and number? pos?))
(s/def ::side-a ::length)
(s/def ::side-b ::length)
(s/def ::side-c ::length)
(s/def ::cuboid (s/keys :req [::side-a ::side-b ::side-c])
(s/fdef cuboid-volume
:args (s/cat :cuboid ::cuboid)
:ret number?)
;; implementation
(defn cuboid-volume [{::keys [side-a side-b side-c]}]
(*' side-a side-b side-c))
述語(predicate)で仕様が書ける
値に対する制約が柔軟に表現できる
Clojureの動的な性質と親和性が⾮常に⾼い
コンパイル時ではなく実⾏時
REPL駆動開発とプロパティベーストテストで制
約を満たしていることを保証する戦略
漸進的型付け/静的⾔語化とは異なる未来
⾃動プロパティベーストテストが便利
clojure.specを活⽤して
変更に強いClojureコードを書こう
(*> ᴗ •*)ゞ
Vive	les	S-expressions	!
Long	live	S-expressions!
Further	Reading
example	code
lagenorhynque/spec-examples
clojure.spec	vs	core.typed	vs	schema
of cial	site
clojure.spec	-	Rationale	and	Overview
spec	Guide
clojure/clojure	at	clojure-1.9.0-beta1
clojure/spec.alpha
clojure.spec	-	Clojure	v1.9	API
documentation
clojure/core.specs.alpha
clojure/core.typed
plumatic/schema
video
book
Spec-ulation	Keynote	-	Rich	Hickey
"Agility	&	Robustness:	Clojure	spec"	by	Stuart
Halloway
clojure.spec	-	David	Nolen
Clojure	spec	Screencast	Series
Programming	Clojure,	Third	Edition

More Related Content

What's hot

Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
Taku Miyakawa
 
関数型・オブジェクト指向 宗教戦争に疲れたなたに送るGo言語入門
関数型・オブジェクト指向宗教戦争に疲れたなたに送るGo言語入門関数型・オブジェクト指向宗教戦争に疲れたなたに送るGo言語入門
関数型・オブジェクト指向 宗教戦争に疲れたなたに送るGo言語入門
Tadahiro Ishisaka
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
Atsushi Nakamura
 
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考えるGoのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
pospome
 
会社でClojure使ってみて分かったこと
会社でClojure使ってみて分かったこと会社でClojure使ってみて分かったこと
会社でClojure使ってみて分かったこと
Recruit Technologies
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
Koichiro Matsuoka
 
10分でわかるOpenAPI V3
10分でわかるOpenAPI V310分でわかるOpenAPI V3
10分でわかるOpenAPI V3
Kazuchika Sekiya
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
Yoshitaka Kawashima
 
Tackling Complexity
Tackling ComplexityTackling Complexity
Tackling Complexity
Yoshitaka Kawashima
 
Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsug
Masatoshi Tada
 
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意
Yoshitaka Kawashima
 
【NGINXセミナー】 Ingressを使ってマイクロサービスの運用を楽にする方法
【NGINXセミナー】 Ingressを使ってマイクロサービスの運用を楽にする方法【NGINXセミナー】 Ingressを使ってマイクロサービスの運用を楽にする方法
【NGINXセミナー】 Ingressを使ってマイクロサービスの運用を楽にする方法
NGINX, Inc.
 
キメるClojure
キメるClojureキメるClojure
キメるClojure
Yoshitaka Kawashima
 
Spring Security Patterns
Spring Security PatternsSpring Security Patterns
Spring Security Patterns
VMware Tanzu
 
入門core.async
入門core.async入門core.async
入門core.async
sohta
 
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetupこれで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
Masatoshi Tada
 
安全なWebアプリケーションの作り方2018
安全なWebアプリケーションの作り方2018安全なWebアプリケーションの作り方2018
安全なWebアプリケーションの作り方2018
Hiroshi Tokumaru
 
強いて言えば「集約どう実装するのかな、を考える」な話
強いて言えば「集約どう実装するのかな、を考える」な話強いて言えば「集約どう実装するのかな、を考える」な話
強いて言えば「集約どう実装するのかな、を考える」な話
Yoshitaka Kawashima
 
jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界
jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界
jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界
Y Watanabe
 
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptxネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
Shota Shinogi
 

What's hot (20)

Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
 
関数型・オブジェクト指向 宗教戦争に疲れたなたに送るGo言語入門
関数型・オブジェクト指向宗教戦争に疲れたなたに送るGo言語入門関数型・オブジェクト指向宗教戦争に疲れたなたに送るGo言語入門
関数型・オブジェクト指向 宗教戦争に疲れたなたに送るGo言語入門
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
 
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考えるGoのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
 
会社でClojure使ってみて分かったこと
会社でClojure使ってみて分かったこと会社でClojure使ってみて分かったこと
会社でClojure使ってみて分かったこと
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
 
10分でわかるOpenAPI V3
10分でわかるOpenAPI V310分でわかるOpenAPI V3
10分でわかるOpenAPI V3
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
 
Tackling Complexity
Tackling ComplexityTackling Complexity
Tackling Complexity
 
Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsug
 
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意
 
【NGINXセミナー】 Ingressを使ってマイクロサービスの運用を楽にする方法
【NGINXセミナー】 Ingressを使ってマイクロサービスの運用を楽にする方法【NGINXセミナー】 Ingressを使ってマイクロサービスの運用を楽にする方法
【NGINXセミナー】 Ingressを使ってマイクロサービスの運用を楽にする方法
 
キメるClojure
キメるClojureキメるClojure
キメるClojure
 
Spring Security Patterns
Spring Security PatternsSpring Security Patterns
Spring Security Patterns
 
入門core.async
入門core.async入門core.async
入門core.async
 
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetupこれで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
 
安全なWebアプリケーションの作り方2018
安全なWebアプリケーションの作り方2018安全なWebアプリケーションの作り方2018
安全なWebアプリケーションの作り方2018
 
強いて言えば「集約どう実装するのかな、を考える」な話
強いて言えば「集約どう実装するのかな、を考える」な話強いて言えば「集約どう実装するのかな、を考える」な話
強いて言えば「集約どう実装するのかな、を考える」な話
 
jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界
jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界
jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界
 
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptxネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
 

Similar to Spectacular Future with clojure.spec

TypeScript 1.0 オーバービュー
TypeScript 1.0 オーバービューTypeScript 1.0 オーバービュー
TypeScript 1.0 オーバービューAkira Inoue
 
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
Akira Inoue
 
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Akira Inoue
 
Okinawa.rb 第2回勉強会
Okinawa.rb 第2回勉強会Okinawa.rb 第2回勉強会
Okinawa.rb 第2回勉強会
Naoki Takaesu
 
Inside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfesInside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfesTakeshi Komiya
 
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~Akira Inoue
 
var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18
var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18
var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18
Syo Ikeda
 
Pub/Sub model, msm, and asio
Pub/Sub model, msm, and asioPub/Sub model, msm, and asio
Pub/Sub model, msm, and asio
Takatoshi Kondo
 
More Better Nested Set
More Better Nested SetMore Better Nested Set
More Better Nested Setxibbar
 
きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回
Tomoya Kawanishi
 
第四回 JavaScriptから始めるプログラミング2016
第四回 JavaScriptから始めるプログラミング2016第四回 JavaScriptから始めるプログラミング2016
第四回 JavaScriptから始めるプログラミング2016
kyoto university
 
VerilatorとSystemC
VerilatorとSystemCVerilatorとSystemC
VerilatorとSystemC
Mr. Vengineer
 
EWD 3トレーニングコース#19 JavaScriptからGlobalストレジにアクセスする
EWD 3トレーニングコース#19 JavaScriptからGlobalストレジにアクセスするEWD 3トレーニングコース#19 JavaScriptからGlobalストレジにアクセスする
EWD 3トレーニングコース#19 JavaScriptからGlobalストレジにアクセスする
Kiyoshi Sawada
 
Ruby Postgres 2009
Ruby Postgres 2009Ruby Postgres 2009
Ruby Postgres 2009Akio Ishida
 
TypeScript と Visual Studio Code
TypeScript と Visual Studio CodeTypeScript と Visual Studio Code
TypeScript と Visual Studio Code
Akira Inoue
 
C++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みくださいC++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みくださいdigitalghost
 

Similar to Spectacular Future with clojure.spec (20)

TypeScript 1.0 オーバービュー
TypeScript 1.0 オーバービューTypeScript 1.0 オーバービュー
TypeScript 1.0 オーバービュー
 
計算機理論入門09
計算機理論入門09計算機理論入門09
計算機理論入門09
 
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
 
Okinawa.rb 第2回勉強会
Okinawa.rb 第2回勉強会Okinawa.rb 第2回勉強会
Okinawa.rb 第2回勉強会
 
Inside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfesInside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfes
 
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
 
var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18
var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18
var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18
 
Pub/Sub model, msm, and asio
Pub/Sub model, msm, and asioPub/Sub model, msm, and asio
Pub/Sub model, msm, and asio
 
Objc lambda
Objc lambdaObjc lambda
Objc lambda
 
More Better Nested Set
More Better Nested SetMore Better Nested Set
More Better Nested Set
 
きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回
 
第四回 JavaScriptから始めるプログラミング2016
第四回 JavaScriptから始めるプログラミング2016第四回 JavaScriptから始めるプログラミング2016
第四回 JavaScriptから始めるプログラミング2016
 
VerilatorとSystemC
VerilatorとSystemCVerilatorとSystemC
VerilatorとSystemC
 
EWD 3トレーニングコース#19 JavaScriptからGlobalストレジにアクセスする
EWD 3トレーニングコース#19 JavaScriptからGlobalストレジにアクセスするEWD 3トレーニングコース#19 JavaScriptからGlobalストレジにアクセスする
EWD 3トレーニングコース#19 JavaScriptからGlobalストレジにアクセスする
 
Ruby Postgres 2009
Ruby Postgres 2009Ruby Postgres 2009
Ruby Postgres 2009
 
Scala on Hadoop
Scala on HadoopScala on Hadoop
Scala on Hadoop
 
TypeScript と Visual Studio Code
TypeScript と Visual Studio CodeTypeScript と Visual Studio Code
TypeScript と Visual Studio Code
 
C++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みくださいC++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みください
 

More from Kent Ohashi

インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPC
インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPCインターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPC
インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPC
Kent Ohashi
 
Team Geek Revisited
Team Geek RevisitedTeam Geek Revisited
Team Geek Revisited
Kent Ohashi
 
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt TechnologiesScala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
Kent Ohashi
 
Clojureコレクションで探るimmutableでpersistentな世界
Clojureコレクションで探るimmutableでpersistentな世界Clojureコレクションで探るimmutableでpersistentな世界
Clojureコレクションで探るimmutableでpersistentな世界
Kent Ohashi
 
英語学習者のためのフランス語文法入門: フランス語完全理解(?)
英語学習者のためのフランス語文法入門: フランス語完全理解(?)英語学習者のためのフランス語文法入門: フランス語完全理解(?)
英語学習者のためのフランス語文法入門: フランス語完全理解(?)
Kent Ohashi
 
JavaからScala、そしてClojureへ: 実務で活きる関数型プログラミング
JavaからScala、そしてClojureへ: 実務で活きる関数型プログラミングJavaからScala、そしてClojureへ: 実務で活きる関数型プログラミング
JavaからScala、そしてClojureへ: 実務で活きる関数型プログラミング
Kent Ohashi
 
実用のための語源学入門
実用のための語源学入門実用のための語源学入門
実用のための語源学入門
Kent Ohashi
 
メタプログラミング入門
メタプログラミング入門メタプログラミング入門
メタプログラミング入門
Kent Ohashi
 
労働法の世界
労働法の世界労働法の世界
労働法の世界
Kent Ohashi
 
Clojureで作る"simple"なDSL
Clojureで作る"simple"なDSLClojureで作る"simple"なDSL
Clojureで作る"simple"なDSL
Kent Ohashi
 
RDBでのツリー表現入門
RDBでのツリー表現入門RDBでのツリー表現入門
RDBでのツリー表現入門
Kent Ohashi
 
GraphQL入門
GraphQL入門GraphQL入門
GraphQL入門
Kent Ohashi
 
たのしい多言語学習
たのしい多言語学習たのしい多言語学習
たのしい多言語学習
Kent Ohashi
 
Ductモジュール入門
Ductモジュール入門Ductモジュール入門
Ductモジュール入門
Kent Ohashi
 
Clojure REPL: The Good Parts
Clojure REPL: The Good PartsClojure REPL: The Good Parts
Clojure REPL: The Good Parts
Kent Ohashi
 
"Simple Made Easy" Made Easy
"Simple Made Easy" Made Easy"Simple Made Easy" Made Easy
"Simple Made Easy" Made Easy
Kent Ohashi
 
Clojurian Conquest
Clojurian ConquestClojurian Conquest
Clojurian Conquest
Kent Ohashi
 
ClojurianからみたElixir
ClojurianからみたElixirClojurianからみたElixir
ClojurianからみたElixir
Kent Ohashi
 
GraphQL API in Clojure
GraphQL API in ClojureGraphQL API in Clojure
GraphQL API in Clojure
Kent Ohashi
 
法学入門
法学入門法学入門
法学入門
Kent Ohashi
 

More from Kent Ohashi (20)

インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPC
インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPCインターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPC
インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPC
 
Team Geek Revisited
Team Geek RevisitedTeam Geek Revisited
Team Geek Revisited
 
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt TechnologiesScala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
 
Clojureコレクションで探るimmutableでpersistentな世界
Clojureコレクションで探るimmutableでpersistentな世界Clojureコレクションで探るimmutableでpersistentな世界
Clojureコレクションで探るimmutableでpersistentな世界
 
英語学習者のためのフランス語文法入門: フランス語完全理解(?)
英語学習者のためのフランス語文法入門: フランス語完全理解(?)英語学習者のためのフランス語文法入門: フランス語完全理解(?)
英語学習者のためのフランス語文法入門: フランス語完全理解(?)
 
JavaからScala、そしてClojureへ: 実務で活きる関数型プログラミング
JavaからScala、そしてClojureへ: 実務で活きる関数型プログラミングJavaからScala、そしてClojureへ: 実務で活きる関数型プログラミング
JavaからScala、そしてClojureへ: 実務で活きる関数型プログラミング
 
実用のための語源学入門
実用のための語源学入門実用のための語源学入門
実用のための語源学入門
 
メタプログラミング入門
メタプログラミング入門メタプログラミング入門
メタプログラミング入門
 
労働法の世界
労働法の世界労働法の世界
労働法の世界
 
Clojureで作る"simple"なDSL
Clojureで作る"simple"なDSLClojureで作る"simple"なDSL
Clojureで作る"simple"なDSL
 
RDBでのツリー表現入門
RDBでのツリー表現入門RDBでのツリー表現入門
RDBでのツリー表現入門
 
GraphQL入門
GraphQL入門GraphQL入門
GraphQL入門
 
たのしい多言語学習
たのしい多言語学習たのしい多言語学習
たのしい多言語学習
 
Ductモジュール入門
Ductモジュール入門Ductモジュール入門
Ductモジュール入門
 
Clojure REPL: The Good Parts
Clojure REPL: The Good PartsClojure REPL: The Good Parts
Clojure REPL: The Good Parts
 
"Simple Made Easy" Made Easy
"Simple Made Easy" Made Easy"Simple Made Easy" Made Easy
"Simple Made Easy" Made Easy
 
Clojurian Conquest
Clojurian ConquestClojurian Conquest
Clojurian Conquest
 
ClojurianからみたElixir
ClojurianからみたElixirClojurianからみたElixir
ClojurianからみたElixir
 
GraphQL API in Clojure
GraphQL API in ClojureGraphQL API in Clojure
GraphQL API in Clojure
 
法学入門
法学入門法学入門
法学入門
 

Spectacular Future with clojure.spec