# Tutorial: Defining the Domain entities

This blog is the part of the series [**Building a Web App with Golang**](https://blog.gkomninos.com/series/webapp-using-golang)**.**

In today's article we are going to define the basic entities and the operations on them for our web application. In the [first part](https://blog.gkomninos.com/crafting-a-web-application-with-golang-a-step-by-step-guide) we defined the scope of the application.

We are going to build a system that can issue issue invoices for clients.

Let's create a new git branch to work on:

```bash
git checkout -b basic-domain
```

**Company**

Every client and "us" (our company/the freelancer) will be represented by an entity `Company` .

Let's create a file named `company.go` in the root of our project

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718515845175/f16a0a8b-cf20-4369-bc1b-c87d5f2fea4d.png align="center")

then we define a struct with the basic attributes we have:

```go
package invoicehub

type Company struct {
	ID           int
	Name         string
	Address      Address
	Email        string
	TaxID        string
	VatID        string
	BankAccounts []BankAccount
}

type Address struct {
	Street     string
	City       string
	PostalCode string
	Country    string
}

type BankAccount struct {
	BankName      string
	AccountNumber string
	IBAN          string
	BIC           string
}
```

The idea is that we will represent each real life company using the above struct.

**Invoice**

Create an `invoice.go` in the root of the project

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718516394251/a8486aac-cfe5-4ebf-aab2-5e0003c36db0.png align="center")

Each invoice will have at least the following:  
\- Seller  
\- Buyer  
\- Amount  
\- Issue Date  
\- Invoice Number  
\- Days (number of days after issuance that must be paid).

We need to install first one dependency to handle decimal numbers:

```bash
get github.com/shopspring/decimal
```

Now let's start with that:

```bash
package invoicehub

import (
	"time"

	"github.com/shopspring/decimal"
)

type Invoice struct {
	ID            int
	InvoiceNumber string
	IssueDate     time.Time
	SellerID      int
	BuyerID       int
	DaysToPay     int

	LineItems []LineItem
}

type LineItem struct {
	Description string
	Amount      Amount
	VatRate     decimal.Decimal
}

type Amount struct {
	Value    decimal.Decimal
	Currency string
}
```

The above structs should satisfy our needs for now.

Pay, attention that I am using ids for Buyer and Seller. We could have used a Company struct there.

<mark>Why I choose to use ids instead of a company struct?</mark>

Our application now is a "monolithic" application. In the future we might want to split into different microservices (maybe one microservice to handle the companies and one microservice to handle the invoices). Let's be proactive and try to decouple the Companies with the Invoices.

I does not look that we need other structs to represent our business domain. Of-course , we might forgotten something but then we will change.

**Operations**

Our application is pretty simple:

For a Company we need to be able to:

**C**reate a company  
**R**ead a company  
**U**pdate a company

Our requirements don't have a Delete so we skip for now.

Creating, Reading, Updating a company are straightforward.

First we need a way to do these operations in our storage layer.  
For this we are going to create an interface `CompanyRepository`

Let's do that:

in your `company.go` add the following:

```bash
type CompanyRepository interface {
	Create(ctx context.Context, company *Company) (int, error)
	Update(ctx context.Context, company *Company) error
	Get(ctx context.Context, id int) (Company, error)
}
```

Now for our invoices:

We need to be able to :

**C**reate Invoice  
**R**ead Invoice  
Create a PDF from an invoice

we don't have full CRUD (Create Read Update Delete) since we don't want to Update or Delete invoices.

Let's define the repository also for invoices:

in the `invoice.go` add:

```go
type InvoiceRepository interface {
	Create(ctx context.Context, invoice *Invoice) (int, error)
	Get(ctx context.Context, id int) (Invoice, error)
}
```

What about PDF generation here? This is not a database operation.  
Additionally, what about creation of an invoice? It is a little bit more complex.

