Building Microservices in Go: Domain Driven Design and Project Layout
Tags: go, microservices
Published: 2021-04-30 22:47:50

> **Disclaimer:** This post includes Amazon affiliate links. If you click on one of them and you make a purchase I'll earn a commission. Please notice your final price **is not** affected at all by using those links.

---

> [I briefly](https://mariocarrion.com/2018/11/07/domain-driven-design-go-loteria.html) covered Domain Driven Design three years ago but I quickly realized [the project](https://en.wikipedia.org/wiki/Loter%C3%ADa) I wanted to use as example was perhaps not the best idea because it was both _too niche_ and it included some naming that is considered offensive.  I even mentioned the "To Do program" domain during that original post.

## What is Domain Driven Design?

According to [Martin Fowler](https://martinfowler.com/bliki/DomainDrivenDesign.html):

> _Domain-Driven Design is an approach to software development that centers the development on programming a domain model that has a rich understanding of the processes and rules of a domain_

It's not a new concept, in fact [Domain Driven Design](https://en.wikipedia.org/wiki/Domain-driven_design) was a term coined by Eric Evans almost 20 years ago ([the _blue book_](https://amzn.to/3s8OAf3) was published in 2003). However in recent years it has become more relevant because of the popularity of _Microservices_ and how those are meant to be designed to do one single thing the best way possible.

However _Domain Driven Design_ has the following caveats:

* It's not easy to implement and it requires more work, specifically isolation and encapsulation on the domain layer to maintain the principal model as _pure as possible_.
* It is recommended for large and complex systems because it requires having domain experts working collaboratively with the team in charge of writing the software.

Recommended books covering Domain Driven Design, listed in the order I suggest reading them:

* [Domain-Driven Design Distilled](https://amzn.to/3ff7sWv)
* [Domain-Driven Design: Tackling Complexity in the Heart of Software](https://amzn.to/3s8OAf3)
* [Implementing Domain-Driven Design](https://amzn.to/3lNK5od)

---

## Understanding the "To Do" Domain

> The code used for this post is [available on Github](https://github.com/MarioCarrion/todo-api-microservice-example/blob/09d705536ebb1dcfa76b341c0029ac5a162ce954/internal/todo.go) feel free to play with it.

Our "To Do Microservice" will be implementing a _To Do Domain_, which consists of the following rules:

* `Task` (s) are activities that need to be completed within a _Period of Time_, they have a _Priority_ and can be _Categorized_.
  * _Tasks_ require a _Description_.
  * Other _Tasks_ can be defined as pre-requisite(s).
* `Period of Time` is a point in time where a _Task_ starts or completes.
  * It consists of a _Start Date_ and a _Due Date_.
  * This value is not required on _Tasks_.
  * _Start Date_ is "less than" _Due Date_.
* `Priority` indicates how important a _Task_ is.
  * There are four priorities: `No Priority`, `Low Priority`, `Medium Priority` and `High Priority`.
  * Default priority is: `No Priority`.
* `Category` is a human readable value meant to be used to organize _Tasks_.
  * Values are unique in all.

## Project Layout

Go does not enforce any project structure or project layout, there are no concrete guidelines for selecting how to organize our projects, usually the most common answer is _use a flat structure_, and that really works for small projects, however this may not work at scale when dealing with really complex systems.

Similar to Go, _Domain Driven Design_ does not enforce any project structure or project layout, instead it defines concepts we have to follow to properly communicate between the team in charge of the implementation and the domain experts.

Clearly we need something else...

This is where another concept comes into place: [_Hexagonal Architecture_](https://alistair.cockburn.us/hexagonal-architecture/), with the sole purpose of creating a loosely coupled application that can be interconnected via _ports and adapters_. The idea of defining those _ports_ and _adapters_ is to allow components to communicate with each other via concrete protocols, which in the world of Go we could define them as interface types.

In Go, if we put everything together we can define a project layout that includes an [`internal/`](https://golang.org/doc/go1.4#internalpackages) package with the following structure:

<script src="https://gist.github.com/MarioCarrion/47658ff4dd99f4c8b9579ca75f19046a.js"></script>

This is the structure I like to follow for complex projects, where each package is described as the following:

* `internal/` defines all domain types and domain logic, all business logic should be defined here as much as possible.
  * `internal/datastore` is a placeholder value, it's meant to represent [Repositories](https://martinfowler.com/eaaCatalog/repository.html) and it literally should be named as the datastore we are planning to use like `internal/postgresql` or `internal/mongodb`.
  * `internal/api` indicates _the public way_ to access our service, _the method_ we use to expose our API for the outside world, for example `internal/rest` or `internal/grpc`.
  * `internal/service` defines all use cases, and in some cases domain logic, mean to connect _datastores_ and _apis_ together.

## Parting words

Recall this is the beginning of this series, I will continue posting more content that describes in detail how to deal with all changes required for building a Microservice, this includes among other things: Testing, Authorization, Configuration and Observability.

Until then, **keep it up**. I will talk to you next time.