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
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.5k
ベクトル検索のフィルタを用いた機械学習モデルとの統合 / python-meetup-fukuoka-06-vector-attr
monochromegane
3
910
Claude Codeセッション現状確認 2026福岡 / fukuoka-aicoding-00-beacon
monochromegane
4
790
Go言語での実装を通して学ぶLLMファインチューニングの仕組み / fukuokago22-llm-peft
monochromegane
0
300
不確実性下における目的と手段の統合的探索に向けた連続腕バンディットの応用 / iot70_gp_rff_mab
monochromegane
2
550
なめらかなシステムと運用維持の終わらぬ未来 / dicomo2025_coherently_fittable_system
monochromegane
0
46k
ベクトル検索システムの気持ち
monochromegane
38
13k
Go言語での実装を通して学ぶ、高速なベクトル検索を支えるクラスタリング技術/fukuokago-kmeans
monochromegane
1
340
Other Decks in Technology
See All in Technology
その Lambda、8分で 管理者権限まで奪われます
k1nakayama
6
3k
新機種発売前に見直そう!端末移行で再ログインが要るアプリ・要らないアプリは何が違うのか 〜シームレスに再開できる設計と実装〜
zozotech
PRO
0
210
AI に書かせたその API、 “信頼” できますか?
nagix
0
120
おい、エージェントを使って終わらせろ
nwiizo
1
650
【技術的負債conf】事業成長に伴う技術的負債の説明責任とAIによるモニタリング、認知的負債について
i35_267
3
1.7k
幾何アルゴリズムで なめらかなピン操作を / iOSDC Japan 2026 / smoothpin
kazumanagano
0
360
30座EKS, 180次升級淬煉的EKS Upgrade Skill 的歷程
eric8230
0
170
Goodbye ShellScript, Hello File-based App
shunsock
0
160
株式会社シーエーシー エンジニア向け会社紹介資料
cac
0
57k
ソフトウェアDNAとクラウドエージェントのススメ
cloudace
0
110
EventBridge に「合流」はない ― サーバーレスのワークフローを育てるということ / No Join in EventBridge
yusukeshimizu
2
130
品質と信頼性を地続きにする
grimoh
1
760
Featured
See All Featured
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
510
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
420
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
280
The AI Search Optimization Roadmap by Aleyda Solis
aleyda
1
6.2k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.6k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
300
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
35
2.8k
Building Applications with DynamoDB
mza
96
7.2k
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
Practical Orchestrator
shlominoach
192
12k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
KATA
mclloyd
PRO
35
15k
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/
͓ΘΓ