Service Design
As shown in this diagram, the Trend Service consumes “search book“ events from the queue, analyzes them and lists the “trendy“ books to the users.
Our trend service should have at least 2 components:
- Consumer: It consumes and analyzes events from the queue.
- API Server: It lists trends to the users.
We‘ll have 3 services in this tutorial, but we don‘t have to make 3 repositories since they're all written in Go. Let's try the monorepo.
Monorepo
A monorepo, short for "monolithic repository," is a software development approach where multiple projects or components of a system are stored within a single repository.
We need to structure the project like this:
.
├── LICENSE
├── README.md
├── domain
│ └── model
│ └── book.go
├── go.mod
├── go.sum
├── infrastructure
│ ├── mq
│ │ ├── helper.go
│ │ └── kafka.go
│ └── parser
│ └── parse.go
└── service
├── recommendation
│ └── main.go
├── trend
│ └── main.go
└── web
├── adapter
│ ├── router.go
│ └── templates
│ └── index.html
├── application
│ ├── executor
│ │ └── book_operator.go
│ └── wire_helper.go
├── config.yml
├── domain
│ └── gateway
│ └── book_manager.go
├── infrastructure
│ ├── config
│ │ └── config.go
│ └── database
│ └── mysql.go
└── main.go
Restructure the folders
- Move adapter/, application/, domain/gateway/, infrastructure/database/ and infrastructure/config/ folders into service/web/.
- Move main.go and config.yml files into service/web/.
- Delete the
Parse
function in infrastructure/config/config.go.
Create infrastructure/parser/parse.go:
/*
Package parser provides config parse funcs.
*/
package parser
import (
"fmt"
"os"
"gopkg.in/yaml.v3"
)
// Parse parses config file and returns a Config.
func Parse[T any](filename string) (*T, error) {
var c T
buf, err := os.ReadFile(filename)
if err != nil {
return &c, err
}
err = yaml.Unmarshal(buf, &c)
if err != nil {
return &c, fmt.Errorf("failed to parse file %s: %v", filename, err)
}
return &c, nil
}
T
is a generic type that can be used to parse any service‘s config file.