Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go Pattern Design

Go Pattern Design

LINE Developers Thailand

September 06, 2022
Tweet

More Decks by LINE Developers Thailand

Other Decks in Technology

Transcript

  1. Go Pattern Design


    Mic Pantakan Ketbamrung

    View full-size slide

  2. • Hexagonal Architecture


    • Port and Adapters pattern


    • Example
    Agenda

    View full-size slide

  3. type cart struct{}



    func (c *cart) checkout() (string, error) {


    // do something before update inventory...


    body := strings.NewReader(`{


    "id": "line_sticker_001",


    "quantity": -1


    }`)


    res, _ := http.Post("https://line.me/myshop/v1/inventory",


    "application/json",


    body)


    return res.Status, nil


    }
    Checkout

    View full-size slide

  4. Matías Varela
    “Before writing the first line of code, one may ask:


    How should I organize the project? or, Which component should I write first?.


    If these questions are difficult to answer is because you are not following a
    software architecture pattern.”
    https://medium.com/@matiasvarela/hexagonal-architecture-in-go-cfd4e436faa3

    View full-size slide

  5. Port and Adapters

    ( A.K.A Hexagonal Architecture )



    The hexagonal architecture was defined by Alistair Cockburn in 2005

    View full-size slide

  6. Clean Architecture

    View full-size slide

  7. Port and Adapters

    View full-size slide

  8. Driver

    • Usb C


    Driven

    • 3.5 jack
    Port
    https://medium.com/@matiasvarela/hexagonal-architecture-in-go-cfd4e436faa3

    View full-size slide

  9. Adapters
    Driver


    • Usb C


    Driven


    • 3.5 jack
    https://medium.com/@matiasvarela/hexagonal-architecture-in-go-cfd4e436faa3

    View full-size slide

  10. Dependency Injection
    • Able to change easily
    https://medium.com/@matiasvarela/hexagonal-architecture-in-go-cfd4e436faa3

    View full-size slide

  11. type macBook struct{}


    func (*MacBook) chargeWithUsbC() {


    fmt.Println("MacBook is charging")


    }


    type person struct{}


    func (*person) charge(laptop macBook) {


    laptop.chargeWithUsbC()


    }


    func main() {


    person := &person{}


    myMacBook := macBook{}


    person.charge(myMacBook)


    }


    Comparing
    type usbC interface {


    chargeWithUsbC()


    }


    type macBook struct{}


    func (*macBook) chargeWithUsbC() {


    fmt.Println("MacBook is charging")


    }


    type person struct{}


    func (*person) charge(u usbC) {


    u.chargeWithUsbC()


    }


    func main() {


    person := &person{}


    myMacBook := &macBook{}


    person.charge(myMacBook)


    }

    View full-size slide

  12. type macBook struct{}


    func (*MacBook) chargeWithUsbC() {


    fmt.Println("MacBook is charging")


    }


    type person struct{}


    func (*person) charge(laptop macBook) {


    laptop.chargeWithUsbC()


    }


    func main() {


    person := &person{}


    myMacBook := macBook{}


    person.charge(myMacBook)


    }


    Comparing

    View full-size slide

  13. Comparing
    type usbC interface {


    chargeWithUsbC()


    }


    type macBook struct{}


    func (*macBook) chargeWithUsbC() {


    fmt.Println("MacBook is charging")


    }


    type person struct{}


    func (*person) charge(u usbC) {


    u.chargeWithUsbC()


    }


    func main() {


    person := &person{}


    myMacBook := &macBook{}


    person.charge(myMacBook)


    }

    View full-size slide

  14. type usbC interface {


    chargeWithUsbC()


    }


    type macBook struct{}


    func (*macBook) chargeWithUsbC() {


    fmt.Println("MacBook is charging")


    }


    type person struct{}


    func (*person) charge(u usbC) {


    u.chargeWithUsbC()


    }


    func main() {


    person := &person{}


    myMacBook := &macBook{}


    person.charge(myMacBook)


    }
    Port

    View full-size slide

  15. type usbC interface {


    chargeWithUsbC()


    }


    type macBook struct{}


    func (*macBook) chargeWithUsbC() {


    fmt.Println("MacBook is charging")


    }


    type person struct{}


    func (*person) charge(u usbC) {


    u.chargeWithUsbC()


    }


    func main() {


    person := &person{}


    myMacBook := &macBook{}


    person.charge(myMacBook)


    }
    Port

    View full-size slide

  16. type usbC interface {


    chargeWithUsbC()


    }


    type macBook struct{}


    func (*macBook) chargeWithUsbC() {


    fmt.Println("MacBook is charging")


    }


    type person struct{}


    func (*person) charge(u usbC) {


    u.chargeWithUsbC()


    }


    func main() {


    person := &person{}


    myMacBook := &macBook{}


    person.charge(myMacBook)


    }
    Port

    View full-size slide

  17. type usbC interface {


    chargeWithUsbC()


    }


    type macBook struct{}


    func (*macBook) chargeWithUsbC() {


    fmt.Println("MacBook is charging")


    }


    type person struct{}


    func (*person) charge(u usbC) {


    u.chargeWithUsbC()


    }


    func main() {


    person := &person{}


    myMacBook := &macBook{}


    person.charge(myMacBook)


    }
    Port

    View full-size slide

  18. type iPhone struct{}


    func (*iPhone) chargeWithLightingPort() {


    fmt.Println("iPhone is charging")


    }


    Port

    View full-size slide

  19. type iPhone struct{}


    func (*iPhone) chargeWithLightingPort() {


    fmt.Println("iPhone is charging")


    }


    type lightingToUsbC struct {


    iPhone *iPhone


    }


    func (*lightingToUsbC) chargeWithUsbC() {


    l.iPhone.chargeWithLightingPort()


    }


    Adapters

    View full-size slide

  20. type usbC interface {


    chargeWithUsbC()


    }



    type iPhone struct{}


    func (*iPhone) chargeWithLightingPort() {


    fmt.Println("iPhone is charging")


    }


    type lightingToUsbC struct {


    iPhone *iPhone


    }


    func (l *lightingToUsbC) chargeWithUsbC() {


    l.iPhone.chargeWithLightingPort()


    }


    func main() {


    person := &person{}


    myPhone := &lightingToUsbC{&iPhone{}}


    person.charge(myPhone)


    }


    Port & Adapter

    View full-size slide

  21. type cart struct{}



    func (c *cart) checkout() (string, error) {


    // do something before update inventory...


    body := strings.NewReader(`{


    "id": "line_sticker_001",


    "quantity": -1


    }`)


    res, _ := http.Post("https://line.me/myshop/v1/inventory",


    "application/json",


    body)


    return res.Status, nil


    }
    cart.go

    View full-size slide

  22. func Test_CheckoutSuccess(t *testing.T) {


    testCart := cart{}


    status, _ := testCart.checkout()


    want := "200 OK"


    if status != want {


    t.Errorf("status should be %s but got %s", want, status)


    }


    }


    cart_test.go

    View full-size slide

  23. func Test_CheckoutSuccess(t *testing.T) {


    testCart := cart{}


    status, _ := testCart.checkout()


    want := "200 OK"


    if status != want {


    t.Errorf("status should be %s but got %s", want, status)


    }


    }


    cart_test.go

    View full-size slide

  24. Implementation

    View full-size slide

  25. type httpClient interface {


    Post(url, contentType string, body io.Reader) (*http.Response, error)


    }


    type cart struct {


    httpClient


    }


    func (c *cart) checkout() string {


    // do something before update inventory...


    body := strings.NewReader(`{


    "id": "line_sticker_001",


    "quantity": -1


    }`)


    res, _ := c.Post("https://line.me/myshop/v1/inventory",


    "application/json",


    body)


    return res.Status


    }


    func main() {


    cli := http.DefaultClient


    cart := &cart{cli}


    cart.checkout()


    }
    cart.go

    View full-size slide

  26. type httpClient interface {


    Post(url, contentType string, body io.Reader) (*http.Response, error)


    }


    type cart struct {


    httpClient


    }


    func (c *cart) checkout() string {


    // do something before update inventory...


    body := strings.NewReader(`{


    "id": "line_sticker_001",


    "quantity": -1


    }`)


    res, _ := c.Post("https://line.me/myshop/v1/inventory",


    "application/json",


    body)


    return res.Status


    }


    func main() {


    cli := http.DefaultClient


    cart := &cart{cli}


    cart.checkout()


    }
    cart.go

    View full-size slide

  27. type httpClient interface {


    Post(url, contentType string, body io.Reader) (*http.Response, error)


    }


    type cart struct {


    httpClient


    }


    func (c *cart) checkout() string {


    // do something before update inventory...


    body := strings.NewReader(`{


    "id": "line_sticker_001",


    "quantity": -1


    }`)


    res, _ := c.Post("https://line.me/myshop/v1/inventory",


    "application/json",


    body)


    return res.Status


    }


    func main() {


    cli := http.DefaultClient


    cart := &cart{cli}


    cart.checkout()


    }
    cart.go

    View full-size slide

  28. type httpClient interface {


    Post(url, contentType string, body io.Reader) (*http.Response, error)


    }


    type cart struct {


    httpClient


    }


    func (c *cart) checkout() string {


    // do something before update inventory...


    body := strings.NewReader(`{


    "id": "line_sticker_001",


    "quantity": -1


    }`)


    res, _ := c.Post("https://line.me/myshop/v1/inventory",


    "application/json",


    body)


    return res.Status


    }


    func main() {


    cli := http.DefaultClient


    cart := &cart{cli}


    cart.checkout()


    }
    cart.go

    View full-size slide

  29. type httpClient interface {


    Post(url, contentType string, body io.Reader) (*http.Response, error)


    }


    type cart struct {


    httpClient


    }


    func (c *cart) checkout() string {


    // do something before update inventory...


    body := strings.NewReader(`{


    "id": "line_sticker_001",


    "quantity": -1


    }`)


    res, _ := c.Post("https://line.me/myshop/v1/inventory",


    "application/json",


    body)


    return res.Status


    }


    func main() {


    cli := http.DefaultClient


    cart := &cart{cli}


    cart.checkout()


    }
    cart.go

    View full-size slide

  30. type mockSuccessClient struct{}


    func (m *mockSuccessClient) Post(url, contentType string, body io.Reader) (*http.Response, error) {


    res := &http.Response{


    Status: "200 OK",


    }


    return res, nil


    }


    func Test_CheckoutSuccess(t *testing.T) {


    myClient := &mockSuccessClient{}


    cart := &cart{myClient}


    status := cart.checkout()


    want := "200 OK"


    if status != want {


    t.Errorf("status should be %s but got %s", want, status)


    }


    }


    cart_test.go

    View full-size slide

  31. type mockSuccessClient struct{}


    func (m *mockSuccessClient) Post(url, contentType string, body io.Reader) (*http.Response, error) {


    res := &http.Response{


    Status: "200 OK",


    }


    return res, nil


    }


    func Test_CheckoutSuccess(t *testing.T) {


    myClient := &mockSuccessClient{}


    cart := &cart{myClient}


    status := cart.checkout()


    want := "200 OK"


    if status != want {


    t.Errorf("status should be %s but got %s", want, status)


    }


    }


    cart_test.go

    View full-size slide

  32. Change HTTP Client

    View full-size slide

  33. Resty docs
    https://github.com/go-resty/resty

    View full-size slide

  34. Resty docs
    https://github.com/go-resty/resty

    View full-size slide

  35. type myResty struct {


    *resty.Client


    }


    func NewRestyClient() httpClient {


    return myResty{}


    }


    func (client myResty) Post(url, contentType string, body io.Reader) (*http.Response, error) {


    resp, _ := client.R().


    SetBody(body).


    ForceContentType(contentType).


    Post(“https://line.me/myshop/v1/inventory")


    return resp.RawResponse, nil


    }


    .


    .


    .


    func main() {


    newCli := NewRestyClient()


    cart := &cart{newCli}


    cart.checkout()


    }
    my_restry.go

    View full-size slide