Skip to content

Instantly share code, notes, and snippets.

@pieterlouw
Created January 18, 2017 20:36
Show Gist options
  • Save pieterlouw/1d0d9aaa16ad20d9ee8671bd7ea243ea to your computer and use it in GitHub Desktop.
Save pieterlouw/1d0d9aaa16ad20d9ee8671bd7ea243ea to your computer and use it in GitHub Desktop.
2nd Example for my Go talk on interfaces

##Example 2##

In this example we will look at a part of a web application that manages stock items. The decision was made to start with using an embedded database, something like SQLite or BoltDB, with the idea to scale out to a more distributed database like Cassandra as the business scale.

Let's define the domain type:

package domain

//StockItem domain type model
type StockItem struct {
	Name        string
	Description string
	Price       int
}

The SQLite implementation package will look like this:

type StockItemRepository struct {
    Db         *sql.DB
}


//Add puts a new StockItem into the warehouse
func (s *StockItemRepository) Add(new *StockItem) error {
    //
}

//Update StockItem identified by  given id with updated  
func UpdateById(id int, updated *StockItem) error {
    //
}

//Find StockItem identified by given id
func FindById(id int) (*StockItem, error) {
    //
}

//List all StockItems in the warehouse
func ListAll() ([]*StockItem, error) {
    //
}

From the calling code we create a StockItemRepository object and assign the opened DB handler to it's Db field:

db, err := sql.Open("sqlite3", "./app.db")
if err != nil {
    log.Fatal(err)
}
defer db.Close()

inventoryStore := &sqlite.StockItemRepository {
    Db:         db,
    //....
}

The web handler type embeds the concrete sqlite.StockItemRepository type:

type webHandler struct {
    sqlite.StockItemRepository
}

This will work for a while until our application need to scale and the need for a database like Cassandra is needed. We can decouple the webHandler from the concrete sqlite type and rather define an interface type that the webHandler can use.

That way the webHandler is not concerned and decoupled with the underlying database that is used.

The interface type will look like this:

type StockItemRepository interface {
	Add(*StockItem) error
	Update(int, *StockItem) error
	Get(int) (*TerStockItemminal, error)
	ListAll() ([]*StockItem, error)
}

It will be a good idea to put the interface part of the domain package where our StockItem type is defined.

The webHandler type can now be changed to use the new interface type instead:

type webHandler struct {
    domain.StockItemRepository
}

The sqlite concrete type implementation will still work as it satisfies the new interface type.

But more importantly if a new Cassandra implementation (or any other implementation that satisfies the interface) is created later on it can easily be swopped in and used by the webHandler without making any changes to the webHandler type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment