GO
Possible Architecture
- layering
- handlers - external interface for http, rpc, message broker, that converts internal models to external
- service - contains logic and operate with internal models with a help of repo & external service
- external service - can be directly RPC service OR wrapped with custom interface
- repo - contains logic to retrieve data from DB by executing SQL (or similar) queries
- basically a sub-type of external service
- might or might not have own models and errors
- everything is passed through DI for testability
- commonly tests are done on each component as units, repo tests with lightweight DB AND functional tests when you spin-up your app and execute actions with it through public interface
- e2e is also a possibility, when you aren’t mocking external services, but using them
- context is stored as global var that populated on start
- logs can be written to VL or similar solution
- graphana+prometheus can be used for alerts and metrics
Roadmap
- intro
- great lang for BE services, CLI tools and distributed systems with GC, strong types, compilation (to single binary) and strong std, that features performance, great error handling and concurrency management
- simplistic & easy to learn
gocommand features:mod- depth managementbuild- compilationrun- dev runtest- testingfmt- formatting- etc
- syntax
- vars:
- changeable:
varOR:=shorthandvardeclares AND allows to avoid initialization & assignment- if value is not provided, go will assign default values:
0,"",falseORnil(pointers, slices, maps)
- if value is not provided, go will assign default values:
:=always must have value, infers type, can be used inside fn only
- unchangeable:
const- you can use
itoakeyword to create int sequence starting from 0 (will start from zero perconstblock)
- you can use
- can have explicit type OR infer it
- go has concept of shadowing AND scoping (block, fn, package)
- data types:
- int8-64, uint8-64, float32/64, complex numbers, boolean, string, bytes (alias for uint8), rune (alias for int32)
- usually you should use just
int, which is often int32 OR 64, based on architecture - go strict with types and require conversion
- for bools go have: &&, !, ||, ==, != logical operations and checks
- usually you should use just
- statically typed and will error at compile time
- int8-64, uint8-64, float32/64, complex numbers, boolean, string, bytes (alias for uint8), rune (alias for int32)
- composite data types:
- array - fixed size sequence of sam-type elements
- size is part of type
- initialize with zero values
- passed as value
- slice - more robust version of array, that supports dynamic sizing, append and copy operations
- each slice has capacity (can be pre-allocated:
make([]T, length, capacity); for performance), that determines when memory re-allocation occursmakealso creates mapsmake(map[string]int)and channelsmake(chan int)- you can convert slice to array
[N]T(slice)(will panic if slice has lower thenNelements) - if you need to operate on array memory as a slice you can convert it:
array[:]ORarray[start:end]
- each slice has capacity (can be pre-allocated:
- map - key/value data type, that supports data storage (with keys of comparable types)
- except basic map operations you can idiomatically check for existence
value, ok := map[key]- comma-ok idiom used to distinguish presence in map, even in case if value is default
- same idiom can be used to check type assertion without panic:
value, ok := interface.(Type)AND if channel closed:values, ok <-ch
- except basic map operations you can idiomatically check for existence
- string - immutable (manipulations will copy string) sequence of bytes (always encoded as UTF-8)
- to effectively iterate over UTF-8 strings you can use
rune, that will represent UTF-8 char - note that
lenprints number of bytes in str, not runes runecan also be created via''- “ can be used to define strings without escape sequences and WITH formatting preservation
""define regular strings with escape sequences- note:
for rangewill iterate string by runes, BUT index access will return bytes
- to effectively iterate over UTF-8 strings you can use
- struct - used to define interface for object with methods only
- functions attached separately
- struct support tags, that define how to serialize data into struct, ex:
json:"name,omitempty"omitemptywont add field to JSON if it has zero valuejson:"-"will prevent (un)marshal- note that not exported fields are ignored in (un)marshal process
- struct can be embedded with other struct, enabling composition pattern
-
- array - fixed size sequence of sam-type elements
- changeable:
- vars:
type Address struct { Street, City, State string }
type Person struct { Name string Address }
p := Person{
Name: “Alice”,
Address: Address{“123 Main St”, “Anytown”, “CA”},
}
fmt.Println(p.Street)
```
- conditions:
- if and if-else
- if supports initialization in condition: if num := 9; num < 0 {...}
- switch
- supports: multiple values per case, type switch, expression & fallthrough (need to define by fallthrough keyword)
- loops
- for is basic and single loop in go, supports condition, post statement, initialization, continue and break with labels for nested loops
- for initialisation; condition; post { ... }
- for range iterator style syntax that can be used for arrays, slices, maps, strings, and channels
- returns index/key (except channel), value for all types
- _ syntax is used to omit value
- notes:
- map:
- can’t be modified on iteration (except deletion)
- iterates in random order
- string:
- iterates by runes
- goto can be used to move control flow to chosen label within fn
- docs
- go has Godoc for comments as docs
- you can add comment before fn to act as inline doc AND at start of file to act as doc for whole file
- supports markup
- can be parsed by Godoc package to form HTML view of docs
- you can write specific types of tests, that will act as example, by using specific file name example_{FUNCTIONALITY_NAME}_test.go AND fn name (starts with Example)