¿Como estructurar tu aplicación en Go?
Tags: go, spanish, programming, structuring
Published: 2021-05-10 01:53:09

##Objetivo

Cuando comencé a programar en [go](https://golang.org/), me hice muchas preguntas. Preguntas sobre el lenguaje en sí, buenas prácticas, code conventions, naming conventions, cómo escribir código idiomático, etc,... pero creo que una de mis primeras preguntas fue: **¿cómo estructuro mi aplicación?**. Luego de haber investigado y haber escrito un par de aplicaciones productivas, **mi idea es compartirles una propuesta de cómo estructurar una aplicación en golang (o simplemente *go*) y dejarles un** [ejemplo en GitHub](https://github.com/hdlopez/clean-architecture-golang) fácil de utilizar.

Si buscan en internet realmente hay muchas, muchas, propuestas e ideas (al final comparto algunos links). Muchas de esas basadas en la propuesta de [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) de Uncle Bob y en [Domain Driven Design](https://martinfowler.com/bliki/DomainDrivenDesign.html). En este artículo les comparto una propuesta más, basada en clean architecture, inspirada en artículos que he leído y en español :).

##Clean Architecture? y eso?

Como mencionaba, en [este](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) gran artículo de hace ya varios años,  *Uncle Bob* describe cuáles considera que deben ser las características de una buena estructura o modularización de una aplicación.

Intentaré describir en español (o spanglish) y usando un poco mis palabras lo que se menciona en el artículo. 

Las aplicaciones deben ser:

1.  *Independientes de frameworks:* la arquitectura no debe tener dependencias con frameworks subyacentes que utilicemos. Esto nos permite flexibilidad ante cambios de framework y no atarnos a las restricciones que cada uno presente .
2. *Testeable*: los componentes de la aplicación deben ser testeables, sin necesidad de otros módulos o de tener una UI. 
3. *Independiente de la UI*:  la interfaz con el usuario de la aplicación podría ser un command line, una API, una web y eso debería ser fácilmente intercambiable sin cambiar las reglas de negocio.
4. *Independiente de la base de datos*: la forma en que se almacenan los datos debe ser independiente de tus reglas de negocio. Si la aplicación comienza almacenando datos en mysql y luego evoluciona y debe simplemente hacer un *POST* de esa información a un API externa, deberían ser intercambiables sin modificar reglas de negocio.
5. *Independiente de cualquier ente externo*: basicamente las reglas de negocio no deberían saber de nada de lo que sucede por fuera de ellas, ni de DBs, ni de APIs o de cualquier otra cosa.

Siguiendo estos principios según Uncle Bob podemos **separar nuestro código en 4 capas**:

* *Entities*: esta capa encapsula las reglas de negocio de nuestro dominio. Normalmente en go estas entidades son representadas por structs y sus funciones asociadas.
* *Use cases*: esta capa contiene reglas de negocio específicas de nuestra aplicación. Aquí se proveen los servicios para cumplir los casos de uso.
* *Interface Adapters / Controller*: esta capa consiste en una serie de adaptadores que toman los datos en el formato que los envía el usuario y los transforma para que puedan ser utilizados por nuestra capa de casos de uso.
* *Framework & Driver*: esta capa está generalmente compuesta de conectores o frameworks que nos permiten adaptarnos a distintos entes externos, como base de datos, APIs, etc.
 
Ahora que conocemos más de clean architecture, apliquemos estos principios y separación en capas a una aplicación en go.

##Aplicando Clean Architecture en Go

Utilizaremos como base de la explicación una  [API de mensajes](https://github.com/hdlopez/clean-architecture-golang). ¿Por qué una API de mensajes? Solo porque quise salir de la clásica aplicación de los ejemplos que manejan usuarios 👨🏻‍💻. La API que utilizaremos maneja una entidad `Message` que solo tiene como dato un string, siendo ese string el texto del mensaje (si lo sé, me maté con el ejemplo 😅). Mi idea no es centrarme en una aplicación compleja a nivel lógica de negocio, sino simplemente usarla para mostrar su estructura.

Si visualizamos el proyecto en GitHub o descargamos el ejemplo, la carpeta *root* se verá más o menos así:

``` sh
drwxr-xr-x  14 hlopez  staff   448 Nov  3 16:17 .
drwxr-xr-x   3 hlopez  staff    96 Oct 25 18:10 ..
drwxr-xr-x   5 hlopez  staff   160 Oct 30 19:30 api
-rw-r--r--   1 hlopez  staff   198 Oct 25 19:39 main.go
drwxr-xr-x   5 hlopez  staff   160 Nov  6 18:12 message
drwxr-xr-x   4 hlopez  staff   128 Oct 30 20:56 restclient
...
...
...
```

Como podemos ver, tenemos básicamente 3 módulos `api`, `message` y `restclient`. Existen algunos módulos más en la aplicación, pero son utilitarios y no son relevantes estructuralmente hablando. 

Relacionando los módulos con las capas de *clean architecture* :

* *api* - contiene el código que se ubica en la capa *Controller*
* *message* - este módulo contiene código de la capa *Entities* y de la capa *Use cases*. 
* ** *restclient* - contiene código que se ubica en la capa *Framework & drivers*. 

> ** El módulo *restclient* es solo un ejemplo, pero podríamos tener más módulos en la capa "Frameworks & drivers" como accesos a mysql, a elastic search, a key value stores (como cassandra), etc.

La aplicación puede ser iniciada haciendo simplemente `go run main.go`. El código en `main.go` es extremadamente sencillo.

*main.go*

``` golang
package main

func main() {
	// Dependency injection section
	clients := config.RestClients()

	msgAPI := restclient.NewMessageAPI(clients[config.MessageAPI])

	msgRepo := message.NewRepository(msgAPI)

	msgSrv := message.Service(msgRepo)
	msgCtrl := api.NewMessageController(msgSrv)

	// Creates the API intance
	api := api.New(msgCtrl)

	// Runs the application
	api.Run()
}

```

Como se puede ver, la función `main()` es la encargada de inicializar los módulos y sus dependencias, para luego iniciar la aplicación usando la función `Run()`.

**En la siguientes secciones describo el por qué de la existencia de cada módulo (comenzando con el módulo *api*). La idea es explicar brevemente las implementaciones y hacia el final ver cómo esta arquitectura nos beneficia en el unit testing.**

> En todos los snippets de código no se muestra el código completo, con imports y funciones auxiliares por cuestiones de simplicidad. El código completo está disponible en [ GitHub](https://github.com/hdlopez/clean-architecture-golang)

### Módulo "api"

El módulo *api* está en la capa *Controller*. Su objetivo es proveer al usuario medios de interactuar con la capa de servicios (*Use cases*). En este caso, la interfaz para el usuario es de tipo REST API y está implementada utilizando en el framework [gin-gonic](https://github.com/gin-gonic/gin). 

*api/api.go*

``` golang
package api

type API struct {
	pingCtrl *pingCtrl
	msgCtrl  MessageController 
}

func (api *API) Run() {
	r := gin.Default()

	api.configRoutes(r)

	r.Run() 
}

func (api *API) configRoutes(r *gin.Engine) {
	r.GET("/ping", func(c *gin.Context) { api.pingCtrl.Ping(c) })
	r.GET("/messages/:id", func(c *gin.Context) { api.msgCtrl.Get(c) })
}
```
El tipo `API` tiene como propiedades los distintos controllers que manejarán el input del usuario y lo transformarán para enviar a la siguiente capa. Un ejemplo, es el caso de *message controller* definido con el tipo `messageCtrl` en el archivo `messagectrl.go`.

*api/messagectrl.go*

``` golang
package api

type MessageController interface {
	Get(c Ctx)
}

// messageCtrl handles message entity
type messageCtrl struct {
	srv message.Service
}

func (ctrl *messageCtrl) Get(c Ctx) {
	// 1 - Unmashall user parameters from gin.Context
	id := c.Param("id")
	// 2 - Check and handle validation errors (no business validation)

	// 3 - Make what you need with your request. In this case, get the message by ID.
	msg, err := ctrl.srv.Get(id)
    ...
    ...
}

```
En este ejemplo, la función `Get` asociada a `messageCtrl` toma los parámetros del usuario, los valida y luego los envia a la capa de servicios. Ignoremos en este caso el uso de la variable `srv` del tipo `Service` que veremos en la siguiente sección.

### Módulo *message*

Para comenzar, es bueno mencionar que el nombre del módulo refiere al domino de la aplicación, en este caso "mensajes". En este módulo se definen los objetos de dominio que se manejarán y las funciones que implementarán los casos de uso. 

En este caso la entidad a manejar es `Message`.

*message/message.go*

``` golang
package message

type Message struct {
	Text string `json:"text"`
}
```
Extremadamente simple, solo contiene un string que almacena el texto del mensaje. Esta es la entidad que se expone hacia afuera para uso de la capa *Controller*.

Dentro del módulo *message*, se tiene también el tipo `Service`. Esta interfaz expone las funciones que implementan los casos de uso (capa de *Use cases*). En el ejemplo de la API de mensajes el **caso de uso** es muy simple:  **Obtener un mensaje por ID**.

*message/service.go*

``` golang
package message

type Service interface {
	Get(ID string) (*Message, error)
}

type messageSrv struct {
	repo Repository
}

func (srv *messageSrv) Get(id string) (*Message, error) {
	// validate parameters depending your business logic
	// example: ID must be an UUID v4
	
	// business logic goes here ...

	// retrieve message using its repository
	msg, err := srv.repo.Get(id)

	// do some stuff

	return msg, err
}
```
Notar que `Service` no tiene mayores dependencias más que con la interfaz `Repository` (tipo que describiremos en breve). Eso hace que la lógica de negocio sea agnóstica a cualquier cambio a nivel almacenamiento. 

En la función `Get` asociada al tipo `messageSrv` se deben validar los parámetros y luego ejecutar las reglas de negocio correspondientes. En este caso podría ser tan simple como obtener el mensaje desde su repositorio.

Respecto al tipo `Repository` es una interfaz que brinda una abstracción del acceso a datos. Este código se podría considerar también en la de capa *Use cases*, en donde los casos de uso que se implementan son los más básicos como: obtener o guardar un `Message`. 

*message/repository.go*

``` golang
package message

type Repository interface {
	Get(id string) (*Message, error)
}

type msgRepo struct {
	// It can be easly changed by a database or other storage without touching
	// business logic
	api restclient.MessageAPI
}

func (repo *msgRepo) Get(id string) (*Message, error) {
	// Getting message from the external API.
	msg, err := repo.api.Get(id)
	if err != nil {
		return nil, err
	}

	return build(msg), nil
}
```
Conceptualmente los repositorios de datos deben interactuar con manejadores de base de datos o conectores con APIs para obtener, almacenar o eliminar información. En el caso del ejemplo, el repositorio realiza una conexión con una API externa que brinda mensajes. En la función `Get` del tipo `msgRepo` se hace uso del módulo `restclient` para lograr dicha conexión.

### Módulo "restclient"

El módulo *restclient* está en la capa *Framework & driver*. En esta capa la idea es brindar conectores con frameworks u otro entes externos logrando que posibles cambios entre conectores no afecten a la lógica de negocio. Como ya hemos repasado, este es solo un ejemplo, pero podríamos tener más módulos en la capa "Frameworks & drivers" como accesos a mysql, a elastic search, a key value stores (como cassandra), etc.

En este caso, en el módulo restclient se implementa el acceso a una API utilizando el framework [resty](https://github.com/go-resty/resty). 

*restclient/messageapi.go*

``` golang
package restclient

type MessageAPI interface {
	Get(id string) (*Message, error)
}

type msgAPI struct {
	restAPI
}

...
...

// Get a message from our external Message API
func (api *msgAPI) Get(id string) (*Message, error) {
	url := api.readURL(id)

	msg := new(Message)
	res, err := api.get(url, http.Header{}, msg)

	// type assertion
	msg, _ = res.(*Message)

	return msg, err
}
```

*restclient/restclient.go*

``` golang
package restclient

type restAPI struct {
	readClient *resty.Client
}

func (api *restAPI) get(url string, h http.Header, v interface{}) (interface{}, error) {
	...

	r, err := req.Get(url)

	// handling error and returns the response properly
	return v, nil
}
```

Se utiliza la composición de tipos en go, componiendo el tipo `restAPI` en `msgAPI`. En el tipo `msgAPI` se aprovecha de una implementación genérica de GET HTTP usando un cliente rest de `resty`. 

### Y la testeabilidad??! 

Venimos enfocados en organización, dependencia entre módulos, organización de capas, pero no hablamos aún de algo **muy importante** que es el **testing**. 

Dada la estructura planteada y la independencia entre capa y capa, es muy sencillo realizar pruebas unitarias de cada uno de nuestros módulos sin depender de módulos externos.

Debajo  muestro un ejemplo de cómo probar las funciones de la capa *Use cases*, en particular del archivo `service.go`.

*message/service_test.go*

``` golang
package message

type mockRepo struct{}

func (repo *mockRepo) Get(id string) (*Message, error) {
	if id == "error" {
		return nil, errors.New("Mocked error")
	}
	return &Message{Text: "TestMessage"}, nil
}

func NewInmemRepository() Repository {
	return new(mockRepo)
}

func Test_messageSrv_Get(t *testing.T) {
	// creates in memory message repository
	repo := NewInmemRepository()
	// create new service instance in order to test
	srv := NewService(repo)

	type args struct {
		id string
	}
	tests := []struct {
		name    string
		args    args
		want    *Message
		wantErr bool
	}{
		{
			"test OK",
			args{"myMessageID"},
			&Message{Text: "TestMessage"},
			false,
		},
		{
			"test fail",
			args{"error"},
			nil,
			true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := srv.Get(tt.args.id)
			if (err != nil) != tt.wantErr {
				t.Errorf("messageSrv.Get() error = %v, wantErr %v", err, tt.wantErr)
				return
			}

			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("messageSrv.Get() = %v, want %v", got, tt.want)
			}
		})
	}
}

```

Como vemos en el ejemplo, en este caso es muy sencillo implementar un "mock" que nos permita probar la lógica de la función `Get` sin depender de la lógica subyacente del repositorio (no dependemos si utilizamos una DB, una API, o cualquier otro framework). 

En el mock implementado en el ejemplo simulamos con el string "error", un caso de error en el repositorio. De esa forma podemos plantear un caso de éxito y un caso de error muy fácilmente y sin depender de otros módulos.

> **TIP** con [esta](https://github.com/cweill/gotests) herramienta en go pueden generar unos hermosos test siguiendo el patrón de [Data Driven Testing (DDT)](https://en.wikipedia.org/wiki/Data-driven_testing) (o también conocido como Table Driven Testing o TDT)

## Conclusión

Luego de leer tutoriales, hacer pruebas de concepto, de probar, de equivocarme, de intentar generar código idiomático en *go*, luego de haber leído decenas de artículos usando los principios de *Uncle Bob* y su famosa [clean architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html), finalmente, este es  **mi humilde aporte a la comunidad (en español) de cómo estructurar tu aplicación** en *go*. 

Usando la estructura del ejemplo de la API de mensajes se puede extrapolar a cualquier otra aplicación. En resumen:

*  *api*: en este caso nos da la interfaz con el usuario mediante una rest API, pero podría ser un command line u cualquier otro tipo de interfaz. El nombre del módulo cambiaría según el caso.
* *message*: en este módulo podemos encapsular nuestra lógica de negocio y casos de uso. El nombre del módulo refiere al domino de la aplicación por lo que podría ser cualquier cosa. Deben ser nombres en singular siguiendo [naming conventions](https://talks.golang.org/2014/names.slide) de go. Ejemplo: user, customer, item, etc. 
* *restclient*: este es un simple ejemplo de un módulo externo para dar servicios a la capa de *Use case*. Otros ejemplos podrían ser, módulos con namings como mysqlhandler, dbhandler, elastichandler, dbutil, siendo todos ellos conectores a distintos gestores de datos.

En [mi repositorio de GitHub](https://github.com/hdlopez/clean-architecture-golang) dejo un ejemplo totalmente funcional que pueden utilizar libremente.

Happy structuring :D (creo que inventé la expresión...)

## Referencias

* [Go for newcomers](https://rakyll.org/typesystem/) - Excelente para los más nuevos en go
* [Go By example](https://gobyexample.com/) - Una página con un enfoque MUY práctico llena de ejemplos de código y que es posible probar en el playground.
* [What's in a name](https://talks.golang.org/2014/names.slide) - Presentación sobre naming conventions en go
* [Uncle Bob - Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
* [Clean Architecture Using Golang] (https://medium.com/@eminetto/clean-architecture-using-golang-b63587aa5e3f) 
* [Applying The Clean Architecture to Go applications](https://manuel.kiessling.net/2012/09/28/applying-the-clean-architecture-to-go-applications/)