Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
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
Go言語とトイモデルで学ぶTransformerの気持ち / fukuokago23-transformer
monochromegane
0
210
適応的スパムフィルタのための軽量な類似メッセージカウンタ / jsai2026-adaptive-spam-filter
monochromegane
0
5.4k
ベクトル検索のフィルタを用いた機械学習モデルとの統合 / python-meetup-fukuoka-06-vector-attr
monochromegane
3
910
Claude Codeセッション現状確認 2026福岡 / fukuoka-aicoding-00-beacon
monochromegane
4
780
Go言語での実装を通して学ぶLLMファインチューニングの仕組み / fukuokago22-llm-peft
monochromegane
0
300
不確実性下における目的と手段の統合的探索に向けた連続腕バンディットの応用 / iot70_gp_rff_mab
monochromegane
2
510
なめらかなシステムと運用維持の終わらぬ未来 / dicomo2025_coherently_fittable_system
monochromegane
0
44k
ベクトル検索システムの気持ち
monochromegane
38
13k
Go言語での実装を通して学ぶ、高速なベクトル検索を支えるクラスタリング技術/fukuokago-kmeans
monochromegane
1
330
Other Decks in Technology
See All in Technology
スクラムで身についていた動き方を、XPで捉え直してみた
codmoninc
PRO
1
350
The Agent Builder Loop from Daily Work to OSS
minorun365
PRO
3
120
Claude in Chrome 入門 / Introduction to Claude in Chrome
cielo1985
0
150
AIに丸投げしないトイル削減 / Eliminating Toil Without Leaving It All to AI
kohbis
4
1.1k
ASTを使って影響範囲を特定する
nealle
0
140
DEFCON34-Write-up_HYCu-MYCu
daikiokazaki
0
140
AIで仕事のやり方を変える
matsu7874
3
1k
GuardDuty 検知対応を DevOps Agent で効率化しようとしている話 / GuardDuty Investigations with DevOps Agent
masahirokawahara
1
350
生成AIのテナント制御とシャドーMCP対策 | AIを"止めずに"、情報を守る
yukun
0
140
From Vanilla Kubernetes to a Batteries-Included Platform: Developer Experience at 1,300+ Clusters
yosshi_
0
680
深夜のクラウド懺悔室 1:29:300 or 1:0:0
kazzpapa3
1
230
AIで開発は速くなったのに、なぜ現場は楽にならないのか 〜あなたの組織のボトルネックを突き止めるワークショップ〜
jacopen
1
310
Featured
See All Featured
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
430
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
540
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
240
Scaling GitHub
holman
464
140k
Designing Powerful Visuals for Engaging Learning
tmiket
1
540
Docker and Python
trallard
47
4.2k
Google's AI Overviews - The New Search
badams
0
1.6k
Building Flexible Design Systems
yeseniaperezcruz
330
41k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.5k
Abbi's Birthday
coloredviolet
3
9.9k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
270
Heart Work Chapter 1 - Part 1
lfama
PRO
9
36k
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/
͓ΘΓ