Showing posts with label Go. Show all posts
Showing posts with label Go. Show all posts

Wednesday, February 11, 2015

Introducing GoHaveAzureStorage

Motivation

In a private project, I wanted to reach Azure Table Storage from some Go applications. My only issue was, I couldn't find a proper Go Azure Table Storage library. So when I got hold on the Azure Table Storage REST API, I decided to do a Go Azure Table Storage lib, and then I decided to do a full Azure Storage lib.

GoHaveAzureStorage

I have used the Microsoft Azure Storage API documentation, as inspiration for the library. With this approach, I hope people who is experienced with programming against Azure will find GoHaveAzureStorage just as easy to use.

A small sample:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
 "fmt"
 "gohaveazurestorage"
)

//Either the primary or the secondary key found on Azure Portal
var key = "PrimaryOrSecondaryKey"

//Storage account name
var account = "Account"

func main() {
 // Create an instance of the lib
 goHaveAzureStorage := gohaveazurestorage.New(account, key)

 // From the lib instace, we can create multiple client instances
 tableStorage := goHaveAzureStorage.TableStorage()

 //Creating a table
 httpStatusCode := tableStorage.CreateTable("Table")
 if httpStatusCode != 201 {
  fmt.Println("Create table error")
 }
}

For documentation and progress of the project:
https://github.com/ChristianHenrikReich/gohaveazurestorage

Tuesday, January 20, 2015

Go: Import cycle not allowed

Level: 1 where 1 is noob and 5 is totally awesome
System: Go

Among the programming languages I use, Go is one of my favorites. Intentionally Go lacks features such as generics, inheritance and some others features, which people might see as standards in a programming language. Some might see this as weaknesses in the language, and some might see it as strengths. In the end, the purpose is the keep the language simple, and to build software with less complex code.

A thing which can be challenging in Go, is object parent-child relations, where a child knows it's parent. Like this code below tries, and fails with an 'Import cycle not allowed' error:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package child

import "Parent"

type Child struct {
  parent *Parent
}

func (child *Child) PrintParentMessage() {
  child.parent.PrintMessage()
}

func NewChild(parent *Parent) *Child {
  return &Child{parent: parent }
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package parent

import (
  "fmt"
  "child"
)

type Parent struct {
  message string
}

func (parent *Parent) PrintMessage() {
  fmt.Println(parent.message)
}

func (parent *Parent) CreateNewChild() *child.Child {
  return child.NewChild(parent)
}

func NewParent() *Parent {
  return &Parent{message: "Hello World"}
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

import (
  "parent"
)

func main() {
  p := parent.NewParent()
  c := p.CreateNewChild()
  c.PrintParentMessage()
}

Cross-refering packages are not allowed in Go. The best thing would be, if Parent could keep track of the children. Then there would be no issues, and some might argue the code would be more clean. But the world is not perfect, and sometimes circumstances enforces design decisions like this.

To make things work, we can use the nice duck typing feature(interfaces) which Go supports. In general, it is good practice to use interfaces. It keeps the code de-couplet and flexible.

So if we make the interface IParent and use it, then everything works out:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package child

type IParent interface {
  PrintMessage()
}

type Child struct {
  parent IParent
}

func (child *Child) PrintParentMessage() {
  child.parent.PrintMessage()
}

func NewChild(parent IParent) *Child {
  return &Child{parent: parent }
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package parent

import (
  "fmt"
  "child"
)

type Parent struct {
  message string
}

func (parent *Parent) PrintMessage() {
  fmt.Println(parent.message)
}

func (parent *Parent) CreateNewChild() *child.Child {
  return child.NewChild(child.IParent(parent))
}

func NewParent() *Parent {
  return &Parent{message: "Hello World"}
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

import (
  "parent"
)

func main() {
  p := parent.NewParent()
  c := p.CreateNewChild()
  c.PrintParentMessage()
}

Now 'Hello World' is written to output, as intended. Of course, the interface can be placed in a 3rd package. As always, it depends...