Slide 1

Slide 1 text

Ryot a Y a m a d a (Pݴޠͷ ίʔυδΣωϨʔλʔΛ ࡞ͬͯΈΑ͏ The Go gopher was designed by Renée French. Illustrations by tottie

Slide 2

Slide 2 text

GoݴޠͰɺίʔυδΣωϨʔλʔΛ࡞͍ͬͯ·͔͢ʁ

Slide 3

Slide 3 text

GoݴޠͰɺίʔυδΣωϨʔλʔΛ࢖͍ͬͯ·͔͢ʁ

Slide 4

Slide 4 text

Goݴޠʹ͓͚ΔίʔυδΣωϨʔλʔ •gomock •gqlgen •go-swagger •protoc-gen-go •kubebuilder

Slide 5

Slide 5 text

ίʔυੜ੒ͷϝϦοτ •ࣅͨΑ͏ͳίʔυΛԿճ΋ॻ͘ඞཁ͕ͳ͍ 
 →ΤϯδχΞͷϑϥετϨʔγϣϯͷܰݮ •ਓҝతͳϛε(e.g. Typo)ͷ࡟ݮ •։ൃ଎౓͕ૣ͘ͳΔ •୭͕ॻ͍ͯ΋ಉ͡Α͏ͳߏ੒ʹͳΔ 
 →ϓϩδΣΫτશମͱͯ͠ͷอकੑɺՄಡੑͷ޲্

Slide 6

Slide 6 text

ಠࣗͷίʔυδΣωϨʔλʔΛ࡞Γ͍ͨ

Slide 7

Slide 7 text

e := &entity.User { Name: name , NameKana: name_kana , Email: email , Age: age , Address: address , Birthday: birthday , PhoneNumber: phone_number , LastLogin: last_login , is_premium: is_premium , … } ͜ΕΛ࡞Δͷ͕ ΊΜͲ͍͘͞ʂ

Slide 8

Slide 8 text

!"" cm d !"" domai n # !"" entit y # %"" repositor y !"" infr a # !"" mode l # %"" repositor y %"" usecase ͜Ε΋࡞Δͷ͕ ΊΜͲ͍͘͞ʂ

Slide 9

Slide 9 text

https://github.com/riita10069/roche

Slide 10

Slide 10 text

roche skaffold init •APIαʔόʔͷ਽ܗΛੜ੒ͯ͘͠ΕΔ •಺෦࣮૷͸ɺgrapiΛgo getͯ͠ݺͼग़͍ͯ͠Δ͚ͩ https://github.com/izumin5210/grapi

Slide 11

Slide 11 text

roche skaffold all NAME .proto handler repository di_container usecase entity migration f ile

Slide 12

Slide 12 text

ϢʔβʔͷCRUD͢ΔΤϯυϙΠϯτ΄͍ͥ͠ message User { string name = 1 ; string name_kana = 2 ; int64 age = 3 ; string email = 4 ; … } ͜Ε͚ͩ࡞Ε͹ ׬੒ͳͷͩ ϊʔίʔυͷੈք

Slide 13

Slide 13 text

ίʔυੜ੒ͷσϝϦοτ • ίʔυδΣωϨʔλʔ͕ؒҧ͍ͬͯΔͱࢮ͵ • ख࡞ۀͰશͯͷ΋ͷΛ௚͢ͷ͸େม • ઃܭͷมߋ͸Ͱ͖ͳ͍ • DDDΛ࠾༻͍ͨ͠ʁNoSQLΛ࢖͍͍ͨʁrocheͰ͸ແཧ • ࿮૊Έ͔Β֎ΕΔ࣌͸ࣗಈੜ੒͞ΕͨίʔυΛফ͢ • Web APIͰɺentity, Req, DBͷεΩʔϚ͸ࣅͨΑ͏ͳ΋ͷʹͳΔͱ ͍͏ԾઆΛஔ͍͍ͯΔ

Slide 14

Slide 14 text

ίʔυੜ੒ͷϝϦοτ(ମײ) • ࣮ࡍͷͱ͜Ζָʹͳͬͨ • ੜ੒͞Εͨίʔυͷେ෦෼͸ͦͷ··ར༻Ͱ͖Δ • ੜ੒͞ΕͨίʔυΛಡΊ͹ͳΜͱ͔ͳΔ • ෳ਺ਓͰ։ൃͯ͠΋ɺߏ੒͕อͨΕΔ • ϚΠΫϩαʔϏεͳͲͰνʔϜ͕ҧ͏৔߹ʹ΋༗༻͔ʁ(ະݕূ) • ։ൃεϐʔυ΋࣮֬ʹ্͕ͬͨ

Slide 15

Slide 15 text

΋ͬͱޮ཰తͳઃܭ͸ͳ͍ͷ͔

Slide 16

Slide 16 text

΋ͬͱྑ͍ઃܭΛߟ͑Δ • ίʔυδΣωϨʔλʔ͸ϓϩδΣΫτ͝ͱʹࣗ࡞͢Δ΂͖ • ઃܭɺٕज़બఆ͕ίʔυδΣωϨʔλʔʹΑͬͯݻఆ͞Εͨ͘ͳ͍ • ࠷খݶͷ੹຿Λ࣋ͬͨδΣωϨʔλʔ͕υϛϊ౗͠తʹػೳ͢΂͖ • All in OneͷίʔυδΣωϨʔλʔ͸ແବ͕ଟ͍ • ੜ੒͞ΕΔίʔυྔ͕૿͑Ε͹ϛεϚον΍όά΋૿͑Δ

Slide 17

Slide 17 text

࠷খͷ੹຿Λ࣋ͬͨผʑͷπʔϧͰ࣮ݱ͍ͨ͠ handler repository di_container usecase entity migration f ile .proto .pb.go repository _interface

Slide 18

Slide 18 text

গ͠ͷָΛ͢ΔͨΊʹίʔυੜ੒Λ͠Α͏(෍ڭ)

Slide 19

Slide 19 text

https://github.com/dave/jennifer

Slide 20

Slide 20 text

https://github.com/dave/jennifer#readme ੜ੒͍ͨ͠ίʔυΛ؆୯ʹੜ੒͢Δ package mai n import ( "fmt " . "github.com/dave/jennifer/jen " ) func main() { f := NewFile("main" ) f.Func().Id("main").Params().Block ( Qual("fmt", "Println").Call(Lit("Hello, world")) , ) fmt.Printf("%#v", f ) } package mai n import "fmt " func main() { fmt.Println("Hello, world" ) }

Slide 21

Slide 21 text

https://github.com/riita10069/roche/blob/master/pkg/rochectl/gen-sca ff old/gen-usecase.go ϝιουͷ࡞੒ usecaseFile.Func().Params(Id("u").Id(name + "Usecase")).Id("GetByID").Params(Id("id").Int64()).Params(Id("*entity." + name), Error()).Block ( List(Id("e"), Err()).Op(":=") . Id("u").Dot(name+ "Repo").Dot("GetByID").Call(Id("id")) , If ( Err().Op("!=").Nil() , ).Block ( Return(Id("nil"), Err()) , ) , Return(Id("e"), Err()) , ) func (u EnterpriseUsecase) GetByID(id int64) (*entity.Enterprise, error) { e, err := u.EnterpriseRepo.GetByID(id ) if err != nil { return nil, er r } return e, er r }

Slide 22

Slide 22 text

https://github.com/riita10069/roche/blob/master/pkg/rochectl/gen-sca ff old/gen-usecase.go ϝιουͷ࡞੒ usecaseFile.Func().Params(Id("u").Id(name + "Usecase")).Id("GetByID").Params(Id("id").Int64()).Params(Id("*entity." + name), Error()).Block ( List(Id("e"), Err()).Op(":=") . Id("u").Dot(name+ "Repo").Dot("GetByID").Call(Id("id")) , If ( Err().Op("!=").Nil() , ).Block ( Return(Id("nil"), Err()) , ) , Return(Id("e"), Err()) , ) func (u EnterpriseUsecase) GetByID(id int64) (*entity.Enterprise, error) { e, err := u.EnterpriseRepo.GetByID(id ) if err != nil { return nil, er r } return e, er r }

Slide 23

Slide 23 text

https://github.com/riita10069/roche/blob/master/pkg/rochectl/gen-sca ff old/gen-usecase.go ϝιουͷ࡞੒ usecaseFile.Func().Params(Id("u").Id(name + "Usecase")).Id("GetByID").Params(Id("id").Int64()).Params(Id("*entity." + name), Error()).Block ( List(Id("e"), Err()).Op(":=") . Id("u").Dot(name+ "Repo").Dot("GetByID").Call(Id("id")) , If ( Err().Op("!=").Nil() , ).Block ( Return(Id("nil"), Err()) , ) , Return(Id("e"), Err()) , ) func (u EnterpriseUsecase) GetByID(id int64) (*entity.Enterprise, error) { e, err := u.EnterpriseRepo.GetByID(id ) if err != nil { return nil, er r } return e, er r } Id() & ม਺໊ɺؔ਺໊ͳͲ .Ͱܨ͛ΔͱεϖʔεͰܨ͕Δ Params()&Ҿ਺ɺؙׅހɺෳ਺ͷҾ਺͕౉ͤΔ Block()&ϒϩοΫɺ೾ׅހ Dot()&. Call() & Ͱؙׅހ ͦͷଞɺ༧໿ޠ͸ؔ਺͕ଘࡏ͢Δɻ

Slide 24

Slide 24 text

https://github.com/riita10069/roche/blob/master/pkg/rochectl/gen-sca ff old/gen-model.go Structͷ࡞੒ var codes []jen.Cod e var code *jen.Statemen t for _, field := range structAst.Fields.List { for _, nameIdent := range field.Names { code := jen.Id(nameIdent.Name ) // ཁૉͷܕ໊ switch field.Type.(type) { // ผύοέʔδͷܕΛར༻͍ͯ͠Δ৔߹ case *ast.SelectorExpr : selectorExpr, _ := field.Type.(*ast.SelectorExpr ) xIdent, _ := selectorExpr.X.(*ast.Ident ) if xIdent.Name == "protoimpl" { continu e } code.Id(xIdent.Name + "." + selectorExpr.Sel.Name ) // ૊ΈࠐΈ·ͨ͸ύοέʔδ಺ͷܕΛར༻͍ͯ͠Δ৔߹ case *ast.Ident : ident, _ := field.Type.(*ast.Ident ) code.Id(ident.Name ) case *ast.StarExpr : code.Id(nameIdent.Name ) } codes = append(codes, code ) } } f.Type().Id(name).Struct(codes...) type User struct { Id int6 4 Name strin g Age int6 4 }

Slide 25

Slide 25 text

File & string func JenFileToString(f *jen.File) { buf := &bytes.Buffer{ } err := f.Render(buf ) if err != nil { fmt.Println(err.Error() ) os.Exit(1 ) } return buf.Strin g } https://github.com/riita10069/roche/blob/master/pkg/rochectl/ fi le/wrirte- fi le.go ҙਤͨ͠ίʔυ͕ੜ੒Ͱ͖Δ͔ͷϢχοτςετ ࣮ࡍʹϑΝΠϧʹจࣈྻΛॻ͖ࠐΉ

Slide 26

Slide 26 text

String & ϑΝΠϧॻ͖ࠐΈ func makeDirectory (filename string) { paths := strings.Split(filename, "/" ) paths = paths[:len(paths)-1 ] filepath := strings.Join(paths, "/" ) if _, err := os.Stat(filepath); os.IsNotExist(err) { defaultUmask := syscall.Umask(0 ) os.MkdirAll(filepath, 0755 ) os.Chmod(filepath, 0755 ) syscall.Umask(defaultUmask ) } fmt.Println("Execute Make Directory" ) (" ✔ ", filepath ) } func CreateAndWrite(content string, filename string) error { if strings.Contains(filename, "/") { makeDirectory(filename ) } err := ioutil.WriteFile(filename, []byte(content), 0664 ) if err != nil { return errors.New("cannot write" + filename ) } fmt.Println("Execute code generate to following file" ) fmt.Println(" ✔ ", filename ) return ni l } https://github.com/riita10069/roche/blob/master/pkg/rochectl/ fi le/wrirte- fi le.go

Slide 27

Slide 27 text

AST(ந৅ߏจ໦)ͷ࡞੒ func getAst(filePath string) f *ast.File { fset := token.NewFileSet( ) f, err := parser.ParseFile(fset, filePath, nil, parser.Mode(0) ) if err != nil { fmt.Println("cannot parse file, filepath is ", filePath ) fmt.Println(err.Error() ) return ni l } return f } https://github.com/riita10069/roche/blob/master/pkg/rochectl/ast/ fi nd-struct.go

Slide 28

Slide 28 text

͋ΔϑΝΠϧ͔ΒstructͷཁૉΛऔಘ func getAstHash(f *ast.File, structASTMap map[string]*ast.StructType) { for _, decl := range f.Decls { d, ok := decl.(*ast.GenDecl ) if !ok || d.Tok != token.TYPE { continu e } for _, spec := range d.Specs { s, ok := spec.(*ast.TypeSpec ) if !ok { continu e } t, ok := s.Type.(*ast.StructType ) if !ok { continu e } structASTMap[s.Name.Name] = t } } } https://github.com/riita10069/roche/blob/master/pkg/rochectl/ast/ fi nd-struct.go func GetPropertyByStructAst(structAst *ast.StructType) ([]string, []string) { var properties []strin g var propertiesType []strin g for _, field := range structAst.Fields.List { for _, nameIdent := range field.Names { switch field.Type.(type) { case *ast.SelectorExpr : selectorExpr, _ := field.Type.(*ast.SelectorExpr ) xIdent, _ := selectorExpr.X.(*ast.Ident ) if xIdent.Name == "protoimpl" { continu e } properties = append(properties, util.SnakeToLowerCamel(nameIdent.Name) ) propertiesType = append(propertiesType, xIdent.Name ) case *ast.Ident : ident, _ := field.Type.(*ast.Ident ) properties = append(properties, nameIdent.Name ) propertiesType = append(propertiesType, ident.Name ) } } } return properties, propertiesTyp e }

Slide 29

Slide 29 text

JenifferΛ࢖ͬͯɺίʔυδΣωϨʔλΛ࡞ͬͯΈΑ͏