-4

Say I have several different gRPC servers, for example x.Server, y.Server and z.Server, and in order to spin them up, I have a lot of repeated code inside their main function, e.g.:

func main() {
    if err := config.EnsureArgLength(1); err != nil {
        log.Fatalln(err.Error())
    }

    srv := &x.Server{}
    if err := srv.ReadServerConfig(os.Args[1]); err != nil {
        log.Fatalln(err.Error())
    }
    if err := srv.RegisterListener(); err != nil {
        log.Fatalln(err.Error())
    }
    if err := srv.RegisterClients(); err != nil {
        log.Fatalln(err.Error())
    }

    s := grpc.NewServer()
    proto.RegisterXServer(s, srv)

    if err := srv.Serve(s); err != nil {
        log.Fatalf("failed to serve: %s", err.Error())
    }
}

I would love to refactor this main function to make it one or two lines long, something like the following:

func main() {
    srv := x.Server{}
    if err := srv.RegisterAndServe(); err != nil {
        log.Fatal("failed to serve: %s", err.Error())
    }
}

But each server will have an auto-generated function proto.RegisterXServer which is not part of x.Server struct, and I'm also not able to modify the file which contains it, since it is auto generated. How should I proceed?

  • 1
    You can't. The closest you could get is taking the function as an `interface{}` and then using runtime reflection, but you'd lose all type safety. – Adrian Aug 10 '21 at 15:11
  • it is not great you have changed the question so much. My answer does not make sense at all. Adrian comment neither. You should have created a new question. I wonder who accepted this edit. –  Aug 13 '21 at 20:30

1 Answers1

0

in regards to op changes, which was radical,

I can suggest using a reducer pattern like this.

package main

import (
    "fmt"
)

func main() {
    fail(reduce(sayHello(), sayGoodbye))
}
func sayHello() func() error {
    return func() error { fmt.Println("Hello, playground"); return nil }
}
func sayGoodbye() error {
    fmt.Println("Goodbye from the playground")
    return nil
}
func reduce(h ...func() error) error {
    for _, hh := range h {
        if err := hh(); err != nil {
            return err
        }
    }
    return nil
}

func fail(err error) {
    if err != nil {
        panic(err)
    }
}