Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015
How To Structure Go Applications - Paul Bellamy - Codemotion Milan 2016
-
Upload
codemotion -
Category
Technology
-
view
213 -
download
4
Transcript of How To Structure Go Applications - Paul Bellamy - Codemotion Milan 2016
How To Structure Go ApplicationsPaul Bellamy
MILAN 25-26 NOVEMBER 2016
HOW BIG IS YOUR APPLICATION?
GO DIFFERENCES
META
package privacy
type private struct{}
type Public struct {
PublicField string
privateField string
}
IS GO AN OBJECT-ORIENTED LANGUAGE?
Go FAQ
IS GO AN OBJECT-ORIENTED LANGUAGE? YES AND NO.
Go FAQ
CAR
FIAT
FIAT
CAR type Fiat struct {
Car
w Warranty
}
type Fiat struct {
Car
w Warranty
}
type Car struct{}
func (c Car) MarshalJSON() ([]byte, error) {
…
}
~/GOPATH
FRAMEWORKS
# Get 'revel' framework and command
$ go get github.com/revel/cmd/revel
# Create a new app
$ revel new github.com/paulbellamy/myapp
# Run revel application
$ revel run github.com/paulbellamy/myapp
myapp/ App root
app/ App sources
controllers/ App controllers
init.go Interceptor registration
models/ App domain models
routes/ Reverse routes (generated code)
views/ Templates
tests/ Test suites
conf/ Configuration files
app.conf Main configuration file
routes Routes definition
messages/ Message files
WHAT WEAVE TRIED
MVC
myapp/ App root
app/ App sources
controllers/ App controllers
models/ App domain models
views/ Templates
public/ Public assets
myapp/ App root
app/ App sources
controllers/ App controllers
models/ App domain models
views/ Templates
public/ Public assets
lib/ Other stuff ???
myapp/ App root
app/ App sources
controllers/ App controllers
models/ App domain models
views/ Templates
public/ Public assets
lib/ Other stuff ???
generate_certificates_tool.go
myapp/ App root
app/ App sources
controllers/ App controllers
models/ App domain models
views/ Templates
public/ Public assets
lib/ Other stuff ???
generate_certificates_tool.go
uuid.go
myapp/ App root
app/ App sources
controllers/ App controllers
models/ App domain models
views/ Templates
public/ Public assets
lib/ Other stuff ???
generate_certificates_tool.go
uuid.go
conn_with_read_timeout.go
myapp/ App root
app/ App sources
controllers/ App controllers
models/ App domain models
views/ Templates
public/ Public assets
lib/ Other stuff ???
generate_certificates_tool.go
uuid.go
conn_with_read_timeout.go
max_bytes_reader.go
myapp/ App root
app/ App sources
controllers/ App controllers
models/ App domain models
views/ Templates
public/ Public assets
lib/ Other stuff ???
generate_certificates_tool.go
uuid.go
conn_with_read_timeout.go
max_bytes_reader.go
time.go
myapp/ App root
myapp.go App binary
app/ App sources
controllers/ App controllers
models/ App domain models
views/ Templates
public/ Public assets
lib/ Other stuff ???
generate_certificates_tool.go
uuid.go
conn_with_read_timeout.go
max_bytes_reader.go
myapp/ App root
myapp.go App binary
app/ App sources
controllers/ App controllers
models/ App domain models
views/ Templates
public/ Public assets
lib/ Other stuff ???
generate_certificates_tool.go
uuid.go
conn_with_read_timeout.go
max_bytes_reader.go
myapp/ App root
myapp.go App binary
app/ App sources
controllers/ App controllers
models/ App domain models
views/ Templates
public/ Public assets
lib/ Other stuff ???
generate_certificates_tool.go
uuid.go
conn_with_read_timeout.go
max_bytes_reader.go
myapp/ App root
app/ App sources
controllers/ App controllers
users_controller.go
models/ App domain models
views/ Templates
import "github.com/myaccount/myapp/app/controllers"
controllers.UsersController
GROUP-BY-MODULE
scope/ App root
app/ Runs “in the cloud”
probe/ Runs in the users’s cluster
common/ Shared code between app and probe
xfer/ Defines the communication protocol
scope/ App root
app/ Runs “in the cloud”
probe/ Runs in the users’s cluster
common/ Shared code between app and probe
xfer/ Defines the communication protocol
scope/ App root
app/ Runs “in the cloud”
probe/ Runs in the users’s cluster
common/ Shared code between app and probe
xfer/ Defines the communication protocol
scope/ App root
app/ Runs “in the cloud”
probe/ Runs in the users’s cluster
common/ Shared code between app and probe
xfer/ Defines the communication protocol
BEST PRACTICE
DOMAIN
DOMAIN
ADAPTERS
DOMAIN
ADAPTERS
BINARY
DOMAIN
ADAPTERS
BINARY
users/ App root
user.go
organization.go
errors.go
cmd/ App binaries
api/ HTTP API
emailer/ Email providers
oauth/ OAuth Providers
db/ App database(s)
users/ App root
README.md
Dockerfile
src/ Top-level container for go files
user.go
organization.go
errors.go
cmd/ App binaries
api/ HTTP API
emailer/ Email providers
oauth/ OAuth Providers
db/ App database(s)
// Without src/ directory
import "github.com/paulbellamy/users"
t := users.Organization{}
// Without src/ directory
import "github.com/paulbellamy/users"
t := users.Organization{}
// With src/ directory
import users “github.com/paulbellamy/users/src"
t := users.Organization{}
users/ App root
user.go
organization.go
errors.go
cmd/ App binaries
api/ HTTP API
emailer/ Email providers
oauth/ OAuth Providers
db/ App database(s)
users/ App root
add_user_to_organization.go
user.go
organization.go
errors.go
cmd/ App binaries
api/ HTTP API
emailer/ Email providers
oauth/ OAuth Providers
db/ App database(s)
// add_user_to_organization.go
package users
func AddUserToOrg(
db DB, email Emailer, userID, orgID string,
) error {
u, err := db.FindUser(userID) // make sure they exist
o, err := db.FindOrg(orgID)
db.AddUserToOrg(userID, orgID)
email.SendWelcomeEmail(u, o)
}
package users
type DB interface {
FindUser(userID string) (User, error)
FindOrg(orgID string) (Organization, error)
AddUserToOrg(userID, orgID string) error
}
type Emailer interface {
SendWelcomeEmail(User, Organization) error
}
users/ App root
add_user_to_organization.go
user.go
organization.go
errors.go
cmd/ App binaries
api/ HTTP API
emailer/ Email providers
smtp.go SMTP email provider
oauth/ OAuth Providers
db/ App database(s)
package emailer
type SMTP struct {
server string
}
package emailer
import "github.com/paulbellamy/users"
type SMTP struct {
server string
}
package emailer
import "github.com/paulbellamy/users"
type SMTP struct {
server string
}
func (s SMTP) SendWelcomeEmail(
u users.User, o users.Organization,
) error {
return errors.New(“TODO”)
}
users/ App root
add_user_to_organization.go
user.go
organization.go
errors.go
cmd/ App binaries
api/ HTTP API
http.go
emailer/ Email providers
smtp.go SMTP email provider
oauth/ OAuth Providers
db/ App database(s)
package api
import "github.com/paulbellamy/users"
import "net/http"
type HTTP struct {
DB users.DB
Emailer users.Emailer
}
…
…
func (h HTTP) ServeHTTP(
w http.ResponseWriter, r *http.Request,
) {
err := users.AddUserToOrganization(
h.DB, h.Emailer,
r.FormValue(“user_id”), r.FormValue(“org_id”),
)
}
…
func (h HTTP) ServeHTTP(
w http.ResponseWriter, r *http.Request,
) {
err := users.AddUserToOrganization(
h.DB, h.Emailer,
r.FormValue(“user_id”), r.FormValue(“org_id”),
)
}
…
func (h HTTP) ServeHTTP(
w http.ResponseWriter, r *http.Request,
) {
err := users.AddUserToOrganization(
h.DB, h.Emailer,
r.FormValue(“user_id”), r.FormValue(“org_id”),
)
}
…
func (h HTTP) ServeHTTP(
w http.ResponseWriter, r *http.Request,
) {
err := users.AddUserToOrganization(
h.DB, h.Emailer,
r.FormValue(“user_id”), r.FormValue(“org_id”),
)
}
users/ App root
add_user_to_organization.go
user.go
organization.go
errors.go
cmd/ App binaries
users/
main.go
api/ HTTP API
emailer/ Email providers
oauth/ OAuth Providers
db/ App database(s)
# Get 'revel' framework and command
$ go get github.com/revel/cmd/revel
# Create a new app
$ revel new github.com/paulbellamy/myapp
# Run revel application
$ revel run github.com/paulbellamy/myapp
users/ App root
add_user_to_organization.go
user.go
organization.go
errors.go
cmd/ App binaries
users/
main.go
api/ HTTP API
emailer/ Email providers
oauth/ OAuth Providers
db/ App database(s)
// cmd/users/main.go
package main
func main() {
// cmd/users/main.go
package main
import “net/http”
func main() {
http.ListenAndServe(“:8080”, a)
// cmd/users/main.go
package main
import “github.com/paulbellamy/users/api”
import “net/http”
func main() {
a := api.HTTP{Emailer: e, DB: d}
http.ListenAndServe(“:8080”, a)
// cmd/users/main.go
package main
import “github.com/paulbellamy/users/emailer”
import “github.com/paulbellamy/users/api”
import “net/http”
func main() {
e := emailer.SMTP{server: “smtp://mailcatcher.local”}
a := api.HTTP{db: d, emailer: e}
http.ListenAndServe(“:8080”, a)
// cmd/users/main.go
package main
import “github.com/paulbellamy/users/emailer”
import “github.com/paulbellamy/users/db”
import “github.com/paulbellamy/users/api”
import “net/http”
func main() {
e := emailer.SMTP{server: “smtp://mailcatcher.local”}
d := db.New(databaseURL)
a := api.HTTP{db: d, emailer: e}
http.ListenAndServe(“:8080”, a)
// cmd/users/main.go
package main
import “github.com/paulbellamy/users/emailer”
import “github.com/paulbellamy/users/db”
import “github.com/paulbellamy/users/api”
import “net/http”
func main() {
e := emailer.SMTP{server: “smtp://mailcatcher.local”}
d := db.New(databaseURL)
a := api.HTTP{db: d, emailer: e}
http.ListenAndServe(“:8080”, a)
# Build our binary ready for deployment
$ go build github.com/paulbellamy/users/cmd/users
# Run our app
$ ./users
users/ App root
cmd/ App binaries
api/ HTTP API
emailer/ Email providers
oauth/ OAuth Providers
db/ App database(s)
mocks/ Testing mocks
emailer.go Mock emailer
db.go Mock db
users/ App root
add_user_to_organization.go
user.go
organization.go
errors.go
cmd/ App binaries
users-server/ Server binary
users-client/ Client binary
api/ HTTP API
emailer/ Email providers
oauth/ OAuth Providers
db/ App database(s)
users/ App root
add_user_to_organization.go
user.go
organization.go
errors.go
cmd/ App binaries
api/ HTTP API
emailer/ Email providers
oauth/ OAuth Providers
db/ App database(s)
SOCIALS
TWITTER: @PYRHHO GITHUB: PAULBELLAMY