mirror of
https://github.com/marcel-dempers/docker-development-youtube-series.git
synced 2025-06-06 17:01:30 +00:00
go intro
This commit is contained in:
parent
b91d28b95d
commit
776e42da90
36
golang/introduction/app/app.go
Normal file
36
golang/introduction/app/app.go
Normal file
@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
customers := GetCustomers()
|
||||
|
||||
for _, customer := range customers {
|
||||
//we can access the "customer" variable in this approach
|
||||
fmt.Println(customer)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func getData() (customers []string) {
|
||||
|
||||
customers = []string{ "Marcel Dempers", "Bob Smith", "John Smith"}
|
||||
|
||||
customers = append(customers, "Ben Spain")
|
||||
customers = append(customers, "Aleem Janmohamed")
|
||||
customers = append(customers, "Jamie le Notre")
|
||||
customers = append(customers, "Victor Savkov")
|
||||
customers = append(customers, "P The Admin")
|
||||
customers = append(customers, "Adrian Oprea")
|
||||
customers = append(customers, "Jonathan D")
|
||||
|
||||
for _, customer := range customers {
|
||||
|
||||
fmt.Println(customer)
|
||||
}
|
||||
|
||||
return customers
|
||||
}
|
28
golang/introduction/app/customers.go
Normal file
28
golang/introduction/app/customers.go
Normal file
@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
type (
|
||||
Customer struct {
|
||||
FirstName string
|
||||
LastName string
|
||||
FullName string
|
||||
}
|
||||
)
|
||||
|
||||
func GetCustomers()(customers []Customer) {
|
||||
|
||||
marcel := Customer{ FirstName: "Marcel", LastName: "Dempers"}
|
||||
|
||||
customers = append(customers, marcel,
|
||||
Customer{ FirstName: "Ben", LastName: "Spain" },
|
||||
Customer{ FirstName: "Aleem", LastName: "Janmohamed" },
|
||||
Customer{ FirstName: "Jamie", LastName: "le Notre" },
|
||||
Customer{ FirstName: "Victor", LastName: "Savkov" },
|
||||
Customer{ FirstName: "P", LastName: "The Admin" },
|
||||
Customer{ FirstName: "Adrian", LastName: "Oprea" },
|
||||
Customer{ FirstName: "Jonathan", LastName: "D" },
|
||||
|
||||
)
|
||||
|
||||
return customers
|
||||
|
||||
}
|
3
golang/introduction/app/go.mod
Normal file
3
golang/introduction/app/go.mod
Normal file
@ -0,0 +1,3 @@
|
||||
module github.com/docker-development-youtube-series/golang/introdouction/app
|
||||
|
||||
go 1.15
|
13
golang/introduction/dockerfile
Normal file
13
golang/introduction/dockerfile
Normal file
@ -0,0 +1,13 @@
|
||||
FROM golang:1.15 as dev
|
||||
|
||||
WORKDIR /work
|
||||
|
||||
FROM golang:1.15 as build
|
||||
|
||||
WORKDIR /app
|
||||
COPY ./app/* /app/
|
||||
RUN go build -o app
|
||||
|
||||
FROM alpine as runtime
|
||||
COPY --from=build /app/app /
|
||||
CMD ./app
|
429
golang/introduction/readme.md
Normal file
429
golang/introduction/readme.md
Normal file
@ -0,0 +1,429 @@
|
||||
# Introduction to Learning Go
|
||||
|
||||
Go can be downloaded from [golang.org](https://golang.org/doc/install) <br/>
|
||||
|
||||
Test your `go` installation:
|
||||
|
||||
```
|
||||
go version
|
||||
```
|
||||
|
||||
# Run Go in Docker
|
||||
|
||||
We can also run go in a small docker container: <br/>
|
||||
|
||||
```
|
||||
cd golang\introduction
|
||||
|
||||
docker build --target dev . -t go
|
||||
docker run -it -v ${PWD}:/work go sh
|
||||
go version
|
||||
|
||||
```
|
||||
|
||||
# Code Structure
|
||||
|
||||
https://golang.org/doc/code.html
|
||||
|
||||
* Package:
|
||||
- Source files in same directory that are compiled together
|
||||
- Have visibility on all source files in the same package
|
||||
|
||||
* Modules:
|
||||
- Collection of packages that are released together
|
||||
|
||||
Our repository can contain one or more go modules, but usually 1.
|
||||
- At the root of the repo
|
||||
|
||||
`go.mod` Declares module path + import path for packages. (Where to download them)
|
||||
- When we write our own program, we can define a module path
|
||||
- This allows us to publish our code (if we want), so others can download it
|
||||
- The module path could be something like `github.com/google/go-cmp`
|
||||
- Makes it easy for other programs to consume our module
|
||||
|
||||
# Our first Program
|
||||
|
||||
* Create a folder containing our application
|
||||
|
||||
```
|
||||
mkdir app
|
||||
|
||||
```
|
||||
|
||||
* Define a module path (github.com/docker-development-youtube-series/golang/introdouction/app)
|
||||
|
||||
```
|
||||
# change directory to your application source code
|
||||
|
||||
cd app
|
||||
|
||||
# create a go module file
|
||||
|
||||
go mod init github.com/docker-development-youtube-series/golang/introdouction/app
|
||||
|
||||
```
|
||||
|
||||
* Create basic source code
|
||||
|
||||
In the `app` folder, create a program called `app.go`
|
||||
Paste the following content into it.
|
||||
|
||||
```
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("Hello, world.")
|
||||
}
|
||||
```
|
||||
|
||||
* Run your application code
|
||||
|
||||
You can run your application
|
||||
|
||||
```
|
||||
go run app.go
|
||||
```
|
||||
|
||||
# Building our Program
|
||||
|
||||
Build your application into a static binary: <br/>
|
||||
|
||||
```
|
||||
go build
|
||||
```
|
||||
|
||||
This will produce a compiled program called `app`
|
||||
You can run this program easily:
|
||||
|
||||
```
|
||||
./app
|
||||
```
|
||||
|
||||
# Install your application (optional)
|
||||
|
||||
"This command builds the app command, producing an executable binary. <br/>
|
||||
It then installs that binary as $HOME/go/bin/app (or, under Windows, %USERPROFILE%\go\bin\app.exe)"
|
||||
|
||||
```
|
||||
go install github.com/docker-development-youtube-series/golang/introdouction/app
|
||||
```
|
||||
|
||||
# The Code
|
||||
|
||||
## Functions
|
||||
|
||||
In the video we cover writing functions. </br>
|
||||
It allows us to execute a block of code <br/>
|
||||
You want to give your function a single purpose <br/>
|
||||
Functions can have an input and return an output <br/>
|
||||
Well thought out functions makes it easier to write tests <br/>
|
||||
|
||||
Instead of doing a boring `x + y` function that adds two numbers, let's do something a little
|
||||
more realistic but still basic:
|
||||
|
||||
```
|
||||
// This function returns some data
|
||||
// The data could be coming from a database, or a file.
|
||||
// The person calling the function should not care
|
||||
// Since the function does not leak its Data provider
|
||||
|
||||
func getData(inputs)(outputs){
|
||||
}
|
||||
|
||||
// functions can take multiple inputs, and return multiple outputs
|
||||
|
||||
// lets say we have 1) customers and 2) the cities they are from
|
||||
// we may want to 1) get a list of customers and 2) get a list of cities
|
||||
// therefore we have 2 types of data, 1) customers 2) cities
|
||||
// let's improve our function so its gets data based on the type
|
||||
|
||||
func getData(customerId int) (customer string) {
|
||||
}
|
||||
```
|
||||
|
||||
## Variables
|
||||
|
||||
To hold data in programming languages, we use variables. <br/>
|
||||
Variables take up space in memory, so we want to keep it minimal. <br/>
|
||||
Let's declare variables in our function
|
||||
|
||||
```
|
||||
func getData(customerId int) (customer string) {
|
||||
var firstName = "Marcel"
|
||||
lastName := "Dempers"
|
||||
|
||||
fullName := firstName + " " + lastName
|
||||
return fullName
|
||||
|
||||
//or we can return the computation instead of adding another variable!
|
||||
return firstName + " " + lastName
|
||||
|
||||
//or we dont even need to declare variables :)
|
||||
return "Marcel Dempers"
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Control Flows (if\else)
|
||||
|
||||
You can see we're not using the `customerId` input in our function. <br/>
|
||||
Let's use it! <br/>
|
||||
|
||||
Control flows allow us to add "rules" to our code. </br>
|
||||
"If this is the case, then do that, else do something else".
|
||||
|
||||
So let's say we have a customer ID 1 coming in, we may only want to
|
||||
return our customer if it matches the `customerId`
|
||||
|
||||
```
|
||||
|
||||
func getData(customerId int) (customer string) {
|
||||
|
||||
if customerId == 1 {
|
||||
return "Marcel Dempers"
|
||||
} else if customerId == 2 {
|
||||
return "Bob Smith"
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
Let's invoke our function :
|
||||
|
||||
```
|
||||
//in the main() function
|
||||
|
||||
//get our customer
|
||||
customer := getData(1)
|
||||
fmt.Println(customer)
|
||||
|
||||
//get the wrong customer
|
||||
customer := getData(3)
|
||||
fmt.Println(customer)
|
||||
|
||||
|
||||
```
|
||||
## Arrays
|
||||
|
||||
At the moment, we can only return 1 customer at a time on our function. <br/>
|
||||
Realisticly we need the ability to return more data, not just a single customer. <br/>
|
||||
|
||||
Arrays allow us to make a collection of variables of the same type. <br/>
|
||||
We can now return a list of customers! <br/>
|
||||
|
||||
Let's change our function to get an array of customers!
|
||||
|
||||
```
|
||||
func getData() (customers [2]string) {
|
||||
//create 1 record
|
||||
customer := "Marcel Dempers"
|
||||
|
||||
//assign our customer to the array
|
||||
customers[0] = customer
|
||||
|
||||
//OR we can assign it like this
|
||||
customers[1] = "Bob Smith"
|
||||
|
||||
//send it back to the caller
|
||||
return customers
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Now we also have to change our calling function to expect an array:
|
||||
|
||||
```
|
||||
customers := getData()
|
||||
|
||||
fmt.Println(customers)
|
||||
|
||||
```
|
||||
|
||||
## Slices
|
||||
|
||||
Since arrays are fixed size, Slices are a dynamically-sized view into arrays.
|
||||
Let's create a slice instead of array so we can add customers dynamically!
|
||||
|
||||
```
|
||||
func getData() (customers []string) {
|
||||
|
||||
//initialise our slice of type string
|
||||
customers = []string{ "Marcel Dempers", "Bob Smith", "John Smith"}
|
||||
|
||||
//add more legendary customers dynamically
|
||||
customers = append(customers, "Ben Spain")
|
||||
customers = append(customers, "Aleem Janmohamed")
|
||||
customers = append(customers, "Jamie le Notre")
|
||||
customers = append(customers, "Victor Savkov")
|
||||
customers = append(customers, "P The Admin")
|
||||
customers = append(customers, "Adrian Oprea")
|
||||
customers = append(customers, "Jonathan D")
|
||||
|
||||
//send it back to the caller
|
||||
return customers
|
||||
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
## Loops
|
||||
|
||||
Loops are used to iterate over collections, lists, arrays etc. <br/>
|
||||
Let's say we need to loop through our customers
|
||||
|
||||
In the `main()` function, we can grab the list of customers and loop them.
|
||||
In this demo, we'll cover a basic for loop, but there are several approaches to writing loops.
|
||||
|
||||
```
|
||||
//loop forever
|
||||
for {
|
||||
//any code in here will run forever!
|
||||
|
||||
fmt.Println("Infinite Loop 1")
|
||||
time.Sleep(time.Second)
|
||||
|
||||
//unless we break out the loop like this
|
||||
break
|
||||
}
|
||||
|
||||
//loop for x number of loops
|
||||
for x := 0; x < 10; x++ {
|
||||
|
||||
//any code in here will run 10 times! (unless we break!)
|
||||
fmt.Println(customers[x])
|
||||
|
||||
}
|
||||
|
||||
//loop for ALL our customer
|
||||
|
||||
for x, customer := range customers {
|
||||
|
||||
//we can access the "customer" variable in this approach
|
||||
customer = customers[x]
|
||||
fmt.Println(customer)
|
||||
|
||||
//OR
|
||||
//we can use the supplied customer from the loop
|
||||
// and silence the x variable, replace it with a _ character
|
||||
fmt.Println(customer)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Structs
|
||||
|
||||
So far so good, however, customer data is not useful as strings. <br/>
|
||||
Customers can have a firstname, lastname, and more properties. <br/>
|
||||
|
||||
For this purpose we'd like to group some variables into a single variable. <br/>
|
||||
This is what `struct` allows us to do. <br/>
|
||||
Let's create a `struct` for our customer
|
||||
|
||||
Let's create a new `go` file called `customers.go`
|
||||
|
||||
```
|
||||
package main
|
||||
|
||||
Customer struct {
|
||||
FirstName string
|
||||
LastName string
|
||||
FullName string
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Let's put it all together:
|
||||
|
||||
In `customers.go`, let's create a function to get customers
|
||||
|
||||
```
|
||||
func GetCustomers()(customers []Customer) {
|
||||
|
||||
//we can declare customers like this:
|
||||
marcel := Customer{ FirstName: "Marcel", LastName: "Dempers" }
|
||||
|
||||
customers = append(customers,
|
||||
Customer{ FirstName: "Marcel", LastName: "Dempers" },
|
||||
Customer{ FirstName: "Ben", LastName: "Spain" },
|
||||
Customer{ FirstName: "Aleem", LastName: "Janmohamed" },
|
||||
Customer{ FirstName: "Jamie", LastName: "le Notre" },
|
||||
Customer{ FirstName: "Victor", LastName: "Savkov" },
|
||||
Customer{ FirstName: "P", LastName: "The Admin" },
|
||||
Customer{ FirstName: "Adrian", LastName: "Oprea" },
|
||||
Customer{ FirstName: "Jonathan", LastName: "D" },
|
||||
)
|
||||
|
||||
return customers
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
In `main()` we can now call our shiny new function
|
||||
|
||||
|
||||
```
|
||||
customers := GetCustomers()
|
||||
|
||||
for _, customer := range customers {
|
||||
//we can access the "customer" variable in this approach
|
||||
fmt.Println(customer)
|
||||
}
|
||||
```
|
||||
|
||||
# Docker
|
||||
|
||||
For our dev environment, we have a simple image using `go` <br/>
|
||||
We also set a work directory and alias the target as `dev`
|
||||
|
||||
This means we can use this container layer as a development environment. <br/>
|
||||
Later down the track we can add debuggers in here for example. <br/>
|
||||
Checkout my debugging video for go: https://youtu.be/kToyI16IFxs <br/>
|
||||
|
||||
|
||||
## Development environment
|
||||
|
||||
```
|
||||
FROM golang:1.15 as dev
|
||||
|
||||
WORKDIR /work
|
||||
```
|
||||
|
||||
## Building our code
|
||||
|
||||
```
|
||||
FROM golang:1.15 as build
|
||||
|
||||
WORKDIR /app
|
||||
COPY ./app/* /app/
|
||||
RUN go build -o app
|
||||
```
|
||||
|
||||
## The Runtime
|
||||
|
||||
```
|
||||
FROM alpine as runtime
|
||||
COPY --from=build /app/app /
|
||||
CMD ./app
|
||||
```
|
||||
|
||||
## Building the Container
|
||||
|
||||
```
|
||||
docker build . -t customer-app
|
||||
|
||||
```
|
||||
|
||||
## Running the Container
|
||||
|
||||
```
|
||||
docker run customer-app
|
||||
```
|
Loading…
x
Reference in New Issue
Block a user