Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Generative Programming in Go
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
monochromegane
June 21, 2015
Technology
7.6k
16
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Generative Programming in Go
GoCon2015発表資料
https://github.com/GoCon/GoCon/blob/master/2015summer.rst
monochromegane
June 21, 2015
More Decks by monochromegane
See All by monochromegane
適応的スパムフィルタのための軽量な類似メッセージカウンタ / jsai2026-adaptive-spam-filter
monochromegane
0
4.2k
ベクトル検索のフィルタを用いた機械学習モデルとの統合 / python-meetup-fukuoka-06-vector-attr
monochromegane
3
800
Claude Codeセッション現状確認 2026福岡 / fukuoka-aicoding-00-beacon
monochromegane
4
580
Go言語での実装を通して学ぶLLMファインチューニングの仕組み / fukuokago22-llm-peft
monochromegane
0
260
不確実性下における目的と手段の統合的探索に向けた連続腕バンディットの応用 / iot70_gp_rff_mab
monochromegane
2
410
なめらかなシステムと運用維持の終わらぬ未来 / dicomo2025_coherently_fittable_system
monochromegane
0
26k
ベクトル検索システムの気持ち
monochromegane
38
13k
Go言語での実装を通して学ぶ、高速なベクトル検索を支えるクラスタリング技術/fukuokago-kmeans
monochromegane
1
310
Go言語でターミナルフレンドリーなAIコマンド、afaを作った/fukuokago20_afa
monochromegane
2
370
Other Decks in Technology
See All in Technology
勉強会企画をアプリで構造化してみた 〜そこで見えた、AIとの付き合い方〜 / I've structured a study group plan using an app.
pauli
0
330
事業価値を⽣み出すSREへ SREが担うべき意思決定の5層
kenta_hi
2
2.2k
フルカイテン株式会社 エンジニア向け採用資料
fullkaiten
0
11k
Claude Code 珍プレー好プレー
shinyasaita
0
290
テスト設計の本質を改めて考えてみる~生成AIを活用する時代だからこそ、作ったテストの説明性を高めよう~
yamasaki696
1
390
AI Driven AI Governance
pict3
0
250
どうして今サーバーサイドKotlinを選択したのか
nealle
0
210
なぜ人は自分のプロジェクトを 「なんちゃってアジャイル」と 自嘲するのか
kozotaira
0
260
なぜ私たちのSREプラクティスはなかなか機能しないのか 〜システムより先に組織を見る〜 / Why our SRE practices aren't really working
vtryo
2
2.6k
Control Planeで育てるBtoB SaaSの認証基盤 - SRE NEXT 2026
pokohide
1
1.6k
プライバシー保護の理論と実践
lycorptech_jp
PRO
1
250
Why is RC4 still being used?
tamaiyutaro
0
310
Featured
See All Featured
Building Flexible Design Systems
yeseniaperezcruz
330
40k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
Ethics towards AI in product and experience design
skipperchong
2
320
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
75k
Optimising Largest Contentful Paint
csswizardry
37
3.8k
Docker and Python
trallard
47
3.9k
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
410
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
890
Tell your own story through comics
letsgokoyo
1
990
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
260
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
350
Become a Pro
speakerdeck
PRO
31
6k
Transcript
Generative Programming in Go - GoCon 2015 summer - @monochromegane
MIYAKE Yusuke (@monochromegane)
GMO Pepabo, Inc.
♕ 3 GitHub Awards Go ranking in Japan :)
Generative Programming
ੜతͳ Programming
Generator + Template parse generate Parser Your App Generated Code
AST Code use
Attention, please.
✘ Generics Meta programming Dynamic generation
parse Parser AST Code Go provides
Generator + Template generate Your App Generated Code use We
implement
argen ActiveRecord Generator
GoͰDataMapperͰͳ͘ ActiveRecordϥΠΫʹ DBૢ࡞͢Δ
by Generative programming
ߏମʹ`+AR`ϚʔΧʔΛ͚ͭΔ //+AR type User struct { Id int Name string
Age int }
ੜ͢Δ $ argen main.go $ tree . !"" main.go #""
main_gen.go
ߏମʹARϥΠΫͳϝιου͕ Ճ͞ΕΔ db, _ := sql.Open("sqlite3", "foo.db") Use(db) u :=
User{Name: "test", Age: 20} u.Save() //// INSERT INTO users (name, age) VALUES (?, ?); [test 20] User{}.Where("name", "test").And("age", ">", 20).Query() //// SELECT users.id, users.name, users.age FROM users WHERE name = ? AND age > ?; [test 20]
Generative Programming ͍υίϩ
Case.1 Generics
ҙͷߏମʹڞ௨ͷϝιου Λ࣋ͨͤͭͭɺݸʑͷܕΛѻ͏ var u User u = User{}.First() var h
Hoge h = Hoge{}.First()
ҙͷߏମʹڞ௨ͷϝιου Λ࣋ͨͤͭͭɺݸʑͷܕΛѻ͏ var u User u = User{}.First() var h
Hoge h = Hoge{}.First() • Ωϟετͨ͘͠ͳ͍ • Genericsͷग़൪
ᵆᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᵪᴸᴸᵊ ᴺwhy no generics golangɹ ᴺݕࡧᴺ ᵎᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᵲᴸᴸᵒ
Let’s generate !
ߏମʹରͯ͠ݸʑͷܕΛѻ͏ ڞ௨ͷϝιουΛੜ
func (m User) First() (*User, error) { return m.newRelation().First() }
func (r *UserRelation) First() (*User, error) { return r.Order("id", "ASC").Limit(1).QueryRow() } func (r *UserRelation) QueryRow() (*User, error) { row := &User{} err := r.Relation.QueryRow( row.fieldPtrsByName( r.Relation.GetColumns())...) if err != nil { return nil, err } return row, nil }
see also: clipperhouse/gen // +gen slice:"All" type Person struct {
Name string Present bool } gang := PersonSlice { {"Alice", true}, {"Bob", false}, {"Carly", true}, } here := func(p Person) bool { return p.Present } gang.All(here) // => false, Bob didn't make it
Case.2 Performance
ϦϑϨΫγϣϯΛͬͨ൚༻ੑ ύϑΥʔϚϯεͱҾ͖͑ // Useful! but... var u User db.First(&u)
ϕϯνϚʔΫ // read SomeFunc(s.F) SomeFunc(reflect.ValueOf(s).FieldByName("F").Int()) // write s.F = 100
reflect.ValueOf(&s).Elem().FieldByName("F").SetInt(100) $ go test -benchmem -bench . • Mac OSX(10.10.3) • CPU: 2.5GHz Core i5(2Core) • Memory: 8GB • Go: 1.4.2
ߏମϑΟʔϧυʹର͢ΔΞΫηε time Alloced Bytes Allocs read field 0.38 ns 0
B 0 allocs reflect 246 ns 16 B 2 allocs write field 0.36 ns 0 B 0 allocs reflect 199 ns 8 B 1 allocs
ෳͷߏମϑΟʔϧυʹର͢ΔΞΫηε time Alloced Bytes Allocs read field 0.36 ns 0
B 0 allocs reflect 583 ns 88 B 2 allocs write field 0.37 ns 0 B 0 allocs reflect 277 ns 8 B 1 allocs
Let’s generate !
ߏମʹରͯ͠ϑΟʔϧυใ औಘ༻ϝιουΛੜ
func (m *User) fieldValueByName(name string) interface{} { switch name {
case "id", "users.id": return m.Id case "name", "users.name": return m.Name case "age", "users.age": return m.Age default: return "" } } func (m *User) fieldPtrByName(name string) interface{} { switch name { case "id", "users.id": return &m.Id case "name", "users.name": return &m.Name case "age", "users.age": return &m.Age default: return nil } }
see also: pquerna/ffjson //go:generate ffjson $GOFILE type Foo struct {
Bar string } f := Foo{"bar"} b, _ := json.Marshal(f) fmt.Printf("%s\n", string(b)) // => {"Bar":"bar"} https://github.com/pquerna/ffjson
Case.3 DSL
ҙͷߏମͷڞ௨ϝιου هड़༰͕ʹͳΓ͕ͪ // far from the DSL... func (u *User)
BeforeUpdate() (err error) { if u.Name != "abc"{ return fmt.Errorf("%s is invalid name.", u.Name) } if u.Age > 20 { return fmt.Errorf("%d is invalid age.", u.Age) } return nil }
Let’s generate !
ϝιου໊/ίϝϯτ/λά͔Β ఆٛΛิͯ͠ੜ
func (u User) validatesName() ar.Rule { return ar.MakeRule().Format().With("abc").OnCreate() } func
(u User) validatesAge() ar.Rule { return ar.MakeRule().Numericality().OnlyInteger().LessThan(20) } rules := map[string]*ar.Validation{ "name": m.validatesName().Rule(), "age": m.validatesAge().Rule(), } for name, rule := range rules { if ok, errs := ar.NewValidator(rule).On(on).IsValid(m.fieldValueByName(name)); !ok { result = false errors.SetErrors(name, errs) } } >
Case. Bad
ͳΜͰGenerate
• ϝιουͷڞ௨Խɺଟଶੑͷ࣮ݱͳͲߏମͷຒࠐ (ҕৡ)interfaceΛͬͯΔ͖ • http://go-talks.appspot.com/github.com/lestrrat/ go-slides/2014-yapcasia-go-for-perl-mongers/ main.slide#27 • http://blog.monochromegane.com/blog/ 2014/03/23/struct-implementaion-patterns-in-
golang/ • Generate࣮ଆར༻ଆҰख͔͔ؒΔɺෳࡶ ʹͳΓ͕ͪɻGenerateͰΔཧ༝͕આ໌Ͱ͖ͳ͍ͷ Ͱ͋Ε͏͖Ͱͳ͍
Tips
ίϚϯυϥΠϯ/go generate ͷ྆ํʹରԠ͢Δ
from := os.Getenv("GOFILE") if from == "" { if len(args)
> 0 { from = args[0] } else { os.Exit(1) } } $ argen main.go // go:generate argen
defineΛͬͯ templateΛׂཧ͢Δ
{{template "Relation" .}} {{define "Relation"}} type {{.Name}}Relation struct { src
*{{.Name}} *ar.Relation } {{end}} func (t Template) toDefine() string { return fmt.Sprintf("{{define \"%s\"}}%s{{end}}\n", t.Name, t.Text) } var relation = &Template{ Name: "Relation", Text: ` type {{.Name}}Relation struct { src *{{.Name}} *ar.Relation }`
templateͰ ࣗಈܗͱ ΦʔτΠϯϙʔτ
func writeWithFormat(file, template string, structs structs) ([]byte, error) { var
b bytes.Buffer w := bufio.NewWriter(&b) write(w, template, structs) w.Flush() formatted, err := imports.Process(file, b.Bytes(), nil) if err != nil { return nil, err } return formatted, nil } func write(w io.Writer, tplText string, structs structs) error { t := template.New("t") t.Funcs(template.FuncMap{}) tpl := template.Must(t.Parse(tplText)) if err := tpl.Execute(w, structs); err != nil { return err } return nil }
ςετੜʹ ରͯ͠ߦ͏
//go:generate go run ../cmd/argen/main.go package tests import "github.com/monochromegane/argen" //+AR type
User struct { Name string Age int } $ go generate && go test ./...
એ ϖύϘͰΤϯδχΞΛืू͍ͯ͠·͢ɻ ڞʹαʔϏεΛੜΈग़͠ҭͯͯ͘ΕΔ৽͍ؒ͠ Λ͍ͬͯ·͢ɻ http://pepabo.com/recruit/career/engineer/
͓ΘΓ