# howmuch - [howmuch](#howmuch) - [Project Diary](#project-diary) - [2024/09/30](#20240930) - [2024/10/01](#20241001) - [Config](#config) - [Business logic](#business-logic) - [Startup framework](#startup-framework) - [2024/10/02](#20241002) - [Logging](#logging) - [Version](#version) - [2024/10/03](#20241003) - [2024/10/04](#20241004) A tricount like expense-sharing system written in Go --- It is a personal project to learn go and relative technologies. --- ## Project Diary ### 2024/09/30 The idea comes from a discussion with my mom. I was thinking about doing some personal budget management thing but she brought up the expense-sharing application that could be a good idea. I explained why it was a terrible idea and had no value but in fact it was a really a good idea. First I have to set up a web server. I'm thinking about using `gin`, since I have played with `chi` in other projects. Then I have to add some basic support functions like system `logging`, versioning, and other stuffs. Next I need to design the API. - User management: signup, login, logout. - A logged-in user must be able to: - create an event - add other users to that event - A user can only view their own events, but not the events of other users' - A user can add an expense to the event (reason, date, who payed how much, who benefited how much) - Users in the event can edit or delete one entry - changes are sent to friends in the event - User can get the money they spent themselves and the money they must pay to each other - User can also get the total amount or the histories. That is what I thought of for now. Thus, Besides a web server, I must have a database that can store all the data. ex. PostgreSQL. I need a message queue system (RabbitMQ?) to handle changes for an event. That will results in a messaging service sending emails. I also want to use `Redis` for cache management. What else? `OpenAPI` + `swagger` for API management. And last but not least, `Docker` + `Kubernetes` for the deployment. That is what I am thinking of for now. I will note down other ideas during the project. ### 2024/10/01 A Go application has 3 parts: - Config - Business logic - Startup framework #### Config The application provides a command-line tool with options to load configs directly and it should also be able to read configs from the yaml/json files. And we should keep credentials in those files for the security reasons. To do this, we can use `pflag` to read command line parameters, `viper` to read from config files in different formats, `os.Getenv` to read from environment variables and `cobra` for the command line tool. The execution of the program is then just a command like `howmuch run`. Moreover, in a distributed system, configs can be stored on `etcd`. > [Kubernetes stores configuration data into etcd for service discovery and cluster management; etcd’s consistency is crucial for correctly scheduling and operating services. The Kubernetes API server persists cluster state into etcd. It uses etcd’s watch API to monitor the cluster and roll out critical configuration changes.](https://etcd.io/docs/v3.5/learning/why/) #### Business logic - init cache - init DBs (Redis, SQL, Kafka, etc.) - init web service (http, https, gRPC, etc.) - start async tasks like `watch kube-apiserver`; pull data from third-party services; store, register `/metrics` and listen on some port; start kafka consumer queue, etc. - Run specific business logic - Stop the program - others... #### Startup framework When business logic becomes complicated, we cannot spread them into a simple `main` function. We need something to handle all those task, sync or async. That is why we use `cobra`. So for this project, we will use the combination of `pflag`, `viper` and `cobra`. ### 2024/10/02 #### Logging Use `zap` for logging system. Log will be output to stdout for dev purpose, but it is also output to files. The log files can then be fetched to `Elasticsearch` for analyzing. #### Version Add versioning into the app. ### 2024/10/03 Set up the web server with some necessary/nice to have middlewares. - Recovery, Logger (already included in Default mode) - CORS - RequestId Using channel and signal to gracefully shutdown the server. A more comprehensible error code design : - Classical HTTP code. - Service error code composed by "PlatformError.ServiceError", e.g. "ResourceNotFound.PageNotFound" - error message. The service error code helps to identify the problem more precisely. ### 2024/10/04 Application architecture design follows [Clean Architecture](https://manakuro.medium.com/clean-architecture-with-go-bce409427d31) that has several layers: - Entities: the models of the product - Use cases: the core business rule - Interface Adapters: convert data-in to entities and convert data-out to output ports. - Frameworks and drivers: Web server, DB. Based on this logic, we create the following directories: - `model`: entities - `infra`: Provides the necessary functions to setup the infrastructure, especially the DB (output-port), but also the router (input-port). Once setup, we don't touch them anymore. - `registry`: Provides a register function for the main to register a service. It takes the pass to the output-port (ex.DBs) and gives back a pass (controller) to the input-port - `adapter`: Controllers are one of the adapters, when they are called, they parse the user input and parse them into models and run the usecase rules. Then they send back the response(input-port). For the output-port part, the `repo` is the implementation of interfaces defined in `usecase/repo`. - `usecase`: with the input of adapter, do what have to be done, and answer with the result. In the meantime, we may have to store things into DBs. Here we use the Repository model to decouple the implementation of the repo with the interface. Thus in `usecase/repo` we only define interfaces. Then it comes the real design for the app. Following the Agile method, I don't try to define the entire project at the beginning but step by step, starting at the user part. ```go type User struct { CreatedAt time.Time UpdatedAt time.Time FirstName string LastName string Email string Password string ID int } ``` Use Buffalo pop `Soda CLI` to create database migrations. ### 2024/10/07 Implement the architecture design for User entity. Checked out OpenAPI, and found that it was not that simple at all. It needs a whole package of knowledge about the web development!