In the [requirements](https://blog.gkomninos.com/crafting-a-web-application-with-golang-a-step-by-step-guide) we had that the `InvoiceNumber` looks like:

> 1031/24

so we have two parts:  
1\. a number that resets every year (1031)  
2\. the year (24)

So the next invoice should look like 1032/24 but if it is the first for 2025 should look like 1001/24 .

Notice that we start always with 1000.

This is just one way others, might do it differently.

It would be nice to have a generic way to compute that per customer. <mark>BUT, do not forget our requirements. We want to code for now and not for imaginary use cases. Let's get stuff done</mark>

Since invoices are a bit more complex let's also create a Service Layer that will handle the business logic .

open `invoices.go` and add:

```go
type InvoiceService interface {
	Create(ctx context.Context, invoice *Invoice) error
	Get(ctx context.Context, id int) (Invoice, error)
	CreatePDF(ctx context.Context, id int) ([]byte, error)
}
```

We also need an extra method in the Repository that returns the last invoice of the year. We are going to use that to compute the invoice number

Add the `GetLastInvoiceForYear` in the repository

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718519776641/4605eaa9-cbc4-4eaa-97ce-effefd15fc5d.png align="center")

### Adding the interfaces in our HTTP layer

Now that we have "described" the operations of our system via the interfaces let's see where we are going to use them.

in the `http/router.go` we defined a base handler :

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718520492810/d072a638-c954-4c73-b6f9-d8947e24bed1.png align="center")

Let's add the interfaces there:

```go
type baseHandler struct {
	e         *echo.Echo
	companies invoicehub.CompanyRepository
	invoices  invoicehub.InvoiceService
}
```

so when we create the baseHandler we should inject the implementations of the interfaces:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718520651156/afaba281-bee9-4f02-aa70-e71168895a04.png align="center")

Since we don't have any concrete implementation yet let's pass nil where we call the NewRouter function in our `cmd/main.go` .

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718520733482/2d4aa839-121c-41f4-81a3-6f7b41785e64.png align="center")

### Commit and Push

let's commit our code and push our branch

```go
git add .
git commit -m "add basic domain entities"
git push origin basic-domain
```

And as usual, you can find today's code in the github [branch](https://github.com/gosom/freelance-invoice-hub/tree/basic-domain)

### Summary and what is next

In today's blog post we started implementing our business logic. We first defined the required structs and the operations that we can do on these.  
The operations are defined using interfaces. Utilizing interfaces allows us to think about our business logic without having to think about implementation details. Additionally, it will allow us to easily unit test our application later.

I would like to share a piece of advice here. <mark>When you have to develop an application no matter how complex it is try first to focus on what is your goal</mark>. Don't fall into the trap of questioning your self all the time like:  
  
what if the user wants also that?  
what if this changes ?  
what if ... ?  

These what if may never happen. If they do be confident that when it's required you will handle it.

I am not saying or implying do not think about scalability, changes of requirements etc . I am saying think about them try to code in a way that some decisions are deferred but don't waste your time trying to code something smart when it is not required.

The moments I am writing these lines I am thinking the following:  
  
\- How am I distinguish which company is the Seller when we don't have a User entity ?  
\- What if when we create an invoice someone else does it parallel (so the invoice number may come wrong?\_  
\- How am i going to create an invoice number when I do it near the end of the year and I use UTC in the system but my current timezone is UTC+3 and I am in the next year?  
\- ...  
  
and many many more.  
  
Some of these are maybe valid concerns. But so far we don't have anything working yet. <mark>We don't have to aim for perfection, a working software is better that no software in the end.</mark>

**Links to the other part of that series**

[https://blog.gkomninos.com/crafting-a-web-application-with-golang-a-step-by-step-guide](https://blog.gkomninos.com/crafting-a-web-application-with-golang-a-step-by-step-guide)

[https://blog.gkomninos.com/setting-up-a-docker-development-enviroment-for-go](https://blog.gkomninos.com/setting-up-a-docker-development-enviroment-for-go)

[https://blog.gkomninos.com/building-a-robust-web-server-in-go-a-step-by-step-guide](https://blog.gkomninos.com/building-a-robust-web-server-in-go-a-step-by-step-guide)

[https://blog.gkomninos.com/tutorial-deployment-of-golang-web-app-using-systemd](https://blog.gkomninos.com/tutorial-deployment-of-golang-web-app-using-systemd)

👍 Please leave a comment or like the article if you like it. This will help me gain visibility.

❤️ Following me on Github or [X](https://x.com/gkomdev) or [LinkedIn](http://www.linkedin.com/in/georgios-komninos-172508147) motivates me keep writing.
