Transcript
This transcript was autogenerated. To make changes, submit a PR.
Hi everyone, my name is Hussain, I am software development teammate
of hellocast cloud. In this session I will try
to provide some best practices about Golang in theory
and I will do a demo about what we see inside
the theoretical information. So as an outline we will see
what is Golang, we will see how to set up development environment,
couple of Golang examples and by using this
examples how to write best and at the end
we will see how to build an artifact out of these Golang projects
to be used inside CI and CD platforms.
Golang is a statically typed compiled language and it is originally
designed by Robert Gresimer and Rob pike and Ken Thompson while
they are working at Google. This is very similar to C language
but there is a memory safety and the garbage collection stuff
in this language. Remember CNC times you need
to alloc on melloc memory in order to do some operations,
but here you are free to do anything without touching on the
memory part. And if you want to deep dive any kind of topic in Golang
you can just refer the landing page because it is golang.org.
Before writing code you need to download the Golang binary
in your system. You can just go to Golang download page and
download your distribution based on your operating system. In my case
I'm using macOS and I will download this macOS distribution
if you are preparing a project creating a project these
project dependencies are a very important topic. In Golang
there is a system which is called Go modules. With Go modules you
can implement modular applications plus you can manage your dependencies.
In the examples you see I say go mod in it and
my version control system URL it will create a modular
application. Of course it is empty. There will be only one file which
is called Go mod file. And here after Gomode init
you see it is dependent to GitHub.com, my outdoor name and
my repository. But you can use GitLab, BitBucket or maybe
if you have a custom version control system service you
can also use that inside the Go module. When you have a look at module
file you will see a module information calling version and if you have
dependency you can see also dependent sections by
using required keyword. In order to see all the dependencies
you can say goal list m all you will see
your exact dependency plus the recursive dependencies needed
by this library. Okay, you know how to use
Golang, I mean the distribution and you know how to generate an
empty project. Now you can select
one of your favorite ides, but as an example, if you are using
Vim terminal, you can use Vimgo plugin. If you are using intelligence products
you can use Golang or you can use vs code as an alternative.
If you are using Vim terminal, then by using
go ran command you can just run your application.
If you are using Golan, you can define a run
configuration to run your project in vs code. You can
run your application by using control plus f five. So this is
very fresh start about writing something and
just running your application to see what's going on.
When you create a resource file in Golang, it will start by a
package statement. Here I am saying that my package name is main
and right after that I have some import statements. I depend
on context package, fmt package and GitHub package.
Here, if you define your package name as main, this will be
an executable rather than a library. For example,
when you have a math package, it will be a library package.
Then you can put your functions inside it. But in our case this
is just for executable very initial principle of
any kind of programming language. Variable declaration here
in the first example you see I declare a variable. I am
saying that count is a variable and it is type. It's integer. The second
line you see I am assigning some value to it. Count is equal to five.
When you say limit colon is equal to 15. You are just declaring
and assign a value to a variable. So this is also known by calling language.
In this following example you see I am defining a slice
which is called list arrays relies on other
languages. It starts with square brackets,
and I am saying that this will be a slice of integer and I put
some values inside it. In the following example you see
there is a nums slice, but this time I am allocating a slice
size. So I'm saying that there will be an integer slice,
but its size will be three, and the very first value,
the zero index value will be one. In my case.
Also, you can define two dimensional slices here and the
value is flot 54. As the final example you
see I am defining a map. It is a key value store. In my case,
keys is data, type is integer, the value will be string.
Let's say that this is the student information map.
The key is student id and the value is student name. In order
to declare a function in Golan you can use funk keyword and it's
followed by a name. Here sum. We open the parentheses
and put arguments inside it. A and b the return type is integer
and of course you provide your return function body. In the second example very
same, but the return type is a bit different. For example,
if you have scala before you remember the tuples,
so sometimes you may need to return multiple values.
In my case I just wanted to state x and y coordinated
separately. Here in the third example, you see there is a do
something. In do something, the function
name starts with a lowercase letter. That means this function will
be a private the first two will be exposed to outside, but third one
will not be exposed to outside. When it comes to usage, you see I am
saying functions sum provide your arguments and it
will return a value. Just assign a variable. Another example,
get coordinates. You see, it returns two values and I am using
x and y in order to use different references to these
returned values. Control structures are very important to
define your business logic, right? You decide on something.
I define an if function. Here it takes a parameter category.
If category is shoes, I print show. Otherwise I print
not a show. The main difference between other languages is
there is no parenthesis right beside the if statement. In the switch statement,
very similar case, you provide your variable and
switch statement followed by one or more cases. And at
the end there is a default case if it is a pc.
If device is a pc, just stay at home. If it
is a laptop, you can go outside. What about for loops in
Golang? Again there is no parenthesis. I starts with zero
up to ten v increment I by one. Here,
if the number is divided by two, I am continue. I'm saying
continue. That means just skip to next iteration without
printing the current number. And in the second example
I define a counter variable with initially initialized by zero
and there is no statement beside the four. That means this is an infinite
loop, right? And inside this infinite loop I am saying that if
the counter is equal to ten, just break. That means just
break the loop, otherwise it will increment counter by
one. Here there is no for each function in Golang,
but you can simulate it. I defined a number slice that
contains four numbers. Inside the for statement there
is a key value pairs. But why there is an underscore in the key
part? Because I am not interested in the
key part. So in golden if you define something
but not use it, the compiler will start to complain about it.
So if you are not interested in it, just put an underscore.
You say range numbers and in this time you will get number.
In iteration we are just printing the specific
number inside the slice. In the second example I have a map.
This time it is string string key string value string. It is
simple, a country code and the country name keystore here.
This time I am interested in both key and the value part called country
and I am printing the code and country at the same time into the standard
output. So I have functions,
variables, etc. Let's try to test this one. In Golang
you can use built in packages like testing, but also you
can use testify which is a third party library.
If you like more assert like operations.
If you need mock related operations, you can use mockery
which is a third party library. Also you can use Golang mock in
your system. So I will not deep dive into mock
part because it really deserves a separate session. But when it
comes to unit test part, let's try to test a function which is
called fibonacci. I have a Fibonacci function. It accepts
a number as a parameter and it tells you what is the value
at that number index. So here I am injecting the
testing t reference to my function and keep in mind that
my function name start with test. This is the naming convention. If the
result is not 610 it
will start to complain about I want 610 but got
another result. But what about if you want to test this function
fibonacci with different kind of multiple inputs, then you can use
test table here. Inside my test fibonacci in batch function
I am defining a struct slice of struct and
it accepts two parameters, input and expected. Here I have
five scenarios, test cases and inside the for loop I am iterating
these parameters calling Fibonacci function.
I am trying to verify if actual is equal
to parameter or not. Otherwise it will start to complain about this one.
You write best, but what about coverage? You need to know
how much part of your code base production code is covered
by best. Right here. When you say go best provide the test
folder and when you say dash cover it will calculate the coverage.
When you provide dash cover profile and some file,
it will put the report in this file. So this is very useful,
especially if you want to do further operations. Something like generate
HTML output. Like operations.
Okay, we generate this coverage because they are
already being used inside the CI systems, right? For example,
if you are using sonar, then this coverage file will be used
for sonar to analyze your code base. Maybe put as some kind of thresholds
in CI CD part. I will not talk about something like Jenkins maybe
or GitHub Excel or something like that. I will try to give
information about the very minimum unit of the CI
CD systems, the artifacts.
Golang has built in tools to generate artifacts based
on our distribution. So in order to see supported disk platforms in Golang
you can use go tool disk list.
So in the table you will see your supported operating
system and the architecture. In my case I'm using macOS.
The value is Darwin AMD 64. In order to
build a project to generate some binary you can provide your
operating system and architecture and when you say go build,
the binary will be generated based on these distribution parameters.
So why do you need this binary? Because it is
very popular inside the contain world. For example, I create
a docker file and I put some contents inside
it. So here I am saying that I will drive my docker image from Golang
and I provided alias as builder. I create a folder,
I make my folder to USRSRc
app. I copy all of project files to the
docker context. I download my dependencies by gomodownload and
generate my binary. But this time I'm providing all parameter
to change the output name. This is the
first stage, but in the second stage I am driving my docker image
from scratch which is the zero sized docker image.
I am copying the binary generated on the first phase to
my stage. Then I am providing this hello binary
as an entry point into this image. So we are
calling this strategy as multi stage docker.
Bill I believe that the theoretical information was
enough for this session. Let's have a look a couple of demo by
using these theoretical informations. Let me open my terminal
first I will create a folder.
Let's say that conf
here go mod okay
you see there is only one file here go mode.
Let's open this one by using Golang
I am using goal end for my projects file.
Open presentations.
This one let
me open. Okay it is already in presentation mode.
So here when you open Gomot file, you will see
there is only module information plus there is a version information.
I will start creating a main file.
Main in this file, this is Golang
by default. Adds this package, the folder name as a package in this file.
But I will change this one as main because I want this package to
be executable. Funk main.
You see this main is a special function. You can run it.
Let's do our famous stuff.
Print run hello world.
Okay. When you run it,
you will see it is in the output. Cool.
Let's start with the variable declarations. But I will create a separate directory
for this variables and a separate
profile variables in
this file let's define a function. Let's say that run
in this run function we can define our
variables arcount. Let's say that this will be an integer
and the value will be 34.
Just print this one.
You see, it complains about you defined it, but you have not used it
count.
Okay, so let's try to run this
one from main functions.
Variables run. You see, this import
is automatically added to this resource file.
Hello world 34. Let's continue to define
a couple of variables. Here the inline one limit
is equal to ten. What else
we can define the slice numbers is
equal to square bracket,
two, five, seven,
what else? We can
define a limited slice here it
you can define this length in advance. Let's say that this is
two,
this is limit,
this is numbers,
and here let me do something. The first
value will be this one. Duplicate it.
Let's try to compile this or run this.
Let's see what happens.
It okay,
I did something wrong. One,
two,
you see index out of range, two,
because you define the limit two, but you are trying to add the
third item, right? I will delete this one to make it work.
So if you do not add for example,
second value, then you will see the value
will be filled by the default values, which is zero is
the default value of the integer type.
What else we can define students
map in this
case, I am saying that the student id
and the grade lot 64
here, student id is one, the value is
this one, and student Id is two,
and value is 100%
here. And just print students.
This is wrong.
It all right, let's write this function. Run this
function again, and as you can see it is correctly
working. What about functions? Let's switch to functions.
Here I define another directory functions.
Just create another resource file functions.
Here I define some
function. It takes a and b as integer and returns
integer. You see, you don't need to define integer for all of the types if
they are repetitive. You define your variable names and integer. I think
this is valid for typescript also.
You return a
plus b. Right, let's do another one.
Funk. This time it will be multiply,
multiply ab. They are
integer return integer return ab.
So here, in this case, one function
starts with capital letter, another starts with
lowercase letter. Here, let's go to main
function. Just comment
this one functions sum. But what
about you see,
there is no multiply.
Why? Because it is private. That is the commission inside codelack.
Okay, inside some function, just provide
45, 55 and wrap
it with here.
Hello world. The values 100. This is it
for functions. What about testing?
In my functions package I am creating
a file which is called functions test.
Okay, you see, the icon is changed for
best in Golang. In order to write a test,
you can start with test keyword and it will automatically
suggest you to sum. So I am testing sum result
is equal to sum two
three. Here, if result is
not equal to five, then T-R-F
wanted five cut
result. Let's run this
one. So basically we are using t reference in
order to verify something. But let's say that you
change this function to something
like this. Then when you go back to function
and run it, you will see one
five but got six. So when you change production code by
doing this, you may understand. Okay, there is a problem.
Let's delete this one. Okay, what about
test tables funk this time
let's say that test sum in fetching
t here I will define a
struct,
something like you define a JSON inside Javascript or typescript,
or you define a map in any kind of
language. So inside the struct you can define your variables
and types, something like this. This is slice of struct.
So let's say that you haven't defined any kind of object,
you don't have an object, but you can define something like this. This will
be the input, let's say that integer and
the expected output. So this is
a table. Now I can
put my values inside it.
Okay, this will be a a.
There will be a b.
Unexpected. So if you provide two and three to the function,
you need to get five. What else? If you
provide this one and this
one, it will be.
Let's put some wrong values. For example
100 200,
it will be 400.
Okay, this one's
then in order to run it, four.
I'm not interested in the index, I'm only interested in parameter
range parameters.
Let's call the sum function and provide parameter
a. Parameter b.
Then parameter
not parameters, parameter b. Assign this
one to a value. Okay, sum is cool.
If sum is not equal to parameter
expected, then you can say t error
f wanted something,
got something so invanted part
parameter expected.
Another one is sum. So let's execute
this function and see what
is going on. You see, wanted 400 but
got 300. You see, that means this
shouldn't be 400, this should be
300. Another one wanted five but got seven. You see,
this is seven. Just execute this one.
But normally you don't change test
code most of the time. So you change
test, but right after change production code.
Okay, this is test. What about coverage?
You can just select this one and run with
coverage. You can say that, or you
can do this. Just open
terminal in
terminal go. Best cover
this one. So you see the coverage of the functions
is 50%. There is no coverage in arrivals part
in functions because there is also multiply function. But I
cannot test it right now. And what about
this coverage alt file?
Let's test. Yeah, you see, go to cover.
I just wanted to see HTML output of this one.
When you do that, you will see the HTML output.
I cannot show it right now but let's continue with the column
part. What can we do next?
Yes, so we can talk about building artifacts right
here. Let's try to build an artifact.
Go build. In my
case this will be, let's say the conf 42.
When you do a build operation, you will see binary
will be generated. Something like this. And when you
execute it, you will see the same output.
Very simple. What about using this one in the containerization?
Generating a Docker image let's create a docker
image for this docker file
here in docker file I will start from
calling as builder.
Okay. This is my first stage and
I will do run.
I will create a folder first and
change my work directory to this one.
Then I will copy everything from my project folder
to docker context. I will download all the dependencies
if I have any.
Then I will generate my binary.
So this will generate a binary. Then in the
second stage I will use scratch image.
Then I will copy from
builder. So from the first stage in this path I
will copy from the builder at this page to mypad.
Let's say that bin app and just
put this one to entry point as
bin app. Let's try to build this one.
Docker build ht let's
wait for this. It will
download the Golang docker image and use it.
Build a docker image and then generate something. Let's see
Docker images. You see we have conf fourty two and
the size is only 1.
When I run comfort I got exactly
same output from this part. So that was
all for this session. Thanks for listening the theoretical information
and watching for my showcase about the calling
usage. Hope it was a very useful
session for you. Maybe see you in the next sessions.