My first go at go... would you do anything different?
Tags: go, bulletjournal, obsidian
Published: 2022-04-08 20:02:36

Hello for a slightly longer article. :-) I had my first try at go program and wanted to share what i have learned. 

The tool: I started using obsidian notes and i'am building my self and electronic bullet journal. 

Here are the links. But i will probably write about this in a later article: 

https://obsidian.md/
https://bulletjournal.com/

In the bullet journal method you have a monthly overview of things. This is basicly a list of you of the number of the day and the weekday besides it. You use this list to write notes about your appointments for that month down. 

Example: 
01 - sa
02 - su 3 pm cake and Coffee
03 - mo 

It's a little tedious to write this down by hand and the use case is easy enough to try this in a new language. I wanted to create a cli tool, which prints a list of days and their respective weekdays for the month i give as parameter when executing the tool. 

Example: 
```powershell
.\printMonths.exe -month=january
----january----
01 - sa
02 - su
03 - mo
04 - tu
05 - we
06 - th
07 - fr
08 - sa
09 - su
10 - mo
11 - tu
12 - we
13 - th
14 - fr
15 - sa
16 - su
17 - mo
18 - tu
19 - we
20 - th
21 - fr
22 - sa
23 - su
24 - mo
25 - tu
26 - we
27 - th
28 - fr
29 - sa
30 - su
31 - mo
``` 

So here is, what i came up with... 

```go
package main

import (
	"errors"
	"flag"
	"fmt"
)

const (
	MONDAY    string = "monday"
	TUESDAY          = "tuesday"
	WEDNESDAY        = "wednesday"
	THURSDAY         = "thursday"
	FRIDAY           = "friday"
	SATURDAY         = "saturday"
	SUNDAY           = "sunday"
)

// Struct to encapsulate the names of the weekdays and
// possibly use them in functions
type WeekData struct {
	days [7]string
}

//this struct holds the data needed to start the print of the days
type MonthData struct {
	numberOfDays int
	startDay     string
	weekData     WeekData
}

//logic for the printing of the days
func (m MonthData) print() string {
	result := ""
	currentWeekday := m.startDay
	for day := 1; day <= m.numberOfDays; day++ {
		result = result + fmt.Sprintf("%02d", day) + " - " + currentWeekday[0:2] + "\n"
		var err error
		currentWeekday, err = m.weekData.next(currentWeekday)
		if err != nil {
			fmt.Println(err)
			return ""
		}
	}
	return result
}

//gets you the next day
func (w WeekData) next(current string) (string, error) {
	if current == SUNDAY {
		return MONDAY, nil
	}
	for index, day := range w.days {
		if day == current {
			return w.days[index+1], nil
		}
	}
	return "", errors.New("Day " + current + " not found")
}

func main() {
	//the weekdata struct is used in the month data struct
	wd := WeekData{[7]string{MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY}}

	//a number of month data structs mapped to the name of the months
	data := map[string]MonthData{
		"january":   MonthData{numberOfDays: 31, startDay: SATURDAY, weekData: wd},
		"febuary":   MonthData{numberOfDays: 28, startDay: TUESDAY, weekData: wd},
		"march":     MonthData{numberOfDays: 31, startDay: TUESDAY, weekData: wd},
		"april":     MonthData{numberOfDays: 30, startDay: FRIDAY, weekData: wd},
		"mai":       MonthData{numberOfDays: 31, startDay: SUNDAY, weekData: wd},
		"june":      MonthData{numberOfDays: 30, startDay: WEDNESDAY, weekData: wd},
		"july":      MonthData{numberOfDays: 31, startDay: FRIDAY, weekData: wd},
		"august":    MonthData{numberOfDays: 31, startDay: MONDAY, weekData: wd},
		"september": MonthData{numberOfDays: 30, startDay: THURSDAY, weekData: wd},
		"october":   MonthData{numberOfDays: 31, startDay: SATURDAY, weekData: wd},
		"november":  MonthData{numberOfDays: 30, startDay: TUESDAY, weekData: wd},
		"december":  MonthData{numberOfDays: 31, startDay: THURSDAY, weekData: wd},
	}

	month := flag.String("month", "default", "month to pick")
	flag.Parse()
	fmt.Println("----" + *month + "----")
	if *month != "" {
		fmt.Print(data[*month].print())
	}
}

```
And the Tests: 
```go
package main

import (
	"testing"
)

func TestNext(t *testing.T) {
	wd := WeekData{[7]string{MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY}}

	nextDay, _ := wd.next(MONDAY)

	if nextDay != TUESDAY {
		t.Errorf("Expected '"+TUESDAY+"', got '%s'", nextDay)
	}
}

func TestPrint(t *testing.T) {

	wd := WeekData{[7]string{MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY}}
	md := MonthData{numberOfDays: 1, startDay: SATURDAY, weekData: wd}

	result := md.print()
	if result != "01 - sa\n" {
		t.Errorf("Expected '01 - sa\n', got '%s'", result)
	}

	md = MonthData{numberOfDays: 3, startDay: SATURDAY, weekData: wd}
	result = md.print()
	if result != "01 - sa\n02 - su\n03 - mo\n" {
		t.Errorf("Expected '01 - sa\n02 - su\n03 - mo\n', got '%s'", result)
	}
}

```
### The lessons

* I had some problems remembering that you can give back multiple values from function. This made stumble when i tried to nest function calls. 

* As far as i understand it the basic go testing package has no assertion. You have to make the test fail yourself. 

* In Java i would create an enum for the weekdays. Im not sure if i handled it the best way here. 

* I need to get a better understanding of pointers. I tried to use string pointers in the functions, to just have one string for each day. But i still get confused. 

* I was fun and go is starting to grow on me. At the first look a lot of convience/code sugar is missing, but i'm sure i need to get more into the language to understand the concepts behind it better and not just write java in go. 

What would change in the code above?