All language subtitles for English_auto_generated_Go_Programming_–_Golang_Course_with_Bonus

af Afrikaans
ak Akan
sq Albanian
am Amharic
ar Arabic
hy Armenian
az Azerbaijani
eu Basque
be Belarusian
bem Bemba
bn Bengali
bh Bihari
bs Bosnian
br Breton
bg Bulgarian
km Cambodian
ca Catalan
ceb Cebuano
chr Cherokee
ny Chichewa
zh-CN Chinese (Simplified)
zh-TW Chinese (Traditional)
co Corsican
hr Croatian
cs Czech
da Danish
nl Dutch
en English
eo Esperanto
et Estonian
ee Ewe
fo Faroese
tl Filipino
fi Finnish
fr French
fy Frisian
gaa Ga
gl Galician
ka Georgian
de German
el Greek
gn Guarani
gu Gujarati
ht Haitian Creole
ha Hausa
haw Hawaiian
iw Hebrew
hi Hindi
hmn Hmong
hu Hungarian
is Icelandic
ig Igbo
id Indonesian
ia Interlingua
ga Irish
it Italian
ja Japanese
jw Javanese
kn Kannada
kk Kazakh
rw Kinyarwanda
rn Kirundi
kg Kongo
ko Korean
kri Krio (Sierra Leone)
ku Kurdish
ckb Kurdish (Soranî)
ky Kyrgyz
lo Laothian
la Latin
lv Latvian
ln Lingala
lt Lithuanian
loz Lozi
lg Luganda
ach Luo
lb Luxembourgish
mk Macedonian
mg Malagasy
ms Malay
ml Malayalam
mt Maltese
mi Maori
mr Marathi
mfe Mauritian Creole
mo Moldavian
mn Mongolian
my Myanmar (Burmese)
sr-ME Montenegrin
ne Nepali
pcm Nigerian Pidgin
nso Northern Sotho
no Norwegian
nn Norwegian (Nynorsk)
oc Occitan
or Oriya
om Oromo
ps Pashto
fa Persian
pl Polish
pt-BR Portuguese (Brazil)
pt Portuguese (Portugal)
pa Punjabi
qu Quechua
ro Romanian
rm Romansh
nyn Runyakitara
ru Russian
sm Samoan
gd Scots Gaelic
sr Serbian
sh Serbo-Croatian
st Sesotho
tn Setswana
crs Seychellois Creole
sn Shona
sd Sindhi
si Sinhalese
sk Slovak
sl Slovenian
so Somali
es Spanish
es-419 Spanish (Latin American)
su Sundanese
sw Swahili
sv Swedish
tg Tajik
ta Tamil
tt Tatar
te Telugu
th Thai
ti Tigrinya
to Tonga
lua Tshiluba
tum Tumbuka
tr Turkish
tk Turkmen
tw Twi
ug Uighur
uk Ukrainian
ur Urdu
uz Uzbek
vi Vietnamese
cy Welsh
wo Wolof
xh Xhosa
yi Yiddish
yo Yoruba
zu Zulu

Original subtitles

welcome to this comprehensive go

programming course for beginners

throughout this course you'll learn key

Concepts and techniques to write

performant idiomatic go code you will be

guided by the expertise of Lane Wagner

and Alan lers who combined have over 18

years of coding experience alongside

mastering topics such as variables

function loops and more you'll also have

the opportunity to apply your new found

skills in seven real world projects

ranging from building an RSS aggregator

to implementing authentication with API

keys so get ready to unlock the

incredible potential of go go has been

exploding in popularity recently it

feels like all the most modern tech

companies are using go to build scalable

backend infrastructure it actually makes

a lot of sense Go's fast lightweight has

an amazing developer experience and is

actually super easy to learn stick

around and in just a few minutes I'll

explain the rest of the reasons why go

could be a game changer for your coding

career at this point I'll just introduce

myself really quickly I'm Lane the

founder of boot. Dev and I've been

writing go for a little over 7 years and

I've been building software for about 10

I've actually spent over 2 years

designing this go course and I've taught

thousands of students with this material

the feedback from all of my students

over the last couple years is actually

been Incorporated in the course so

everything is very battle tested and up

todate I was actually just making some

updates yesterday so how does this

course actually work well we're going to

start by doing over 100 handson coding

lessons and exercises now when we're

done with all of that you'll actually

have a really strong grasp on the

fundamentals so at that point we'll go

build a production ready back-end server

Ino from scratch now I'm begging you

please do not binge watch this video

tutorial hell is a very real place and

it's a place that you will go if you

don't write your own code get your hands

on the keyboard and write some code with

me in fact you should actually be coding

ahead of me and only using my Solutions

when you get stuck so head over to boot.

and create a free account that's where

all of the code samples for this course

are hosted now alternatively I have

linked a GitHub repo in the description

below all of the raw code for the

samples in this course are hosted there

it won't be quite a streamline of an

option but it is an option now you

should also know that this course is

just one part of the full back-end

developer career path over on boot. so

if you're interested in going from zero

to hired as a backend developer you

should definitely check that out too now

as long as we're talking about external

resources know that if you get stuck

during this course you have some options

for help first you've got the boot. deev

Discord second you've got the free code

Camp Discord and third you've got the

free code Camp Forum I will link all of

those down in the description below okay

one last thing before we jump into the

course if you want to connect with me

personally or you want access to my

other go and backend content then you

can follow me on Twitter wag lane or you

can subscribe to my YouTube channel at

boot. I'll link both of those down in

the description below with all of that

out of the way let's talk about go

everyone always wants to talk about how

fast the go programming language is

let's talk about it and let's compare go

to some of the other more popular

programming languages so in terms of

execution speed

execution

speed go is much faster than JavaScript

python Ruby and PHP pretty much any

interpreted language a language that's

not compiled is going to be slower than

go because go is a compiled language now

don't worry too much if you're not

familiar with the terms compiled and

interpreted we'll talk about those in

just a minute for now just understand

that go is much faster um than these

languages when it comes to executing

programs if we're doing computationally

heavy work go is going to be much more

performant um than some of these other

languages now here on the other side

I've listed some compiled languages so

when it comes to compilation

speed compilation

speed go is actually much faster than

these compiled languages when it comes

to compiling the code now again we'll

talk about compiling in a minute but for

now just understand that you have to

compile your code before you can can run

it when you're working with a compiled

language and so by having a fast

compilation speed like go has it

actually increases developer

productivity quite a bit we can iterate

more quickly on our code we can deploy

it more quickly it's not as expensive to

run tests to compile uh the program and

deploy it to production um so this is

actually a huge benefit that go has now

I do want to point out that go does not

necessarily run faster it does not

necessarily have a faster execution

speed than all of these languages but it

does beat them handily when it comes to

compiling not to beat a dead horse but I

want to talk a little bit more about

execution speed so we talked about how

go is generally faster than the

interpreted languages right python

JavaScript Ruby PHP and so on it gets a

little interesting when we compare go to

kind of the natively compiled languages

or the languages that compile directly

to uh kind of machine code that runs on

your CPU versus the compiled languages

that run on top of a virtual machine

right so the the two big ones that run

on a virtual machine are Java and C

while some of the compiled or natively

compiled languages that you'll be

familiar with might be rust C C++ even

though go is a natively compiled

language a language that compiles

directly to machine code like rust C and

C++ its execution speed is actually more

similar to Java and C when it comes to

its runtime speed how many computations

it can do kind of per second and we'll

talk more about this later but the

primary reason for that is the go run

time there's basically a chunk of code

that's included in every go program that

manages memory and that tends to slow

down the execution speed a little bit

that said it is worth pointing out that

a go program tends to use much less

memory than Java and csharp because

there isn't a need for an entire virtual

machine here we are the first coding

challenge let me break down what we are

supposed to do and then I'll kind of

explain what this code over on the right

actually does so um our assignment is to

log the string starting textio server to

the console instead of hello world so

throughout this course we'll be building

out little pieces of the textio product

which if you're familiar with twilio

it'll kind of be like a twilio clone

it's a kind of backend server that sends

SMS and email messages and works a lot

with kind of text textual data every

file of go code has a package

declaration at the top here we have

package main simply because this program

builds into an executable go program

right so we can run this code kind of

Standalone the next line is importing

the fmt package from the standard

Library we are importing it because

we're using it down here within the main

function now the main function is the

entry point to the program so every go

program starts exec ution at the top of

the main function which is just a

function named main that takes no inputs

and doesn't return anything on line six

and seven we have some single line

comments these don't execute they are

not part of the program they're just

there for documentation and single line

comments just start with that double

slack finally on line eight we have the

one thing that this program actually

does which is print the string hello

world to the console so let me go ahead

and run

that see down here it printed to the

console it's using the stand libraries

fmt package um and the print line

function that is exposed from that

package uh to do so so the assignment

here is pretty simple uh we're just

supposed to swap out that hello world

message for starting Tex iio server

going to run that and make sure it looks

like what I would

expect we're good to go next let's fix a

quick bug I love quick wins um we're not

going to talk about all of this syntax

in this program what we're interested in

is just fixing the math bug on line 17

so the assignment description says texo

users are reporting that we're billing

them for wildly inaccurate amounts

they're supposed to be build

for2 for each text message they

send something else is happening so the

total cost here is being set to the cost

per message plus the number of messages

now that doesn't make a lot of sense to

me go ahead and pause the video see if

you can figure this one out on your own

um to me it looks like the cost per

message should be multiplied by the

number of messages right and let me let

me run it like this so that we can see

Doris spent 4.02 on text messages

today four

messages that doesn't make sense right

for four messages she should not be

build $42 if each message only cost 2

cents so I'm going to go ahead and

change that to multiply I would expect 8

cents yep Dora spent 8 cents on text

messages today cool going to go ahead

and submit that this is one of my

favorite XKCD Comics uh you can pause

and read it uh really quick if you'd

like slow and resource expensive

compilation times a really terrible

thing to work with I've worked on

systems in Java and C++ that took over

an hour to compile the code that means

that if we find a bug and we want to

deploy it to production even if we get

the bug fixed within five minutes it's

still going to take an hour just to

build the new production version so that

we can deploy it on our servers I've

personally never worked on a go program

that's taken more than just a couple of

seconds to build and compile so the

first question is go code generally runs

blank than interpreted languages and

compiles blank than other compiled

languages like C and rust so the answer

is going to be faster and faster right

it runs faster than inter most

interpreted languages and it compil Iles

faster than most compiled

languages so the question on this one is

does go generally execute faster than

rust the answer is going to be no so

I've thrown around this word compilation

or compiled a few times but we haven't

really talked about what it means when

we write

code we write it in a human readable

format right typically in a file in the

case of go A.O file right maybe main.go

and this file is going to contain

human readable text right go code that

we as developers work on the thing is

your computer's Hardware doesn't know

what any of that human readable text

means your computer's CPU only

understands

binary right which is ones and

zeros right which at the end of the day

is just numbers right but it's just

numbers and simple operations things

like add and subtract so we need some

process that we can use to convert human

readable code to machine code that can

be executed by the computer's hardware

and that's all that compilation is

compilation is just the process of

taking some human readable code right go

code in our instance and converting it

to Binary or machine code that our

computer can actually understand so what

does this process actually look like

Well normally you'd start by writing

your go program so say main.go

and you'd run it through the go compiler

on your command line you'd type go

build and that would produce a new file

which is the executable program let's

say we're doing a hello word a hello

world program it might be

hello

world.exe

right an executable program on your

computer and you could run that

executable directly on your operating

system without ever having to use the go

tool chain again so the great thing is

you can take this hello world.exe

program and give it to someone else and

they can run it on their computer

without ever having to install the go

tool chain or even know that you used go

to build the program in the first place

this is different than languages like

python where if you want to run

someone's python code you have to use

the python interpreter every single time

time and you run the source code you run

the source code directly on your machine

it's also worth pointing out that part

of the reason that compiling is so much

faster at runtime is that we do all of

this compiling work upfront so when we

go to run the executable we don't have

to do any conversions from Human

readable text to Binary machine code

that's different than how interpreted

languages work with an interpreted

language as we run the program The

Interpreter is reading the human code

and kind of at runtime converting it to

machine code that the CPU can operate on

so you might be wondering where is the

compiling Happening Here on botev well

we actually do the compiling and the

running at the same time for you so when

you click the Run button um we're

actually taking your code shipping it

off to our servers compiling it running

it and giving you the result don't worry

when we get down the road to the actual

project you'll be building and running

your own go code on your own machine but

we can see the difference between a

compiler error and a runtime error even

here on Bev so for example um here in

this code the assignment says to pass

this exercise fix the compiler error in

the code so I'm just going to run it as

is and you'll see we get this nasty

error here and it says main.go right

line six syntax error this is actually a

compile time error so we weren't even

able to compile this code it didn't fail

at runtime it failed compile time right

which again that distinction will become

more clear a little bit later so anyways

um we can fix it by adding that Clos

parentheses that was

missing and now it compiles and runs

just

fine so to review go code like this

little go program here that prints hello

world that's not understood directly by

the hardware on your computer your

computer's processor or your computer's

CPU

understands machine codee so we need to

take our human readable go code run it

through the go compiler to produce the

machine code that we can run directly on

our CPU right the CPU is designed by the

manufacturer to run a specific format of

binary cool so the question for this

exercise is do computer processors

understand English instructions like

open the

browser no processors are not chat GPT

uh they need machine

code now we touched on this very briefly

before but I want to talk about how you

distribute a compiled program versus how

you would distribute an interpreted

program so let's say that you'd written

a script in Python so you've got this

script main.py right this is raw python

code and you want to give it to your

friend so that they can run your script

well all you would do with an

interpreted language is give your friend

the main.py file and then on their

computer they would run the command

Python

main.py and they'd be able to run your

code now there are a couple of downsides

to this approach the first problem is

that your friend needs to have python

installed on their computer so your your

friend being able to use your program is

dependent on them already having python

installed it's even dependent on them

knowing how to use it or knowing how to

use a command line right so Distributing

the programs of interpreted languages

can be tricky because it's really only

useful if you're Distributing to other

developers who know how to use these

tools already the other problem is the

code itself let's say you spent you know

many weeks writing this python script

and it's super useful and you're trying

to sell it to customers if you just give

them your python code I mean they

effectively own it they can change it

even if you didn't intend for it be open

source congratulations it's now open

source the problem is you can't really

allow someone to use your program

without giving them all of the Special

Sauce that makes it work let's review

how this works in a language like go so

in go we'd start the same way right we'd

write some human readable go code in a

file called main.go but instead of

giving that file to our friend we're

going to compile it

first going to compile it

we'd use the go go tool chain so we'd

write something like go build in our

command line and that would produce a

new executable file right so this is

this is machine code here um let's just

say that the name of our program is

Hello World why

not so if we're on Windows it might be

hello world.exe

right so when you go online and you

download a program to use say it's a

video game um it is probably

a bundle of machine code it is a built

binary right in order to run your

favorite video game let's say Starcraft

2 or World of Warcraft you don't need to

install the C++ compiler right you're

just given the built kind of final

product the final executable program and

that's what we're doing in uh the go

programming language as well so now we

can give our friend this

executable they don't need to install go

and they do not need access to the

original source code so generally

speaking Distributing programs that are

natively compiled is much much easier um

than Distributing programs that kind of

have a runtime dependency like an

interpreter so to answer the question

for this exercise do users of compiled

programs need access to the source code

no they don't and a related question

which language is interpreted we've got

go C++ Python and rust and the answer is

python the rest are all compiled so now

the question is why is it generally more

simple to deploy a compiled serers side

program or backend application and the

answers are compiled code is more memory

efficient because Docker exists there

are no runtime language dependencies or

because compiled code is

faster well it's just the same as what

we talked about earlier um when we

deploy to a server say on the cloud uh

we have to have all of the dependencies

uh that our backend application needs in

order to run installed on that server

and if there are no runtime dependencies

if all we need is a compiled binary then

that's arguably the simplest way to do

it right so the answer is it's more

simple to deploy a comp to deploy a

compiled program to a back-end server if

there are no runtime language

dependencies things like the python

interpreter or The nodejs Interpreter

for example go is strongly typed and

statically typed and that's a really

good thing if you've been paying any

attention at all to the JavaScript World

you'll notice that a lot of JavaScript

developers are making the switch to

typescript and that's primarily to get

access to static typing a lot goes into

typing and type systems but one of the

biggest benefits of a static type system

like goes is that when we declare a

string right like say this username

string that I've set equal to wag Lane

we can't later accidentally change it to

an integer a number right like a float

64 um it's going to stay a string the

nice thing about a static type system

like we have with go or that you have

with typescript is that we get feedback

on our errors uh much more quickly right

rather than finding out about a bug when

our code is running in production we

find out about the bug say when we

compile our code let's move on to the

assignment the the assignment says we'll

be using basic authentication for the

text iio API so basic authentication is

is just this format here where you've

got a username and a password um in an

HTTP header it tells the server on each

individual request to the server who you

are right it's kind of like logging in

um or rather it's kind of like being

logged in okay uh so the code on the

right has a type error change the type

of password to a string Okay cool so I'm

just going to run it to see the type

error first so invalid operation

username plus colon plus password has

mismatch types of string and int now

this is a compile time error we we

weren't even able to compile this code

right let alone run it in production um

so we've been instructed in the

assignment change the type of password

to a string but use the same numeric

value so that it can be concatenated

with the username variable Okay cool so

I'm just going to change this to a

string by surrounding in double quotes

that's how you do strings and go

pretty similar to other languages and

then I'm just going to change that type

to a string type and run it again

authorization basic wag Lane colon

number that looks good to

me when we're talking about the

performance of a programming language or

an application we really care about how

it performs across two different axes

one is speed how fast it can do

computations right which is kind of

measured in CPU cycles and then we also

have memory consumption which is just

how bloaty the program is how much data

it has to store in memory to be able to

do those computations every program you

write no matter the language is going to

be using memory every time you create a

new variable it allocates space in

memory where it can store that

variable's data now in languages like

rust or C memory management is

effectively manual now that said Russ

does have some nice tooling that kind of

takes care of it for you at compile time

so it's not quite as error prone um as

as it would be in C or C++ but at the

end of the day your program is

allocating memory right it's saying this

chunk of memory I'm going to use I'm

going to store some variable data here

in this bit of RAM and then later your

program says I'm not using it anymore um

so we can free it up for use by other

programs now let's jump over to Java so

with Java it's a little bit different um

Java is a garbage CL CED language

garbage collection which essentially

means that memory management is

automated and in Java it's done by the

Java virtual machine so every time you

run a Java program you're actually

creating an

entire mini virtual

machine that your Java bite code runs

within so this is the

jvm and then you kind of insert your

code

into the

jvm and you run your code in there and

the jvm is what takes care of allocating

and freeing all of the memory that you

use and this creates overhead basically

at the end of the day Java programs use

quite a bit more memory than rust or C

programs go is in an interesting sort of

in between world where go is a garbage

collected language like Java so it has

automated automated memory management

but it does not have a jvm when you

compile go code rather than having to

run it within a jvm just like with Rus

and C you get one binary or one

executable program the difference is

that go includes a

runtime a

runtime within every single binary

that's built using the go programming

language so we could think of it as

something like this it's kind of like a

little side

car that is compiled

alongside your code so your go program

basically has this this little bit of

extra code that's added to it and that

bit of code is what handles garbage

collection and automated memory

management so it's a little more bloaty

than what you'd get with rust and C

right it is garbage collected um but

it's not nearly as um expensive in terms

of memory overhead as a language like

Java or C let's take a look at what some

actual numbers look like I pulled this

chart from Dexter darwick uh blog and if

you're following Along on botev you can

click the link to go check out the full

the full blog and the description of

this experiment but basically he built a

restful web server in three different

programming languages right in Java go

and rust and then me measured the memory

consumption and when the servers were

just at rest effectively doing nothing

and waiting for requests to come in Rust

used less than half of the memory that

go was using and go used 100 times less

memory right measured in megabytes than

the jvm was using to run the rest

service so to order the three languages

in terms of memory efficiency I would

say Java is the least efficient uh go is

in the middle and rust would be the most

memory efficient and it's also worth

pointing out just really quickly that as

the load on the server increases I would

expect go to have more similar

performance to Java in other words we

wouldn't see as quite a large

discrepancy here right go would likely

still be more memory efficient than Java

almost certainly in fact um but it

probably wouldn't be a 100x discrepancy

we're seeing this huge discrepancy um

mostly because this is an idol uh a test

of an idle program so generally speaking

which language uses more memory that's

going to be Java another question on the

same topic is what's one of the purposes

of the go runtime so to style go code

and make it easier to read that doesn't

make sense that would be like compile

time tooling right not run time tooling

to clean up unused memory to cook fried

chicken or to compile go- code so it's

definitely going to be to clean up

unused memory and if you remember

remember the runtime is just that little

bit of extra code that's included in

every compiled go program that among

other things handles memory

management so we've already talked about

how go has strong and static types but

we haven't yet talked about what those

types are you're probably already

familiar with Boolean values and string

values which are valid go types and also

exist in pretty much every other

programming language um numbers are

where it first starts to get a little

bit different uh if go is your first

compiled programming language generally

speaking numbers fall into four

different buckets we have integers

unsigned integers or uints floats and

complex numbers integers are just whole

numbers they can be positive or negative

right 1 2 3 4 you get the idea unsigned

integers are the same as integers but

they're not signed which basically just

means they don't have a negative

component you can only represent

positive numbers in in an unsigned

integer you probably already familiar

with the idea of floats it's just

fractional numbers right numbers that

have a fractional component things like

1.21 or

3.14 complex numbers are a little funny

they're used to represent the concept of

imaginary numbers if you've gotten to

imaginary numbers in your math studies

I've never actually used complex numbers

um in production I'm sure there are

plenty of use cases for them but we're

not going to go into detail on how they

work here you can certainly go read up

on it if you'd like the only other thing

worth mentioning is that size matters

when it comes to types A uint 8 and a

uint 16 are two different types they

both represent unsigned integers but a u

16 has twice as much room for data

within it it has 16 bits of data whereas

a u 8 only has eight bits for example

the largest number that you can store in

a uint 8 is 255 because that's the

largest number you can represent with

eight 1es and zeros in binary but with a

uint 16 the largest number you can store

is about

65,000 again because that's the biggest

number that can be represented by 16

binary digits just like bigger number

better person uh bigger number in your

types means you can represent more

possible values uh within that type so

float 64 can represent more values than

a float 32 the only reason you wouldn't

use a larger type is if you're trying to

save on memory if you're trying to write

a program that is hyper performant

you'll want to use a smaller size right

if you know that an integer is only ever

going to store three different values

say 1 two or three then you might

consider using a u and 8 the bite type

is an interesting one and it's one that

you'll use a lot especially when you're

say marshalling a Json object um to be

sent across a network connection or

maybe you're reading to and from a file

on disk um but under the hood a bite is

just an Alias for the uint8 type which

makes sense right a bite is just eight

binary digits eight bits and that's all

a uint 8 is a rune is a Unicode code

point which generally speaking you can

think of as one character in a string

and that's usually how it's used under

the hood it's just an alias for the

int32 type moving on to the assignment

it says initialize the given variables

to int float 64 bu and string

respectively with their zero values and

um as we can see here if we just use VAR

the name of the variable and the type

that should do it so we'll initialize

the variables here so

VAR SMS sending limit is an INT VAR cost

per SMS is a float

64

has as permission is

a

and username

is a string okay cool and all so all of

these variables are now instantiated and

should contain their zero value so for

example zero uh 0.0 false and empty

string so let's go ahead and run

that and that looks correct to me I'm

going to go ahead and submit it we've

been declaring variables the hard way

now we're going to do it the easy way

there is an operator in go colon equals

that is the short assignment operator

and it allows us to to declare variables

and have go infer their type so instead

of typing VAR empty string we can just

say empty colon equals the empty string

and go knows that this has to be a

string so it is a string now when we use

this short assignment operator we're not

saying this is a loose type that can

change in the future it's still a static

type empty is a string just like it

would be if we declared it this way in

reality in go you will very rarely see

variables declared like this you will

almost always see them declared using

the short the short assignment operator

for example num Carson equals 10 creates

a new variable called num cars and sets

it equal to 10 and its type will be

inferred to be an INT and the int type

Alias is either int32 or int64 depending

on your computer's architecture if you

want to specify a particular size of

integer then you would declare it using

this kind of lonand syntax so in this

assignment we're just meant to declare a

variable named congrats with the value

happy birthday using a short variable

declaration so as simple as congrats

colon equals the string happy

birthday let me run

that

perfect this next assignment says our

current price to send a text message in

texo is 2 cents however it's likely in

the future that the price will have to

be a fraction of a penny or have a

fractional part to the cost so we should

use a float 64 to store this value edit

the pennies per text declaration so that

it's inferred by the compiler to be a

float 64 Okay cool so

here we're just setting it equal to two

if I run that then I get the type of

pennies per text is int and this percent

T in go um is is a formatting verb that

that tells the go programming language

or or at least the print F function I

should say the formatting package from

the standard Library um that I want to

print the type of this variable rather

than its value so that's why we're

saying int there instead of

two um to get a float all we need to do

is change it from two to 2.0 I believe

64

cool another handy syntactic Quirk of

the go programming language is that we

can declare multiple values on the same

line so in this assignment it says

declare a float called average open rate

and a string called display message on

the same line okay so average open

rate display

message same line the average open rate

um must

be23 and the display message should be

the

string is the average open rate of your

message and then it looks like

this is just going to print them

together so it's going to say 0.23 is

the average open rate okay cool let's go

ahead and run

that 023 is the average open rate of

your messages that looks correct to

me so we've already briefly talked about

the different type sizes in go right so

we have the int type int 8 int 16 int 32

and int 64 and it's important to

understand that the int type just

aliases int32 or int64 um same with the

uint type just depending on your cpu's

architecture so you might be on a 32 or

a 64-bit machine most modern machines

are going to be 64 bits my

recommendation is that unless you have

an explicit reason to care about the

size right so unless you're trying to

kind of hyper optimize for performance

then you should really just stick to

these four types int uint float 64 and

again if you're working with imaginary

numbers then complex 128 but that's

honestly unlikely so so these three

types are going to do the vast majority

of the heavy lifting when it comes to

working with numbers in go we can also

convert numbers between you know

different number types for example we

could take a an integer 88 and convert

it to a float like this so it become

88.0 right um converting the other way

is a little trickier though because say

we had 88.6 if we were to convert it to

an INT we would lose the point 6 we

would truncate it down to just 88 now

this assignment says our text AO

customers want to know how long they've

had accounts with us follow the

instructions in the comment provided you

will create a new variable called

account age int that will be the

truncated integer version of account age

Okay cool so create a new account age

int here should be the result of casting

account age to an integer so we'll just

do int account age and I would expect

that to be two after casting it because

it should truncate the 6 so let's go

ahead and run that your account has

existed for 2 years yeah that looks good

to

me we already briefly touched on this

but it's worth mentioning again I

recommend that you stick to the I call

them the default types so for example we

know there's um you know five or six I

can't think of it off the top of my head

now different types of inss right int

int 8 int 16 in 32 int 64 I'd recommend

sticking to int unless you have a very

good reason to specify a smaller size

like int 8 or in32 and that's simply so

you avoid cluttering your code with tons

of type conversions that can sometimes

even lead to bugs so unless you need a

smaller type for performance reasons

just use these default types okay so the

question for this assignment is when

should you elect to not use a default

type when either a default or a specific

size will work when my system has lots

of extra Hardware that I want to utilize

or when performance and memory are

primary concern so it's going to be

performance if you have performance

concerns that's the time I would maybe

stray away from the default

types the next question is what does the

size of a type indicate so a float 64

what does 64 mean is it bits bites or

nibbles uh the answer is going to be

bits now it is worth pointing out

nibbles is a real thing so a bite is 8

Bits a nibble is actually Four bits if

you didn't know that fun interesting

trivia aside from variables go also

supports constants which are immutable

values um and in go just like in

JavaScript or typescript we use the

const keyword and constants do not

support the short declaration syntax so

we have to kind of write it all

out okay so getting to the assignment

says use two separate constants

something weird is happening in this

code what should be happening is that we

create two separate constants Premium

plan name and basic plan name right now

looks like we're trying to overwrite one

of them okay cool so on line six we've

got Premium plan name and we're setting

it to Premium plan and then we have

Premium plan name again attempting to

override the value and set it to a new

string if we try to run this we actually

get a compile time error so we're not

allowed to mutate constants in go so

what we should be doing is creating a

separate constant and it should be named

basic plan name let's go ahead and run

that plan Premium plan plan basic plan

looks good to me constants in go are not

the same as constants in JavaScript and

in typescript in JavaScript and

typescript the const keyword really just

means you can't reassign to this

variable but you can compute the

variable or the variable's value at

runtime in go every value

that's stored in a constant must be

known or computed at compile time before

the program runs so if we create this

new constant called my int and set it

equal to 15 within the compiled go

binary effectively this symbol my in

just refers to the static number

15 the cool thing is that we can

actually compute constants like we can

make constants that depend on other

constants but that computation will run

when we compile our code not when we run

our code so for example um I can create

this constant first name Lane last name

Wagner and then I can create a new

constant called full name it's first

name plus a space plus and the last name

and that's really convenient in case I

ever want to change first name uh now I

don't have to change it in two places

right full name will automatically

update but this is only valid because

all of the inputs to this full name

constant first name and last name are

known at compile time so the compiler

can still do the thing it wants to do

which is replace full name with a static

string right lane space

Wagner so on to the assignment says

keeping track of time in a message

sending application like textio is

critical imagine getting at a point

reminder an hour after your doctor's

visit not very helpful right complete

the code using a computed constant to

print the number of seconds in an hour

okay so we've got the number of seconds

in a minute is 60 the number of minutes

in an hour is also 60 so how many

seconds are in an hour cool well we

could hardcode this as like 60 *

60 but the cool thing is we can actually

compute it because we can say well we

know the minutes the number of minutes

in an hour and we know the number of

seconds in a

minute and if we multiply those two

together we should get the number of

seconds in an hour

right that looks correct to

me so I'm obviously a huge go fan but

formatting strings in go is honestly one

of my least favorite features of the

language I think it's one of its

weaknesses at the moment who knows maybe

it'll improve in the future the way it's

done well we essentially have two

different functions provided to us by

the standard Library we have print F and

S printf printf prints a formatted

string directly to standard out and S

printf just Returns the formatted string

as a value basically all string

formatting in go currently works the

same way we have these formatting verbs

things like percent V percent s percent

D and they're replaced in the string

template with actual values so for

example I am percent V years old the

percent V in this case is replaced by 10

the first parameter uh that comes after

the template in the print F function

here we could also replace with a string

instead of an integer right I am percent

V years old way too many for I am way

too many years old percent V is sort of

the default formatter it's usually what

you want assume you don't want to print

in kind of the default standard way

using percent V then there are a few

others um percent S interpolates A

String percent D interpolates an integer

in decimal form so for example 10

becomes the number 10 instead of say in

binary form uh percent s is for floats

so you can specify the number of kind of

places after the decimal point uh that

you want printed out to the console or

printed out to The Returned string in

the case of s printf um so I actually do

end up using percent F fairly regularly

when I'm working with floats so onto the

assignment it says create a new variable

called MSG online 9 MSG stands for

message of course um it's a string that

contains the following High name your

open rate is open rate percent where

name is the given name and open rate is

the open rate rounded to the nearest

10's place okay so the 10's place is the

number right after the decimal so let's

get started here message colon equals

fmt dos printf so we're going to use S

printf instead of print F because we

don't want this value going to standard

out we want it returned from the

function so we can save it in the MSG

variable

let's just grab this

template so we'll use percent s we could

use percent s or percent V here because

we're just uh interpolating a string and

we'll do percent um .1 F because we

want to just print the

first number after the the decimal point

right the tenth

place okay and then we just pass the two

values as the following parameters or as

the last two parameters so name and open

rate right so the first value name will

go into the first verb the second value

will go into the second verb let's run

that see what we get hi s Goodman your

open rate is

30.5% that looks good to me let's talk

about conditionals in go so a

conditional is just where we are

checking if a condition is true if it is

we do one thing if it's not we may do

another so for example uh here's an if

statement in go and if this expression

evaluates to true then we'll run the

stuff within the curly braces the body

of the estatement if you're familiar

with other programming languages like

JavaScript this is um a very very

similar syntax the only difference is

we're not surrounding the height is

greater than four section with um

parentheses so again to be clear this

bit between the if keyword and the curly

brace um will be evaluated and if it

evaluates to true then the stuff inside

the curly braces will be executed um so

in this case we have the variable height

and we're using the greater than

operator um to compare it to the number

four so if height is greater than four

then we'll print you are tall enough

sort of listed um some of the different

comparison operators uh down here at the

bottom they are basically identical to

pretty much every other programming

language you will uh probably have used

uh up to this point additionally we can

do different things um if the if

statement does not evaluate to true so

this is a perfectly valid if statement

you do not need an else if or an else

block they are they're optional

effectively um but the way it works is

when we get to this code uh basically

we'll we'll uh compare height to six

right and if that expression evaluates

to true then we'll just print you are

super tall and we'll be done

okay otherwise if that expression

evaluates to false then we'll drop down

into this next if else or sorry else if

statement and we'll compare height to

four if height is greater than four then

we'll print you are tall enough and

again we'll be done at that point so if

this evaluates to true we execute this

um kind of section of code between the

curly braces and at that point we'll be

done otherwise if that's also false so

if height is not great than six and

height is not greater than four then the

else statement executes notice the else

statement does not have its own

expression it just kind of always

executes if all of the if and else if

statements um turned out to be false so

let's jump into the assignment it says

fix the bug on line 12 the if statement

should print message sent if the message

length is less than or equal to the max

message length or message not sent

otherwise Okay cool so up here we've

defined two variables uh message length

is 10 Max message length is 20 um and

then here we're going to do some

comparing let me just run the code in

its current

state says trying to send a message of

length 10 and a max length of 20 message

not sent okay so that seems problematic

right because with a message length of

10 and a Max message length of 20 I

should be able to send that message so

the Bug Online 12 I think we just need

to flip this operator to be less than or

equal to so that now this expression

right message length less than or equal

to Max message length should evaluate to

true because it is message length is in

fact smaller okay let's run

that message sent that seems to work

it's worth pointing out that in go we

also have kind of an alternate way to

write if

statements if the variable that we are

comparing in an if statement is only

used in that if statement then this

syntax can be helpful okay so here's

kind of the traditional way of doing

something we would create a variable

called length let's just assume it's an

integer you can kind of forget um this

function Syntax for now we'll talk about

it um in a future chapter but basically

the idea here is we have a length

variable it's an integer right and we're

initializing it here we're creating the

variable here um and then we're compar

pairing it against one right we're

checking if it's less than one and if it

is we're doing something in this case

we're printing that the email is invalid

well instead of this syntax and by the

way this works perfectly fine there's

nothing wrong with doing it this way um

but we can alternately do it this way

which is basically to initialize that

length variable in the if block within

that first kind of initial statement so

notice there's two statements here um

separated by a

semicolon and in the first one we're

creating that length variable and then

then we're moving the comparison itself

kind of after the semicolon and then if

that condition obviously evaluates to

true then we'll um execute the block

this does kind of two things for us

first it saves us a line of code um

which I would argue probably isn't the

biggest benefit in the world um but more

importantly uh it makes it so that this

length variable is only accessible

within uh kind of the scope of this if

block so kind of down under Neath this

code we wouldn't be able to use the

length uh variable anymore which is kind

of nice if you never intended to use it

in the first place you can kind of think

of this as a clean code hack or like a

um kind of safety hack um to ensure that

the length variable is never reused Down

Below in other code when you never

intended it to be reused okay so uh the

question for this assignment is why

would you use the initial section of an

if statement uh and the answers are to

confuse other programmers to keep the

code concise and the scope limited or to

speed up your code um the answer is

going to be to keep the code more

concise and to again limit the scope

that that variable um exists within like

other programming languages go supports

functions functions are basically just a

way to break up your code into

individual units that are easier to

reason about right a function takes in a

specified number of inputs and it

returns ears a specified number of

outputs for example this subtract

function here named sub takes two inputs

X and integer and Y an integer and it

returns a single integer in this case it

just performs the simple calculation x -

Y and then Returns the result to the CER

now this little bit right here right

Funk sub X integer y integer returns

integer is what's known as the function

signature if you've never heard that

term before it's basically just a

description of what the function does in

terms of its types in terms of its

inputs and its outputs and what types

they are right this basically says this

is a function called sub it takes an

integer X and an integer Y and returns

another integer function signatures are

great because they tell us how we can

use the functions really at the end of

the day if we're the person calling the

function or the person using the

function really all we care about is

what we need to give the function as

input and what we get out of the

function in terms of its outputs so a

function signature basically tells us

all we need to know about a function to

be able to use it it omits all of the

implementation details the stuff with

within the curly brackets or within the

body of the function so let's get on to

the assignment assignment says we often

need to manipulate strings in our

messaging app that makes sense right

we're working with SMS and email uh

messages within textio so we're doing a

lot of textual data manipulation the

concat function should take two strings

as inputs and smash them together right

so returning a new string that is a

concatenation of the inputs for example

hello Plus World equals hello world so

we'd expect to return this concatenated

string from our concat function over

here fix the function the function

signature of concat to reflect its

Behavior Okay cool so let me try running

this and just see what happens looks

like undefined

S1 undefined S2 undefined S1 okay so

these are

undefined

and so S1 and S2 that kind of stands for

string one string two that makes sense

the problem here is that we're

not we're not telling

go what the types of the inputs should

be and this plus operator when operating

on strings just concatenates so that

should work let's go ahead and run

that yeah this looks good to me I want

to just make one more point about

function signatures in go you'll notice

that the type comes

after the name of the variable so S1 is

a string S2 is a string and that's just

to make it a little easier to read the

authors of the go programming language

kind of built on uh a lot of the ideas

from C and in C it was the reverse it

was string S1 string S2 and that just

kind of reads a little clunky if you're

used to kind of speaking in plain

English makes more sense for the type to

kind of come after um what it describes

go provides another bit of interesting

syntactic sugar when it comes to

function signatures when multiple

arguments are of the same type in this

case X and Y the inputs to the add

function are both integers um the type

only needs to be declared on the last

one assuming that they're in order right

so in this case this is valid go code

and X and Y are both integers because

they follow one another we can put the

integer um just after the y if we were

going to add say a string as a third

parameter uh to this function then we

would just add a comma here after int

and put you know name String or or

whatever um this is just a bit of

syntactic sugar uh it makes our code a

little less verbose you don't need to do

this you can explicitly put the type on

every input and output but you will

often see code like this it's a

convenient shorthand so we've got these

two um example Snippets of code Funk

create user first name String last name

String age in and Funk create user first

name last name String agent so which of

the following is the most succinct way

to write a function signature Su synct

is just another word for kind of it's I

guess it's the opposite of verbose right

fewer fewer

words um it's going to be the one that

uses the syntactic sugar which is this

one because we're omitting the string

keyword after first name so we already

talked about this briefly the idea that

in go we specify the type of of a

variable after the variable name and

this is you know different from kind of

the C style way of doing things which if

you were to declare a variable Y and C

you would say int Y and really the

authors of the go programming language

just felt that that didn't flow

naturally from English it's not the way

we talk right we say x is an integer not

integer is X if you want to read up on

that decision and why they ended up uh

choosing that style then you can follow

this link here assuming you're following

Along on botev so the question is what

are we talking about when we discuss

this declaration syntax right this this

swapping of the name and the type um and

here are options the decision about

Campbell case versus snake case um the

style of language used to create new

variables types and functions guard

Clauses versus if else no the ever

important question of tabs versus spaces

no it's going to be the style of

language used to create new variables

types and functions related question is

Which languages declaration syntax reads

like English from right to left C or go

the answer is going to be go go supports

functions as data or basically the idea

that you can pass functions around your

program uh to be called in different

places callbacks right if you're

familiar with JavaScript then you're

probably familiar with the idea of a

callback it's a function that you could

pass to another function to be called

later this question deals with that idea

whenever we pass a call back in go the

type of the function Chang based on what

its inputs and outputs are so for

example here funk in in int is a

function that takes two integers as an

input and returns an integer and that's

going to be a different type than a

function that say took three integers as

input and returned an integer and if you

think about it it makes sense right if

I'm going to pass a function to another

function so that it can call it later it

kind of needs to know how many inputs

how many parameters it can pass into

that function if it's a function that

takes two inputs versus three inputs

then the caller is going to have to

write the code differently so we have to

treat every function signature as its

own unique type so this question is a

bit of a doozy I encourage you to pause

the video and try to work this one out

on your own um but basically it says

what is this hairy beast here right F

Funk Funk int int int int

int all right potential answers are a

function named F that takes as int takes

an INT as the argument and returns an

INT uh no it is not nearly that simple

right a function named F that takes a

function and an INT as arguments and

returns a function let's

see uh that right there is a full

function and an INT as arguments and

returns a function no this returns an

INT okay a function named f that takes a

function and an INT as arguments and

returns an INT that's what I believe it

will be function named F that takes a

function as the argument and returns an

INT yep that's not it so ju to be clear

f is a function it takes two

parameters a

function right a function of a specific

type a function that takes two ins and

returns an INT and as its second

parameter an INT and then F returns an

INT

hopefully that makes sense again feel

free to pause the video and and stare at

that for a second let's talk a little

bit about memory and how data that we

create in our program using variables is

stored in memory so over here I'll keep

track of the memory of our program and

over here I'll write some

code so let's say in our code we write X

colon equals 5 right so we're creating a

new variable called X and we are giving

it the value the integer value of five

and then we're placing the value

five in that memory right stored as

binary data within Ram now in our

program X the symbol is essentially just

a

pointer it points to this location in

memory so let's say on the next line of

code we update X and we say x equal 2 so

now we're reassigning the value of x to

two now let's try something different

what if we create a new variable called

Y and we initialize it to the current

value of x which in this case happens to

be two well in this

case we're actually going to allocate a

new section of memory to store the value

of y and we'll initialize it to the

current value of x which is two

and the symbol

y now has its own location in memory so

we basically created a copy of X now

this idea is really important to

understand because sometimes in

programming we'll have multiple

variables that actually point to the

same location in memory they can

overwrite each other and sometimes we

don't sometimes we have copies of data

right so now for example if I were to

update y let's say I made y equal 1 at

this point x would be unaffected X would

remain two but y now becomes one right

because we have a copy these two

variables X and Y reference different

locations in memory so why does all of

this matter well in go variables are

passed by value not by reference so

let's take a look at this code snippet

here top of main we deare a new variable

called X we set it equal to 5 and then

we pass X into a function called

increment the increment function just

adds one to X right making it six after

that we print X and the weird thing is

that when we print X here we still get

five and the reason for that is the

increment function was operating on a

copy of X when we pass X in here to

increment increment gets a new copy of X

still equal to 5 it increments that X to

6 and then because we are not returning

it it essentially just gets thrown away

and then back in main we still have this

same X that's still equal to five the

correct thing to do here would be to

have the increment function return X

after making its modification and up in

main we would write x equals increment X

so that we could capture the return

value from the increment function so

moving on to the assignment it says it's

critical in texo that we keep track of

how many SMS messages we have sent on

behalf of our clients fix the bug to

accurately track the number of SMS

messages sent okay let me just try

running this in its current

state and we're missing a

return okay I'm going to remove

this this uh type return there and see

what happens sent 430

messages and it looks like here we have

sends so far sends to add increment S is

doing nothing because s so far is still

printing as

430 okay I think I'm understanding so

let me put that back in the assignment

says alter increment sends so that it

Returns the result after incrementing

sends so

far alter the main function to capture

the return value from increment sends

and overwrite the previous sends so far

value Okay cool so this is pretty

similar to the code snippet here

basically we need to return an INT so

we're going to

return send so

far and then here we need to reassign

sense so far into the result of

increment sense cool

so again here we'll still be operating

on copies but because we're going to

return the copy and save it back into

the original variable we should be good

to go let me run

that yep you've sent 455 messages that

looks correct functions in go can have

multiple return values and when they do

have multiple return values the Syntax

for specifying that is just to wrap the

return values in parentheses as well so

when there's just a single return value

we do not wrap that return value in

parenthesis but when there are multiples

we do wrap them in parenthesis one thing

I really like about go is that it does

not allow you to have unused variables

and because it doesn't allow you to have

unused variables and because it allows

you to have multiple return values from

a function we kind of need a way to

ignore some of the return values because

there are definitely instances where a

function returns two things but maybe we

only care about one of those things for

example a point on a graph can be

described by its XY coordinates but

maybe all we care about is the x

coordinate so here we can call the get

Point function and ignore the Y value by

using an underscore and it's important

to understand that the underscore is not

just like a conventional name that we're

going to ignore it's actually ignored

the

compiler completely removes it from our

code so moving on to the assignment here

in texo we have obviously first names

and last names for all of the users that

we're able to send messages to well when

we welcome someone to texo we don't need

their last name so let me go ahead and

try to run this code and you'll see

we'll actually get a compiler error that

says last name declared and not used

used like I said go does not allow us to

have unused variables which I think is

kind of an awesome uh little bit of the

tooling it helps keep our code very

clean and concise easy to understand um

so we need to explicitly ignore that

last name with an underscore if we're

not going to use it let me try running

that again and that looks good to me in

go we can name our return values and if

we do it actually Alters the behavior of

the function

just a little bit let's take a look at

this function get chords or get

coordinates it returns two integers and

we've named the integers X and Y and by

naming them we've actually initialized

at the top of the function the the

variables X and Y and they're

initialized with their zero values so in

the case of an integer literally just

the number zero for both of them the

other interesting thing about naming our

return values is that if we use a naked

return statement a return statement that

doesn't explicitly say for example

return 0 comma 5 then the values of X

and Y are automatically returned from

the function

so this version of get coordinates is

actually the exact same as this kind of

more verbose version of get coordinates

right here we have not given the return

values the names X and Y and instead

we've initialized X and Y to their zero

values and then returned them explicitly

now a couple of recommendations I would

recommend using named returns when you

want to document kind of what the

intended purpose of each return value is

so for example if you have a function

that just returns three integers that

function signature could be pretty

confusing but if you have a function

signature that says it returns three

integers and they're named width height

and length that's a lot more interesting

to the caller of the function they

understand the purpose of each

individual return value much better so I

like to think of named return values as

basically a built-in way of documenting

what the purpose of all of your return

values are and you should generally just

use them on the other hand this implicit

or automatic return that you get along

with um named return values I would

typically advise against you'd only want

to use this in like very short very

simple functions um because it harms

readability right and I'm pulling this

directly from the tour of go they also

agree with me um implicit returns or

naked return statements um generally a

little bit harder to understand so the

way I would write this function

personally would be get chords XY in and

then I would explicitly return X and Y

so let's jump down into the assignment

it says one of our clients likes us to

send text messages reminding users of

Life events coming up fix the bug by

using named return values in the

function signature so the code will

compile and run as intended Okay cool so

this is the function we are interested

in fixing years until events looks like

it takes a user's age as input and then

returns or should return kind of the

number of years until they're an adult

which is 18 the number of years until

they can drink at least in the US which

is 21 and the number of years until they

can rent a car which apparently is 25 um

and it looks like we never want a

negative number so if if any of these

are less than zero we just set them

equal to zero that makes sense once

you're over 18 your years until you're

an adult are just zero right you're

already an adult okay let me try running

this see what we get okay undefined

years until adult all right this makes

sense right because there's no colon

here so we're not defining a new

variable and the assignment said to use

named return values so let's go ahead

and do that so here's until adult years

until drinking I'm going to format this

a little

better and we'll do years until car

rental so again this will declare all of

these values with their zero value at

the top and then this naked return

statement should return them in

order and just to make sure adult

drinking car

rental adult drinking car rental okay

we're in the right order let me run that

first test so four years old they'll be

an adult in 18 years can drink in 17 can

the current 21 that all looks good 10

it's going down

22 Yep this looks good to me so as I

mentioned before explicit returns are

probably better than implicit returns in

most scenarios um it just makes a lot

more sense right so here in this

function get chords XY in so we're using

named return

but we're still explicitly returning X

and Y this is how I would recommend

writing most of your go code

um this this function here is doing the

same thing um it's explicitly returning

hardcoded values though instead of the

variables X and Y and it's just

important to understand that this

effectively overrides the implicit

return of X and Y so in this case five

and six will be returned again that's

why I recommend doing it explicitly

because when you see a return statement

that has explicit values being returned

those are the ones that are returned you

don't have to do any guess work you

don't have to scroll back to the top of

the function to see which values are

being returned so now we're going to

break that advice just for practice's

sake um the assignment says fix the

function to return the named values

implicitly okay so here we have a

problem in our code where we are

basically explicitly returning zeros

which as we talked about overrides the

implicit return so my guess is if we

look at all of these

yep every test is returning zeros if we

just remove that implicit return and run

that then it should work as intended yep

and then just to show you what I mean

like what I would recommend doing is

this it's

bigger like that that's how I'm going to

recommend doing it and in fact because

Boot Dev just checks the output this

should work just fine with our test so

I'm going to submit it like

this moving on to some questions about

named returns so it says when should

naked returns be used and the answers

are for large functions for small

functions or for complex functions and I

would argue if you're going to use naked

returns at all which honestly I'd kind

of just recommend against then you

should only use them for small functions

the more complex and large your

functions get the more important it is

to be explicit and readable and document

your returns with named returns and

things like that the next question is

when should named returns be used so

when there are many values being

returned when the function is simple or

when there are few parameters being

returned I would argue it's never really

a problem to name your return values but

it's really important when there are

many values being returned especially if

there are many values of the same type

being returned because then you can you

know essentially tell the collar of your

function through your function signature

what they should expect each value to

represent let's talk about one of my

favorite programming patterns or

programming Styles um that is early

returns or um what they're also

sometimes called as guard Clauses so an

early return or a guard Clause is

exactly what it sounds like it's just

when we return early from a function so

this function divide if it's past a

divisor of zero then it returns early

with an error other wise it goes ahead

and does kind of the division and

returns uh the results and a nil error

now we're going to talk about errors

soon you don't have to worry too much

about how they work for now um just

understand that a nil error effectively

means no error so when we're looking at

this divide function we can understand

that if the divisor is zero we're going

to return early and and basically say we

can't do this division because we can't

divide by zero um otherwise we'll take

the happy path towards the end of the

function best practices when it comes to

software engineering and how we write

code change all the time right there's

millions of developers all around the

world writing code and we all have

different opinions and kind of the the

common opinion about a certain style

tends to change over time um the

interesting thing is I think that these

days um guard Clauses and early returns

are kind of looked at as a good thing um

this is clean code right this is a good

way to write code certainly most go

programmers think this way way um but it

wasn't always that way um there used to

kind of be a heuristic that uh

developers used which was you shouldn't

ever return from a function in more than

one place so back when that was kind of

the more popular way of doing things

you'd get kind of nasty if else nested

statements like this um if you look at

this function get insurance amount

basically takes a status as input it

returns an integer and it only has one

return statement so it only returns from

one place but I would argue that doesn't

necessarily make this function all that

much easier to understand right we're

initializing a variable up at the top

amount and then just in this big nasty

nested if else chain we're kind of

reassigning the value of amount uh based

on some conditional logic now compare

that with guard Clauses right so with

guard Clauses instead of overwriting the

variable amount and then returning it at

the end of the function we're just

returning early with the proper amount

at each step of the way now both of

these functions do the exact same thing

they have the same behavior um but I

would argue that the one with the guard

Clauses is much easier to understand so

the question for this exercise is which

is true guard Clauses are unreadable

guard Clauses are generally worse than

nested IFL statements or guard Clauses

provide a linear approach to logic trees

okay so it's definitely not um these two

right so I'm I'm going to go with

provide a linear approach to logic trees

and really all that means is rather than

having to follow kind of a tree

structure to look at conditional logic

we can just follow a straight line right

is it this no we move on is it this no

we can move on right it it allows us to

break up kind of the cognitive load when

we're when we're reading code so

definitely a linear approach there the

next question is what is a guard Clause

so a bit wise or operation an and

operation in Boolean logic or an early

return from a function when a given

condition is met and it is an early

return let's talk about structs so

structs are the first collection type

that we're going to talk about in this

course a collection type is just a type

that contains other types in the case of

a struct a struct is just a collection

of key value pairs if you're familiar

with python dictionaries or JavaScript

object literals this is basically the

same idea so for example we can define a

car struct and we can say a car has a

make a model a height and a width and

each of those feels has its own

Associated type so let's move on to the

assignment I think looking at the code

is going to be the easiest way to

understand structs okay complete the

message to send struct definition it

needs two Fields phone number an integer

and message a string and um on these

exercise I always recommend kind of

going and looking at the test weite this

is all the code the way boot Dev works

like all the code is here um and we're

really just testing standard output to

see if you got the right answer so you

can see literally everything that's

going on

um so here you can see where a message

to send is going to be instantiated with

phone numbers and messages and here you

can see where um it's the uh fields are

going to be accessed with the dot

operator so let me go ahead and run it

in its current state um we should get

yep a compile time error where it's

saying message is undefined phone number

is undefined right so we need to add

those to the

definition all right phone

number

integer message

string let's go ahead and run

that and sending message love to have

you aboard to that big number okay that

looks good to me struct keys can hold

any type uh not just primitive types

like integers strings and booleans um

here you can see we've actually nested

the wheel struct within the car struct

right so we have the car struct from the

last example and we've added a front

wheel and a back wheel and they are each

of type wheel right and a wheel has a

radius and a material so we can actually

Nest structs within other structs and

then we also saw this just a little bit

in the last assignment but this is how

we can instantiate a new instance of a

struct right so this is the struct

definition we're saying this is what a

car looks like and then here we've

created a new empty car called my car

and when you create it kind of with

those empty uh those empty brackets all

of the fields inside of the struct will

just be initialized to their default

values their zero values right so

strings will be empty strings ins will

be zero and then here we're using the

dot operator to access Fields right so

my car. front wheeel right so we're

accessing the front wheel key and then

radius to access access the radius

within the front wheel and we're setting

it equal to five again with this syntax

stuff it's just best to get Hands-On

keyboard and jump right into it so let's

get to the assignment says textio has a

bug we've been sending texts with

information missing before we send text

messages in texo we should check to make

sure the required Fields have nonzero

values notice that both the user struct

so that's this here is a nested struct

or notice that the user struct is a

nested struct within message to send

okay so message to send has a message

which is a string and then a sender and

a recipient and both of those are of

type user okay that makes sense a user

is the sender a user is the recipient

and then there is a message cool

complete the send the can send message

function

okay it should only return true if the

sender and recipient Fields each contain

a name and a number if any of the

default zero values are present return

false instead Okay cool so can send

message this is essentially a function

that's going to validate a message to

send to see if it actually has data

inside of it so so um if I run the code

right now it's always returning true

right so you have an appointment

tomorrow you have an event

tomorrow from Susie Saul ah see there's

a phone number missing there that's a

problem looks like there's a phone

number missing there that's a problem

okay let's see so sender and recipients

contain a name and a number so if M to

send

dot sender and recipi sender contain

name dot name

is

empty

false

right and then if m dot is going to be

recipient is empty also return FSE so

we're just going to do some guard

Clauses

here and then sender and recipient and

now we're interested in the number

number is an integer so if it's

zero cool so we're just we're just

basically doing a a very simple

validation to make sure um that names

aren't blank and numbers are not blank

so let me run

that okay so this one has all the

information there and it's sent now this

one has a number missing can't send

message that looks

correct okay this is looking good to

me all right next up we have Anonymous

strs so Anonymous strs are just struct

instances that don't have a name so

whenever you create a new Anonymous

struct in go you're you're immediately

instantiating a struct of a given type

right the type of the struct doesn't

have a name so for example here we have

a

struct with a make and a model now in

the exercise previous we remember we

actually had this same exact struct but

we'd given it name the name was car

right here we haven't created a new

struct definition we haven't created a

new struct definition called car instead

we're immediately instantiating a new

instance of a struct called my car this

could be named anything right and it

just has a make and a model field on it

so the only reason you would use an

anonymous struct is if you have no

reason to create more than one instance

of the struct so to be clear what's

happening here we're creating a new

variable called my car and it has two

Fields it's a struct with two Fields

make and model and we're immediately

giving it a value of make Tesla Model 3

and this type this specific struct type

doesn't exist anywhere else within our

program this is kind of a type that's

just unique to this one instance um

called my car it's not very common that

you'll see kind of top level um

Anonymous structs like this more often

you'll see nested Anonymous structs

right so rather than creating wheel as a

separate struct type we've just said

well Wheels kind of always exist within

cars I know that's not really true but

maybe within our program it's true um so

we just create a little Anonymous struct

um within the greater car struct now as

far as best practices in writing clean

code my opinion is that you should

generally favor um named structs you

avoid Anonymous structs unless you have

a really good reason to use them uh

you'll really never go wrong with naming

your structs okay so the question on

this assignment is what is a good reason

to use an anonymous struct you're

worried about security you need your

code to be faster you're worried about

user privacy or it is only being used

once well the only thing even remotely

related to how Anonymous trucks work um

is that it's only being used once so if

you're certain that you only want this

type to be used one time maybe you don't

want someone accidentally reusing a type

um then you might want to use an

anonymous

struct next question is what's one

advantage of using an anonymous struct

anonymous trucks make your code run

faster Anonymous strs prevent you from

reusing a struct definition you never

intended to reuse or Anonymous TRS can

be compiled more quickly um it's this

reuse one um one place that I have used

Anonymous kind of top level structs from

time to time is in HTTP handlers so if I

know that a given HTTP endpoint will

always return a a specific Json payload

then I'll use an anonymous struct to

define the shape of that Json payload we

haven't really talked about Json in go

yet but kind of spoiler alert structs

are how we structure Json data

typically next we have embedded structs

and embedded structs are not the same

thing as nested structs an embedded

struct is basically where would take all

the fields from one struct and kind of

shove them into another one uh let me

show you what I mean so here's our car

struct that we've been using for our

examples um it's got to make in a model

great here's our truck struct now you'll

notice we've embedded the car type here

but the car is missing kind of a name a

key in the truck struct bed size is the

key int is the type here we just have

the type which is car so what does this

do and how does it differ from a nested

struct well in the embedded struct if we

want to access the field model from a an

instance of a truck rather than doing

truck. car. model we would just do

truck. model because these fields of the

car type are becoming kind of top level

fields of the truck type we're

inheriting all of those fields from the

car type now I have to be careful with

the word inherit even though it is kind

of a pretty good descriptive term for

what's happening go is not an

objectoriented language because it

doesn't support classes or inheritance

in the class-based sense so if you're

familiar with the idea of

object-oriented programming just know

that classes and inheritance aren't

really what's going on here uh this is

you can almost just think of this as a

shorthand for kind of retyping this make

and model into the truck struct it's

it's almost just a syntactic sugar um so

that we don't have to retype all of

these Fields so let's take a look at

some code um and how we would use this

truck struct so I've created this new um

instance of a truck called it Lane's

truck has a bed size which is an integer

right and it has a car here now you

might look at that and say that looks an

awful lot like a nested struct and the

Syntax for creating a new instance of an

embedded struct is very similar to uh

the Syntax for a nested struct

essentially the key

is just the same name as the type this

just kind of a quirky thing about um

composite literals uh the embedded stuff

looks like the nested stuff however when

we are accessing the individual fields

on um Lanes truck using the dot operator

you'll see they're all accessed at the

top level it's not Lan truck uh doar

doake it's Lan truck. make right it's

not lanest truck. car. model it's just

LAN truck. model so those fields are

being brought up into the top level it's

just when we kind of instantiate the

truck the first time that we need to do

this sort of nested syntax so let's hop

into the assignment it says at texo a

user which is a struct represents an

account holder and a sender is just a

user with some additional sender

specific data a sender is a user that

has a rate limit field that tells us how

many messages they are allowed to send

fix the system by using an embedded

struct as expected by the Tex test code

okay so let's go ahead and take a look

at the test

code so it looks like the test code is

creating some

senders and it's expecting that a sender

has a rate limit and that it has a user

right and this is looking like an

embedded

struct and up here you can see s is a

sender and we're directly accessing name

number and rate limit all the top

level so I think all I need to do here

is embed the user structure in fact

let's run this without without that see

what happens yep we're getting some

undefined

Fields we'll embed the user type in

there and that's looking pretty good to

me I will mention just to give you an

idea of like when you use this in the

real world one place that I use it

actively on boot Dev is users have kind

of public fields on boot Dev and private

Fields so public fields are um stuff

that we show on the leaderboard things

that kind of anyone can see about your

profile maybe your bio or your profile

picture um but users also have private

Fields things like um your hashed

password right the password we store in

the database and I've actually

embedded the private Fields within the

public user so that I can easily nullify

them when I don't want to send private

data uh to a given web page all right

let's go ahead and run this code

let's talk about methods on structs or

just methods in general in go um I know

I told you go is not object oriented and

it's not but if you squint really hard

structs in go kind of look like classes

in a language like Java JavaScript or

python so methods in go are just

Behavior or functions that we can Define

on a type and more often than not we end

up defining methods on structs although

we could Define methods on any type so

let's take a look at the Syntax for this

so here we have a simple rectangle

struct it has a width and a height right

and here we've defined an area method on

the rectangle struct so this is just a

function right we're familiar with

functions already the only difference is

that we've added this special parameter

before the name of the function which is

again just a parameter that comes into

the function just it's just a special

parameter um and in this case it is of

type rect which is just a struct and

we've named it R and then this function

just returns r. width * r. height right

so it Returns the area of the rectangle

so why would we use a method on a struct

well there are reasons that we'll get to

later when we talk about interfaces um

but for now it's mostly a syntactic

thing a syntactic sugar thing if we have

behavior that we want to Define on a

given type then strs can be a really

good choice they give us this nice

tactic sugar right we create this new

rectangle called R and now we can just

call r. area to get the area of the

rectangle it's kind of a nice way to do

computed properties on a type right so

we could have stored area as a separate

number within the wct struct the problem

with that is now we lose kind of a

single source of Truth when it comes to

the area right if we store the area as

say 50 and the width and height as 5 and

10 but then we update the height and

forget to update the area right now we

have a bug in our code so this is a

great way to kind of have a oneline

accessor to get the area of a rectangle

but we don't have to actually store that

area in our struct as kind of duplicate

data so let's get down to the assignment

says let's clean up texo authentication

logic we store our users authentication

data inside an authentication info

struct okay so that's here it's got a

username and a password we need a method

that can take that data and return a

basic authorization string the format of

the string should be authorization basic

username colon password right so this is

the kind of standard basic authorization

that's used in HTTP requests the

assignment says create a method on

authentication info called get basic off

that Returns the formatted string Okay

cool so let's create a

new a new method and we can kind of

reference this syntax over here so it's

funk and we want the receiver to be an

authentication info struct so I'll just

call it AI oh that's that's actually

confusing let's do off aui

authentication

info and we wanted the name of the

method to be called get basic

off and it returns a

string okay and then we want to return

this format

here so if you remember we can use the

format package to do that so we'll

return fmts

printf remember s printf Returns the

string rather than printing it to

standard out or to the console and we'll

use that

template username and password are both

just strings so we'll use percent s for

our formatting verbs and then we can do

off I dot username first

and ai.

password next okay cool that looks

correct to me let's run

it perfect let's talk about interfaces

so an interface in go is just a

collection of method signatures for

example take a look at this shape

interface so we have an interface it's

named shape and it specifies two

different method signatures so area is a

method that takes no parameters and

returns a float 64 perimeter is another

method that takes no parameters and

returns a float 64 now any type that

implements both of these methods and and

matches their method signatures will

implement the shape interface which

really just means that we can think of

it and treat it as a shape so for

example let's take a look at this

rectangle struct so erect has a width

and a height uh both of which are float

64s and again this is just a this is

just a kind of standard struct and it

has two methods on it uh one is the area

method that takes no parameters returns

a float 64 um one is the perimeter that

takes no parameters and returns a float

64 and because a rectangle implements

both of these methods we can think of a

rectangle as a shape a shape is just

anything where we can kind of calculate

its area and calculate its perimeter and

multiple types can implement the same

interface

so for example this circle struct it has

different underlying data right rather

than a width and a height we can

represent a circle with just a radius um

but to calculate its area and its

perimeter the calculation is a little

bit different right we're using pi for

example um but the method signature is

identical right we don't pass anything

in because we have all the data we need

on the circle struct and we just return

a float 64 so both circles and

rectangles because they implement the

required methods can be thought of as

shapes or we could say they implement

the shape interface let's get into the

assignment I think it'll all start to

make a little more sense so the

assignment says the birthday message and

sending report strs have already

implemented the get message method so

let's take a look at that so uh birthday

message is this struct here sending

report is this struct here they both

have this get message method that

returns a string and they're just it

looks like the strings that they return

are just a little bit different right

the birthday messages get message uh

function returns this like hi blank it

is your birthday on blank and a sending

report says your blank report is ready

right so they just they just format a

little little

differently okay so assignment says

first add the get message method as a

requirement on the method interface okay

so we need to finish the message

interface and add a get message

method that returns a string

Okay cool so now this message interface

because birthday message and sending

report both implement this method we can

think of both of those as messages next

it says complete the send message

function it should print a messages

message which it obtains through the

interface meth method Okay cool so the a

message is an interface so inside of the

send message function we don't actually

know if we're dealing with say a

birthday message or a sending report we

just know that we have access to a

message so really the only thing we can

do with it is call get message which we

know will return a string and it says it

should print a message so we'll do ft.

print line just print out the message

cool okay now this is powerful right

let's go take a look at how this code is

actually called so we have this test

function that also just takes a method a

message and it

sends that message right it's just

calling our send message function

here but down here and this is where

it's most interesting the test function

is not past like interface literals

that's not even like a real thing right

an interface is like abstract type that

represents other types instead because

the test function takes an interface we

can pass into it any struct that

implements that interface so for example

here on line 42 we're passing in a

sending report and then on line 46 we're

passing in a birthday message those are

two different types in a strongly typed

language being passed in as the first

parameter to a single function but the

reason it works is because we're using

interfaces okay let's go ahead and run

this see what

happens your first report report is

ready you've sent 10 messages hi Dondo

it is your

birthday this looks great this looks

great to me

in go interfaces are implemented

implicitly and what that means is when

we have a type like in our last example

we had the rectangle type that

implemented the shape interface we never

had to explicitly write anywhere on the

rectangle struct that it was intended to

implement the shape interface because it

satisfied all the requirements of the

shape interface it just kind of

automatically implemented it and that's

fairly unique to go in a language like

Java we might have to write something

like this um we could take a look at

this little example here we've got this

employee interface and a contractor

struct if we wanted the contractor to

implement the employee we would need it

to still fulfill the interface right by

implementing all the methods but we

might need to also explicitly type

something like

implements

employee right we explicitly say that we

intend to implement that interface in go

it's done automatically let's hop into

the ass assignment it says at texo we

have full-time employees and contract

employees we've been tasked with making

a more General employee interface so

that dealing with different employee

types is a little simpler add the

missing get salary method to the

contractor type so that it fulfills the

employee interface Okay cool so we have

the employee interface we have the

contractor

struct um and if we look at the

full-time struct it looks like it

already

implements the employee interface so we

just need to add the Missing Method

because right now a contractor has a get

name but does not have a get salary Okay

cool so let's go ahead and do that we'll

do

employee get salary it returns an

INT and a contractor's salary is their

hourly pay multiplied by how many hours

they work per year okay so be something

like

c. hourly pay multiplied by c. hours

per

year okay and just because I'm curious I

want to go look at how a full-time

salary uh employee works yeah so you can

see the the way that a full-time

employee their salary is calculated is

is totally different like their their

salary is actually just stored probably

because the way we think of full-time

employees is like you know you make

$60,000 a year you make $70,000 a year

whereas contractors often get paid by

the hour so it make sense that they have

a different calculation um and then down

here in the test Suite um this looks

very similar to the last assignment

where the test function is able to take

as inputs any type of employee right so

we can pass in both full-time and

contractors here uh let's go ahead and

run

that Jack Bob and Jill we can see all of

their salaries even

though Jack is full-time and Bob and

Jill are both contractors so that looks

good to me in go types Implement

interfaces implicitly because it kind of

decouples the definition of the

interface from the definition of the

type the type doesn't even really need

to know that it implements a certain

interface and that's really really cool

because it means it's easy for a type to

inter to implement lots of different

interfaces so the quiz question here is

how is an interface fulfilled answers

are type has all the required interfaces

methods defined on it or a struct embeds

the interface in its definition and the

answer is going to be it has all the

methods defined the next question is can

a Type fulfill multiple interfaces or

Implement multiple interfaces and yes

why not another quiz question go uses

the blank keyword to show that a type

implements an interface and the answers

are fulfills implements inherits and

there is no keyword in go and the answer

is that there there is no keyword in go

interfaces are implemented

implicitly in the next question it says

in the example given the blank type

implements the blank interface let's

take a look so example here we've got

the shape interface circle

struct circle has an area method so it

looks like the circle type implements

the shape interface like we talked about

before or a type can Implement multiple

interfaces it just needs to have all the

methods for all of the different

interfaces for example the empty

interface so that's this this definition

right here this is an interface with no

methods required is actually always

implemented by every single type in the

go programming language now it's often

not a very useful interface because you

can't really do anything with an empty

interface you have no methods to call

let's jump down into the assignment it

says add the required methods the email

typee implements both the expense and

printer interfaces Okay cool so we got

these expense and printer interfaces two

different methods we need to implement

and we have this email type with an is

subscribed Boolean and body string cool

all right cost

method if the email is not subscribed so

if not e do is subscribed I believe is

what the field was then the cost is

0.05 times

uh the length for each character in the

body so the length e do body now

remember go is strongly typed and we

can't multiply an INT by a float

directly so we need to cast this integer

sorry I think I highlighted those

backwards the length of the body is an

integer this is a float so we need to

cast the length of the body to a float

so we can we can multiply a float by a

float um otherwise we'll

turn uh it's

0.01 times that same thing the length of

the body cool uh the print function

should just print to standard out the

emails body text easy enough fm.

printline e.

body okay so now our email struct

implements both of these interfaces and

if we come down here to look at the test

function this is interesting the test

function takes an expense and a

printer right so we can use both of

those uh methods

there and actually the email struct so

we're creating instances of emails here

we're actually passing it into test as

both the expense and the printer right

because it makes sense it implements

both cool let me run

that oh what did I screw up 05 time FL 6

4 length value of type float 64 is not

used let's

see 0.05 time float 64 length of e body

what did I screw up value of type float

64 is not

used I forgot my return cool let's try

that

again okay

so printing with cost 11 cents hello

there printing with cost $1 I want my

money back yeah that looks that looks

pretty good let's submit

it up until this point we haven't really

been naming the arguments of our

interfaces method signatures um but we

totally could so if we take a look at

this this is The copier interface it's a

uh copy method that it requires which

takes two strings and returns an INT um

the interesting thing is when you look

at this method signature it's kind of

hard to tell what the intention behind

the interface is it's like great it

takes two strings but what are those

strings supposed to represent right so

here we can take a look at what I would

consider a better interface definition

where The copier interface actually has

a copy method that specifies the source

file is kind of the name of the first

parameter and the destination file is

the name of the second parameter and

then byes copied is the integer that's

returned so you know the functionality

here is identical but now we have much

better I I mean I would consider it

documentation of what the intention

behind this interface is so the question

is are you required to name the

arguments of an interface in order for

your code to compile properly uh no no

it'll work fine either way next question

is why would you name your interfaces

methods parameters right like we don't

need to why would we do it um execution

speed memory savings or readability and

Clarity uh it's going to be for

readability and Clarity type assertions

so type assertions are something you'll

see every once in a while I would argue

they're probably not super common but

you will come across them um and the

whole purpose of a type assertion is so

that you can take an interface and kind

of cast it back into its underlying type

so in this code sample here we can kind

of assume that s is an instance of a

shape interface and at this point in the

code because it's just an interface we

don't know NE neily if it's a circle or

maybe a square or maybe some other type

so what we do is we do a type assertion

to cast it to the circle struct and

basically what happens here is on the

left hand side of the um this uh short

declaration operator here we get back

the instance of the circle so this is

going to be an instance of the circle

struct again the underlying struct um

behind the shape interface if it was a

circle right because we we can't be sure

if we had a shape we're not sure if it

was a circle or maybe something else but

this okay variable this is going to be a

Boolean and if it's true then it was a

circle and we should have a valid kind

of filled out Circle struct if okay is

false then we kind of have to discard

the circle um because we we weren't able

to parse out um the shape as a circle

because it wasn't a circle so let's move

on to the assign it's an email then it

should return the email's two address

and the cost of the email if the expense

is an SMS then it should return the

sms's phone number and cost if the

expense is any other underlying type

just return an empty string and a 0.0

for the cost Okay cool so we've got this

get expense report that takes an expense

as input and my guess is yep expense is

this interface so our job is to kind of

try to cast it into the potential

underlying types email and SMS

so first we do um email

okay uh expense Dot and we'll cast it to

an email type if

okay so if it's an email return the

emails to address so uh return email. to

address as that string there and also so

it's cost so email dot looks like cost

is a method email. cost

okay uh next we can do s

okay uh e do cast to an SMS so if it's

an SMS we can

return sms's to phone number to phone

number and the SMS Dot cost I believe

that's also just yep just a

method okay and it says otherwise if it

has a different underlying type return

empty

string and 0.0 for the cost okay cool

that

feels at least like we followed the

instructions let's see what we

get not enough arguments in call to sms.

cost let's take a look at sms. cost

cost

H have

want what did I screw up

here ah should be s. cost I I named I

named this truck the struct S all right

let's try that

again report the email going to John do

will cost 11 email the sms okay cool and

invalid expense perfect that I mean that

feels right I can come down here and

check the test Suite yeah invalid okay

cool let's submit that when we want to

do a lot of successive type assertions

in a row there's actually a better way

and that's with type switches so here's

a Syntax for a type switch uh basically

we have an interface and we cast it um

at the very top of the switch and then

we can actually check and kind of

pattern match against different possible

types if none of the types that we've

specified are the matching underlying

type then it will kind of fall down to

the default case so let's write some

code and see how it works um down in the

assignment it says after submitting our

last snippet of code for review a more

experienced gopher or term for a go

developer uh told us to use a type

switch instead of successive assertions

let's make that Improvement implement

the get expense report function using a

type switch Okay cool so kind of the

same thing though if it's an email

return a to address and a cost if it's

an SMS then we should return a phone

number and a cost blah blah blah right

the difference is we're going to use a

different syntax this time okay so we're

going to be using this switch syntax so

switch value colon equals e.type

okay Open brackets case um we are

interested in if the expense is an

email so case email now the the

interesting thing is with now within

this case block V is an email so I can

treat it like an email so I can do

return V

Dot oh what was it two address I think

yeah two

address b.

cost a

SMS return B do two phone number I think

it was two phone number b.

cost and

default

return uh I think it was empty string

just zero values right empty string and

0.0 okay cool let's see what

happens with that oh am I forgetting

nope I've

got oh I'm indenting a little

weird there we go let's run

that cool the MS SMS is going to be is

going to this number with this

cost got some emails and costs okay

that's looking good to me now that we've

learned what interfaces are and how we

use them let's talk about how we can use

them more effective and in a sort of

idiomatic and clean way if you forget

all of the other advice that we're going

to go over when it comes to writing

clean interfaces don't forget this one

and that is to keep interfaces as small

as you can the best the cleanest and the

most useful interfaces typically just

have one or two methods defined on them

imagine a simple Stringer interface it

has one method defined on it called

string that simply returns a string you

can take that interface and implement it

on basically any type and now you have a

super useful interface for logging out

string representations of different

types there isn't a hard and fast rule

about exactly how many methods you

should be defining on your interfaces

but what you really should be doing is

looking for kind of the minimal Behavior

necessary to accurately represent an

idea or concept right so for example

here's a slightly larger interface from

the standard Library again normally

we'll see interfaces in the standard

library with maybe just one or two or

three uh methods this one has five but

this is kind of still the minimum um

amount or or the the the minimal

necessary behavior that we need to

describe a file like a file in your file

system right we need a way to close the

file we need a way to read it we need a

way to seek to individual uh kind of

sections of the file um so this is an

example of a slightly larger interface

right I would say five methods is

definitely a on the larger end um but

it's still a good interface because it's

using as as little Behavior as it

possibly can to describe an operating

system file so the question that goes

along with this is interfaces should

have as blank methods as possible and

the answers are complex few and many and

the answer is going to be few the next

mistake that I've seen new go developers

make is when they write an interface

that sort of knows about the types that

they've intended to satisfy it so for

example if you have a car interface and

you've defined an is fire truck method

on the car interface that returns a buou

you know whether or not it's a fire

truck that's probably a mistake you

would actually just want to use a type

assertion or a type switch if you really

needed to figure out the underlying type

you should not make your interfaces

aware of the underlying types this also

breaks rule number one right because

rule number one we don't need to know if

a car is a firetr for like the minimal

behavior of a car I mean you can see how

this sort of design pattern would get

out of hand very quickly because we

might need to also Define other booleans

like is pickup is sedan is tank right if

you start catering to all of the

underlying types of a given interface

your interface is going to be really

bloated and become very very large so

the question here is actually the

reverse it says it's okay for types to

be aware of the interfaces that they

satisfy if it were flipped around the

answer would definitely be false but

because we're talking about the types

being aware of the interfaces they

satisfy I don't think that's necessarily

a problem um they don't need to be aware

of them right because again in go uh

interfaces are satisfied implicitly but

I would argue to some extent they are

aware of them because the developer had

to go in some cases out of their way to

satisfy the implementation of an

interface so I'm going to go with true

on this one so now this is the reverse

question it says it's okay for

interfaces to be aware of the types that

satisfy them no they should not be aware

finally I just want to talk about how

interfaces are not classes sometimes

this can get mixed up especially if

you're coming from an object-oriented

background um inter Es are just a very

different idea interfaces are not

classes they are much Slimmer right

classes have a lot of functionality

going on inheritance is a fairly complex

topic um interfaces are honestly just a

simpler idea um interfaces don't have

Constructors or deconstructors that

require that data is created or

destroyed right so that's another way

that they differ from classes that have

kind of this in inherent setup and tear

down uh situation interfaces are not

hierarchical right there's there's no uh

hierarchical inheritance tree when it

comes to interfaces and the most

interesting one is that interfaces

Define functions signatures but not

underlying Behavior right so this is

actually a big difference between

interfaces in classes in a class A Child

class can inherit behavior from a parent

class which can kind of dry up your code

right don't repeat yourself in go that's

not the case at all an interface doesn't

dry up your code you still have to go

Implement all of the methods on all of

the different types individually

interfaces just allow us to use all of

those types kind of in the same places

later in this course we'll get to talk

about generics which is a way to kind of

dry up your code and funny enough kind

of uses interfaces um under the hood or

kind of as a part of the generic system

to make that happen so finally the

question is interfaces allow you to

define a method's Behavior once and use

it for many different types uh that's

false go has a very unique way of

handling errors really quickly let's

review how JavaScript handles errors and

the way JavaScript handles errors is

very similar to python or Java it uses a

TR catch Paradigm um and let's contrast

that with how go handles errors in its

sort of unique way let's pretend that we

have a function called get user um and

we'll start with JavaScript so we have a

function called get user

whoa and it Returns the user so we'll do

const user equals get user and we have

to wrap the get user function the call

to the get user function and a tri block

because we know that the get user

function can throw because let's just

say for example uh maybe the user

doesn't exist Okay cool so if something

goes wrong we add a catch block and if

this function throws execution will stop

we'll enter the catch block and do

whatever is in here for now we can just

uh console.

log the error now let's take a look at

what this function looks like in go we

do something like this we do user air

colon equals get

user if Air does not equal

nil then we could print out the error

and return so that we don't continue and

then down here we could you know deal

with the user object so uh use user here

and for consistency sake we could say

use user here um after the user object

is created in JavaScript okay so what's

the difference well let's talk about the

first reason why I prefer goes error

handling to javascript's error handling

let's pretend we need to go get some

data for the user after we've already

kind of retrieved the user successfully

so let's say we need to go get the

user's profile picture well in go all we

would do

is call the next dangerous function

let's say get user Pro profile and maybe

it takes a user. ID as input right so we

need to successfully wait for the user

to come back and then we can go fetch

its

profile right so this looks very similar

we doing another dangerous function get

user profile and it returns a profile

and an error if an error with the

profile occurs uh again we'll just kind

of print out the error and return

otherwise now we have a profile object

okay what would we do in JavaScript well

in JavaScript we can't just take this

Tri catch and paste it down here and

update some stuff this will not work if

we do get user profile

user.

ID

profile the problem with this code is

that user is only available within this

Tri Block it's scoped to the tri block

right so this user object here will be

undefined so the normal thing to do in

JavaScript would just be to take this

line here and inject it

within the tri block the original Tri

block right so now I'm doing my second

dangerous function after I do my first

dangerous function the reason I don't

like this is that the logic for handling

the errors is now all in one place if I

want want to handle the error for the

get user profile function differently or

separately um then I want to handle the

error from the get user function I have

to actually Nest the whole Tri

catch like

this right so now user. ID is accessible

because I'm in the same Tri block but I

get a second catch block so we kind of

get this nasty nesting if we want to

treat each individual error separately

and this kind of brings us to the second

reason why I prefer Go's error handling

and it's that it forces us to think

about each individual error that's

passed back from a dangerous function so

again in JavaScript kind of the normal

thing to do unless you really needed

separate error handling would be to just

kind of do all of your dangerous stuff

in one large Tri block the problem with

this in my opinion is that it kind of it

doesn't encourage me to remember which

of these functions is dangerous in the

first place for example maybe this is a

safe function and this is a dangerous

function that can potentially throw an

error but looking at this code from um

kind of a calling perspective I don't

really know that that's the case whereas

in go because a function returns kind of

the valid data and the error with every

function call I know for a fact that the

get user profile function can throw an

error because it returns an error value

this will probably make more sense if I

actually write out some of these

functions so in JavaScript the get user

function might look just like this

function get

user uh we could say uh do some get user

logic

here and then maybe it returns you know

a

user looking at the function

signature all I can tell in JavaScript

is that this function takes no arguments

and the only way for me to know what it

returns is to go find that return

statement see oh okay it returns a user

however in go I actually get two super

helpful things in the function signature

and remember the function signature is

just kind of that first line of a

function definition so in go if I were

to write the function definition for the

get user function would be something

like this

funk get user doesn't take any inputs

but it returns a let's say a user struct

and an error right and then we have some

kind of do get user logic

here right so now just by looking at

this function signature I can tell that

it returns a user and that it could

possibly return an error as well that I

need to go handle whereas again in

JavaScript not only do I not get to see

in the function signature what is

potentially returned but I also don't

know that this function can throw I have

to kind of go digging deeper into the

function definition to see if there's

potentially something uh dangerous going

on in the meat of the function so again

to reiterate because this is actually a

super important point when you're

learning about how errors are handled in

go the primary reason I like error

handling in go is that it forces me as I

write my code to be kind of hyper aware

of every potential error and make sure

that I write code that handles it so now

that we understand what error handling

in go kind of looks like from a high

level let's dive into the detail s

errors in go are just values and

specifically they're just interfaces so

the built-in error interface is an

interface with a single method the error

method and that method returns a string

describing what went wrong so how do we

actually go about handling errors in

code well let's take a look at this

function right here so this is a

function in the standard Library it's

called asky to integer it takes a string

and attempts to convert it into an

integer value and potentially that can

be problematic right because you can

write strings that aren't numbers under

the hood Okay cool so what do we do we

get back an integer and an error and in

essence it's it's it's really simple the

error is either nil or it's not nil if

it is nil that means everything went

fine and nothing went wrong so if the

error is nil it means there is no kind

of string representing what went wrong

because nothing went wrong however if

the error is not nil that means

something did go wrong right so if the

error is not nil in this case then we'll

print an error message and return from

the function right so we're basically

writing guard Clauses that say something

went wrong let's handle this error and

get out of here right enough talk let's

write some code so you can see what I

mean let me expand this so it's a little

easier to see the code okay the

assignment says we offer a product that

allows businesses that use texo to to

send pairs of messages to couples it's

mostly used by flower shops and movie

theaters okay great complete the send

SMS to couple function so that's this

function here it should send two

messages first to the customer and then

to the customer's spouse so use send SMS

to send the message to customer if an

error is encountered return 0.0 and the

error uh do the same for message to

spouse if both messages are sent

successfully return the total cost of

the messages added together okay I think

I understand what's going on so we're

basically going to send both of these

messages one after the other um if any

errors happen we kind of abort early and

return the

error okay so uh send SMS takes a

message as input so first we'll say uh

send SMS and we'll send the message to

the

customer and send SMS returns a float 64

and error so we'll say um I think it's

the cost

return the total cost okay yeah so cost

error send SMS all right if error does

not equal nil so if there was a problem

sending the

SMS uh return 0.0 and the error so

return

0.0 right because this function send SMS

to couple Returns the total cost and an

error so we're saying if we failed to

send the SMS then it costs nothing and

we'll return the error that describes

what went

wrong otherwise we'll do it for the

message to spouse so we kind of are just

going to do this exact same thing so I'm

going to say cost for uh for let's say

customer cost for

spouse and we'll be sending the message

to the

spouse

cool all right now if we get to the

bottom of the function that means

nothing went wrong so we can

return cost for

customer Plus cost for

spouse and nil right because if we get

down here nothing went wrong so we don't

have an error to return okay let's go

ahead and run this code and see what we

get and I want to just scroll down and

take a look at some of these test

cases okay message for customer thanks

for coming into our flower shop message

for spouse we hope you enjoyed your gift

error can't send texts over 25

characters Okay cool so I mean if we

look at the send SMS uh function it

actually throws an error or I shouldn't

say throws because we don't throw in go

right but returns an error value that

says can't send texts over blank

characters so that looks correct to me

um here we've got message to customer

message to spouse total

cost okay this is looking pretty good to

me I'm going to go ahead and submit that

we talked about how error handling in go

is all built around the error interface

in fact let's just review that really

quickly uh this error interface is

really just an interface that wraps a

method returning a string because if you

think about it at the end of the day an

error is just a kind of nullable string

either it's a string representing what

went wrong or saying what went wrong or

it's nothing because nothing went wrong

so being good at handling errors in go

has a lot to do with being good at

formatting strings or formatting useful

error messages so let's review how we

format strings in go most formatting go

is built around kind of these formatting

verbs that are defined in the format

package the fmt package of the standard

Library so for example the S printf

function returns a string where it

interpolates the values passed into the

function after the formatting string

into the formatting string uh string

where where the verbs exist so for

example this first percent V is replaced

with name the second percent V is

replaced with age percent V is the verb

we use for sort of the default format

right if you format an integer using

percent V then it kind of just prints

the integer in string form um but there

are other ways that we can format stuff

for example the percent F verb is used

to format floats and you can actually

specify how many decimal places you want

to show up in your output string by kind

of prefixing the F portion with a point

2 for two decimal places or say A.1 for

a single decimal place so let's jump

right into the coding assignment

assignment says we need better error

logs for our backend developers to help

them debug their code complete the get

SMS error string function so that's this

one right here um it should return a

string with this format Okay cool so I'm

just going to jump right ahead so it

should

return

turn fmts printf right because we're

trying to format a string uh this format

let me expand that a little

bit okay so return a string with that

format uh cost is the cost of the SMS so

I'm going to replace cost here with the

cost formatted to two decimal places so

percent Point 2 F right for two decimal

places and replace recipient with the

stringified representation of the

recipient's phone number which is the

string

here so percent v um it's important to

point out I could also use S here to

format a string but V and S do the same

thing effectively um when you're working

with

strings

and then we need to pass in as

parameters the values that we want to

format or that we want to interpolate

into the string so it's going to be cost

and

recipient going to Dent that because

that is some crazy

formatting okay that looks better all

right SMS that costs per point2 F to be

sent to percent V this looks good to me

all right I'm going to go ahead and run

that and see what we

get ah right can't forget to import the

formatting package let's run

that okay SMS that costs 1.40 to be sent

to the string cannot be

sent awesome this looks correct to me

I'm going to go ahead and submit that

let's talk about building our own cust

error types so remember the error

interface is an interface in fact let me

jump back and show you what it looks

like again so it's just this interface

here and because it's an interface that

means we can build our own types like

this user error struct here that

Implement that interface which means

they can be used as errors and remember

that the error interface just has one

single method that we need to Define

right the error method that returns a

string and as long as we have that then

our type can be used as an error so for

example we could create this user error

type that stores a name and then we can

use it as an error to format an error

message that contains the name of the

user's account who had an error so for

example in this snippet here we have a

send SMS function and if we're not able

to send a message to a user we can

actually just return that user error

struct with the user's name and again

that is an error we can return that

struct as an error type because it

implements the error interface the

caller of this function would then just

treat it like any other error the reason

this is useful is that we can store

structur data within our errors so if we

want to format them a specific way we

have access to sort of dynamic data like

a name let's write some code that uses

this concept so the assignment says our

users are frequently trying to run

custom analytics queries on their

message deliverability metrics right so

we're sending lots of messages we want

to know are these messages getting

delivered they end up writing a bad

query that tries to divide a number by

zero it's become such a problem that we

think it would be best to make a

specific type of error um for dividing

by zero update the code so that the

Divide error type so that's this error

type here or rather this struct here

implements the error interface its error

method should return a string formatted

in the following way cannot divide

dividend by zero okay let's write that

method so it's going to be a function on

the Divide error type so I'm going to

name it de which is

a a divide error and the name of the

function must be error takes no

arguments and returns a string right so

that's that's the function signature we

need to use um to implement the error

interface and then we're going to return

a string and we're going to need to

format the string so we'll use S

printf uh the format package is already

imported and this is our template and

dividend in this case is a float

64

and uh you it says here dividend is the

actual dividend use the percent V verb

so percent V okay so we're just going to

kind of do the default formatting for a

float

64 and

let me indent all this so that it's kind

of

readable where dividend is the actual

dividend of the divider okay so we'll do

de do

Dividend that will interpolate there

okay that looks correct to me I think

we've implemented the error interface

properly let's go ahead and run

that uh oh I forgot my

comma um this is kind of an interesting

Quirk of the go programming language um

if you to add a new line after the last

parameter to a function you have to put

a comma so this would

work all right

and this would

work but this does not work right that's

what I did the first time so just kind

of something to watch out

for okay so let's take a look at this um

dividing 10 by 0 cannot divide 10 by 0

dividing 10 by 2 quotient 5 dividing 15

by 30 5 question okay this is looking

like it formatted properly let's submit

that so we've got a quiz question it

says what is the underlying type of an

error is it an interface is it a struct

is it a string well it could technically

be a struct or a string right like we

saw in the last uh the last assignment

but the most correct thing would be to

say an

interface because it must always be an

interface right it must always implement

the error interface it could also be a

struct or a string um but it will always

be an interface next question is can a

Type be an error and also fulfill

another interface well errors are just

interfaces and we know that types can

fulfill any number of interfaces as long

as they have all of the required methods

so yeah there's no problem with this

let's talk about the errors package so

the standard library and go has an

errors package that exposes a few useful

functionalities but the one we're most

interested in right now is the errors.

new function so the useful thing about

the errors. new function is allows us to

create a new error from just a string so

we don't need to kind of you know Define

a new struct or a new type and then have

it explicitly implement the error

interface that can be a lot of code if

all we want to do is kind of return an

error with a very specific string let's

go ahead and use it the assignment says

twilio software Architects may have over

complicated the requirements from the

last coding assignment yeah all we

needed was a new generic error message

that returns a string no dividing by

zero when a user attempts to get us to

perform the taboo right the taboo of

dividing something by zero complete the

divide function use the errors. new

function to create an error when y

equals z that reads no dividing by zero

okay so this is pretty straightforward

basically if Y is zero which means that

the the number that we divide by would

be zero which is obviously a huge

problem in mathematics you're not

allowed to do that in go or most

programming languages that I'm aware of

um so we need to return an error here uh

so that this operation never happens so

we'll return errors. new looks like the

errors package is already imported for

us and we just need to return an

error that says no dividing by

zero okay let's go ahead and run that

and see what we

get oh I screwed up this function

returns a float 64 and an error so we

should return a zero value for that

first value when we're returning a

non-nil error let's go ahead and run

that cool dividing 10 by Z no dividing

by

Z all of this looks good to me let's

talk about loops in go so if you are

familiar with Loops in other languages

Loops in go syntactically are very

similar to say Loops in JavaScript uh

the main difference is just that we

don't use the parentheses around uh kind

of the the signature of the for Loop um

which again is very similar to how if

statements in go work we're basically

just dropping those uh parentheses

syntactically um the initial portion

runs at the beginning so for example in

this uh snippet of code where We're

looping over the integers 0 through 9 UM

in the initial section we're just

initializing a variable I and setting it

equal to zero um in the condition

section uh we're checking and making

sure that I is less than 10 so at the

end of every uh kind of iteration of the

body which in this case we're just

printing I in the body um we're going to

check and make sure that I is less than

10 if it is we'll continue on to the

next iteration of the loop otherwise

we'll be done um and then at the end of

every iteration we'll also be running

this after section so we'll be

incrementing I and that happens before

uh the condition is run so for example

if we increment I to 10 and then I is no

longer less than 10 we will not continue

on to the next iteration of loop which

is why this prints 0 through 9 and not 0

through 10 10 let's jump right into the

assignment says at texo we have a

dynamic formula for determining how much

a batch of bulk messages cost to send so

we need to complete the bulk send

function it takes a number of messages

as input and returns a float 64 um which

it looks like will be the total cost of

the batch of messages okay each message

costs 1.0 plus an additional fee the fee

structure is so it's going to be first

message is 1.0 plus 0 so 0 is the fee

second message is 1.0 Plus

01 third message is 1.0 plus 02 okay

cool and then our job is to use a loop

to calculate the total cost of all of

these messages for you know the number

of messages that we've been given okay

let's let's just start writing some code

so total cost I'm going to just start it

out at 0.0 and then we'll use a loop or

I equals 0 uh to do like num messages

iterations so you know a number of

iterations equal to num messages so um

start I at zero uh and then we'll do I

is less

than n

messages and I

Plus+ okay so this uh kind of body of

the for Loop should execute numb

messages times and we're going to want

to add the total cost so plus equals um

and we're going to use this formula so

it's going to be 1.0

plus this fee and how do we calculate

that fee well it looks to me like it is

0.01

times the basically the message number

right so for the first message at index0

I equals 0 um it's going to be a fee of

zero so if we just use I this should

work because if I is zero and we

multiply that by 01 anything multiplied

by 0 is 0 right so we'd get 1.0 + 0 for

the second message I should be one so

we'll get 1 plus 01 because anything

multiplied by one is itself um and so on

and so forth um that's looking correct

to me at the end of the function we'll

just return a total

cost cool let's run that oh untyped

float constant truncated to int okay so

I is an INT and we cannot multiply an

INT by a float 64 so I'm going to cast

um I to a float 64 let's try that

again and take a look at some of these

numbers Okay cool so the cost for 10

messages is

10.45 and and that sounds about right

right because each message costs

one plus this like fractional part that

grows over time so like the 10th message

would have cost like

0.10 and it would decrease over time so

that looks about right to

me 50

messages yep okay I'm going to go ahead

and submit that one interesting thing

about four Loops in go is that each

section of the for Loop the initial the

condition and the after are actually

optional and we can omit any of them so

for example if we omit the condition

then the for Loop will just run forever

so let's see why this might be useful um

let's jump into the assignment the

assignment says complete the max

messages function given a cost threshold

it should calculate the maximum number

of messages that can be sent um and then

it looks like the fees for each message

are going to be identical to the last

assignment so let's go ahead and just

get started um so max messages we have a

threshold a cost threshold right we want

to see how many messages we can send

while keeping the total cost under the

threshold so I'm going to create a total

cost variable and set it equal to

0.0 and then this is going to look

really similar to the last assignment um

but basically we'll set I equal to zero

to

start um I'll skip the condition for now

because we don't know to what number

we're kind of looping up to right we're

trying to calculate that so I don't know

where stop yet um but I do want to

increment I with every uh iteration of

the

loop and then I basically want to um

update the total cost by adding to it um

and use uh this formula over here right

so it's going to be

1.0 plus

0.01

time time I which I need to cast with

64 okay so that formula is looking again

identical last time

now if I want to

return the the maximum messages that I

can send while keeping the cost under

the threshold then basically I need to

check and say if the total cost is

greater than the

threshold then I should return

IES that sound right so for example

let's say that right off the bat the

threshold were I don't know is it

negative one right so I'm not allowed to

say send anything I would want to in

that case return zero right cuz I can't

send any messages so what would happen

we'd enter the loop I'd calculate the

total cost for the first message which

would be

1.0 and then because the total cost is

already higher than the threshold I

would return I which would be zero so

that works right however if the

threshold were a little higher let's say

the threshold were 1.5 uh then what

would happen is we do that comparison

the total cost would be less than the

threshold

so we'd continue to the next Loop uh

iteration of the loop where I would be

incremented to one and then on that next

iteration we'd go over okay so this is

looking good to me let me go ahead and

run this

code okay so with a threshold of 10 I

can send nine messages without going

over the

threshold that sounds right right

because I'd have like nine in some

fractional

part let's go ahead and mcy most

programming languages have support for a

while loop and really a while loop is

very similar to a four Loop except it

doesn't have that kind of initial and

after statement it it just runs until

some condition is no longer true now

because of this similarity the authors

of the go programming language decided

to not include an explicit while loop

with a while keyword instead the for

Loop is a while loop or just basically

both those side um kind of sections are

omitted and we just have a condition

that follows the four keyword so in

other words if we have a four keyword

and then a single expression then it is

a condition um that while true will

continue to kind of run the body of the

loop over and over and over again until

the condition stops being true let's

take a look at an example um here we

have a variable called plant height we

start it uh equal to one and we've done

this outside of the for Loop right and

then within the for Loop we just have

one section where we're comparing the

variable plant height to the number five

right and while it is less than five

we'll print this message and then at the

end of the loop we'll increment plant

height now you might notice this looks

just like a for Loop where we've

essentially taken the initial statement

and moved it up outside of the for Loop

body and we've taken the after statement

and moved it within the for Loop body

and that is what we've done right but

it's to demonstrate that this is valid

syntax let's jump right into the

assignment okay so the assignment says

we have an interesting new cost

structure for our SMS vendor so at texo

we have a vendor that we have to pay to

send text messages through right so

we're a software service that makes

sending text messages easy but we do

have to pay some kind of uh maybe

Hardware service that actually does the

sending of uh the text messages kind of

over the wireless network okay um they

charge exponentially more money for each

consecutive test text we send let's

write a function that can calculate how

many messages we can send in a given

batch uh given a cost multiplier and a

Max cost in pennies okay so given a cost

multiplier and a maximum cost our

function will return basically the

number of messages that we're allowed to

send um that's under that that Max cost

so it says in a nutshell the first

message costs one penny Okay actual cost

and pennies starts at one and each

message after that first message uh

costs the same as the previous message

multip by the cost multiplier okay so

that's happening here um gets expensive

uh there is an infinite Loop in the code

okay so on line 10 here we have this

four with no body and then an open curly

bracket um let me show you what happens

when we run that our codee's going to

sit and run and execute the body of that

for Loop over and over and over and over

with no exit condition uh this is

obviously a problem we don't want uh an

infinite for Loop there so our job is to

exit before incrementing Max messages to

send if the cost of the next message

would go over the Max cost so all we

need to do is check and only execute

this Loop while the actual cost is less

than or equal to the Max cost in

pennies um and we're going to have to

cast looks like so this is a float this

is an inch so we're going to cast this

to

64 now this should work because Max

message to send starts at

zero so assuming the actual cost is less

than the Max cost then we go ahead and

increment say we can send one more

message and then we take a look at the

next cost and if the next cost is still

less then we'll essentially get to add

another message so we'll keep kind of

looking ahead and calculating the next

cost right and as soon as the next cost

goes too high we stop okay so I'm going

to go ahead and run

that cool so with a multiplier of

1.1 and a Max cost of five we can send

17 messages that sounds about

right right the actual cost starts at

one the Max cost is five multiplier of

1.1 yeah that sounds right um so the

multiplier goes up Max cost goes up now

we can send nine messages that all looks

good to me let's talk about the modulo

operator how it works and go and kind of

how it works uh generally so the modulo

operator is a percent sign so it looks

like this right and the modulo operator

essentially calculates

remainders remainders so what do I mean

by that well let's jump into an example

uh let me switch colors so

four 4 / 3 in sort of a normal uh

floating Point division uh equals like

1.33333 forever right um we have this

fractional part however that's how math

Works normally and that's how math Works

in floating Point division in a language

like go if we're doing integer division

then we can't have a floating Point

result so the result of four divided 3

and integer division is actually just

one it's essentially the number of times

that three can be divided evenly into

four and then we chop off the remainder

the interesting thing about the modulo

operator is that 4 modulo 3 doesn't

return the number of times that three

can be divided evenly into four it

Returns the

remainder after that division so

actually in the case of Four modulo 3

the remainder is also one so it's the

same but for example five modulo 3

is

two and 6 modulo

3 is zero again because three divides

evenly into six right six integer

division by three is two right because

three goes evenly into six twice but the

remainder is zero that's why 6 mod 3 is

zero let's just do a couple more

examples feel free to pause the video um

in between when I give the question and

provide the solution um so that maybe

you can practice a little bit okay so

let's do

12 mod

4 we'll do in fact maybe I'll just write

out all the problems first let's do

16 mod

5 let's

do

22 mod

8 and let's let's do

27

mod

6 I think those will be those will be

good okay 12 mod four so does four

divide evenly is 12 uh yes 4 * 3 is 12

right so the remainder is

zero all right how many times does five

divide evenly into 16 the answer is

three right 5 10

15 and the remainder would then be one

how many times does 8 go into 22 8 16 24

so 24 doesn't work so it's going to be

16 and then 22 subtract 16 is 6 is the

remainder right and then 27 mod 6 um 6

goes into 27 four times 6 * 4 is 24 so a

remainder of three so an important thing

to note here is if you're trying to

figure out if a number divides evenly

into another number then you can just

check if say a mod b

equals 0 right if aod B equals z then

that means B divides into a an even

number of times so a is a multiple of B

so in go the module operator is just

that percent sign right so seven mod 3

um this expression is going to evaluate

to one we'll also need to know about the

logical and operator and the logical or

operator which are double Ampersand and

double bar uh respective The Logical and

operator operates on two Boolean values

and only returns true if both sides are

true right this and that the or Operator

just needs at least one side to be true

right in order for the entire expression

to evaluate to True let's jump into the

assignment it says we're hiring

engineers at texo so it's time to brush

up on the classic fizzbuzz game coding

exercises have been dramatically

overused in coding interviews around the

world complete the fizzbuzz function

that print the numbers 1 to 100

inclusive each on their own line but

substitutes multiples of three for the

text Fizz multiples of five for Buzz and

multiples of three and five for fizzbuzz

okay so we need a for Loop for I colon

equals 0 I is less than 100 actually

less than or equal to because it said

inclusive right

i++ okay um we need to think about the

order in which kind of these things can

happen happen so we're checking for

multiples of three multiples of five and

multiples of three and five so we

actually should check for multiples of

three and five first because something

could be that and one of the other two

conditions right it could be a multiple

of three and five and just a multiple of

three that makes sense maybe it'll make

sense when I type it out so if I

mod 3

Z and I mod

mod

three zero oops not three and three

three and five then we'll

print bizbuzz

right else

if I mod 3

0 then we'll just

print

is else if I imod five is zero we'll

just print

Buzz

otherwise we'll

print

I

right if they're both multiples Fizz

buzz if it's just three Fizz if it's

just five Buzz okay let's try

that oh cannot forget to import the

formatting package

okay let's

see fizzbuzz one two Fizz four Buzz five

Fizz seven eight fiz Buzz one oh ha one

through 100 that would have been close I

almost didn't follow instructions I was

like why do we have a Fizz Buzz up front

that doesn't uh that doesn't make sense

Okay cool so one two Fizz four Buzz

right five is a multiple of five 10 is a

multiple of five

15 is a multiple of 5 and three so this

is looking correct to me let me go ahead

and submit that so in the last

assignment we kind of uh did a if else

chain within our for Loop but there's

another way that we can write guard

Clauses within Loops um so that we don't

have to necessarily do that if else

chaining um if we don't want to uh the

continue keyword stops the current

eration of Loop and continues to the

next iteration so continue is a powerful

way to use guard classes right so we

write our for Loop and and then if some

condition happens um we can kind of bail

out of the body of the for Loop early

and just continue on to the next

iteration the break keyword is similar

in that it stops the current iteration

but instead of continuing on to the next

iteration it just ends the loop entirely

moving on to the assignment it says as

an Easter egg we decided to reward our

users with a free text message if they

send a prime number of text messages

this year because textio is is run by a

bunch of nerds complete the pr the print

primes function it should print all of

the prime numbers up to and including

Max Max it Should Skip any numbers that

are not prime okay so here's the pseudo

code print Prime Max so let's convert

this pseudo code into real go code so um

for n in range 2 to Max plus one so

we're going to do 4 n colonal

2 N is less than Max + 1

n++ okay if n is two if n is

two n is prime print it fmt do print

line

n and we need to continue right continue

to the next iteration basically saying

okay this n is prime we'll print it and

then we can move on all right if n is

even so so

if n mod 2 is zero right that's an easy

way to check if something is even um and

not make your way onto our programmer

humor if n mod 2 is

zero n is not prime skip to the next n

so uh we do not print and we just

skip

okay next we do a nested for Loop here

for I in range so for I CL

equal 3 to the S < TK of n + 1 okay this

is actually interesting I could use the

math. square root function here that

would be a valid way but if I want to

stay in integer land which I think I do

I can

do

um I can instead Square I so I * I I * I

and see if it's less than

n Plus

right does that make sense so instead of

doing I is less than the square root of

N I can do I SAR is less than

n

right that that makes sense to me cool

um because basically we're just saying

we only need to check up to the square

root of n we know that if we go higher

than that um but like we don't care

about numbers higher than the square

root um cool

next one is

i++ if I could be multiplied into n so

if n mod I

oops if if I goes into n evenly so if

that results in a zero n is not prime

skip to the next

n okay so I can't continue here because

if I continue here here I'll just skip

to the next I and I want to skip to the

next n so I think what I do here is I do

something like is

prime

true here I set is prime is

false and break and then at the end of

the for loop I can say if not is

prime

continue okay

okay uh if n is not prime skip to next n

yeah so we'll break out of this

Loop right we'll break out of this

Loop and then we'll

continue

cool now I just want to be clear there

are other ways to write this function

I'm kind of uh on purpose using lots of

continues and breaks uh so that we can

get some practice with it cool um n is

prime printed so if we get all the way

to here without any of these kind of

guard Clauses being triggered then n is

just Prime so fmt print

line

n let's run that and just sanity check

um our code primes up to 10 2 3 5

7 yep right that's two is a prime number

it's kind of like the only even prime

number and nine is an odd number before

10 but it's not prime because it's

evenly divided into by three right maybe

I should have even explained what prime

numbers are in the first place in case

you're not familiar um there is uh there

is a link here if you want to go read

more about them but basically a prime

number is any number where the numbers

that multiply evenly into it are

anything except one in itself so if it

has any multiples or if it has anything

that multiplies into it that isn't just

one and itself it's Prime right so seven

you can't you can't multiply two into

seven you can't multiply three into

seven you can't multiply four into seven

right um so it's

Prime um let's just uh look at a couple

more of the examples so up to 20 we got

2 3 5 7 11 13 17 19 right again we're

skipping 15 because it has the multiples

three and

five primes up to 30 um again skipping

25 um and also skipping 27 because 9

divides evenly into 27 as as just three

cool so hopefully that makes a bit of

sense and then just kind of as a as an

explanation of of why this pseudo code

Works we're skipping even numbers

because they can't be prime right if it

if two divides into something it's not

prime um we only check up to the square

root because anything higher than the

square root has no chance of multiplying

evenly into n right so like for example

take the number 16 its square root is

four nothing over four could possibly

evenly divide into

16 that the square root couldn't right

so like for example 8 divides evenly

into 16 but that's only because four and

two already

do okay uh we start checking at two

because one is not prime one's kind of a

special case

number okay so this is looking correct

to me I'm going to go ahead and submit

it

let's talk a little bit about how arrays

work under the hood so if you're

familiar with the idea of arrays from

JavaScript or lists from python arrays

and go are similar you can think of an

array is just an ordered list of items

so we usually denote arrays with square

brackets and an array of say three

integers might be something like 2 3 1

right so we've got three integers

stored in our array the first thing is

the integer 2 it's stored at index zero

the next one is a three it's stored at

index one and finally we have a one

stored at index 2 now here's the big

difference between arrays in go and

arrays in JavaScript or lists in Python

in go arrays have a fixed size so the

type of this array would

be three

int so inside of the square brackets we

kind of indicate the size of the array

and then after we indicate the type of

thing in the array so this array's type

is an array of three integers in

languages like JavaScript or again like

lists in Python arrays are kind of

dynamically resize they don't have a

fixed size you can add things onto the

end you can push stuff onto the

beginning but in go arrays are always

fixed so to show you what this looks

like in code um basically we can create

a new array of 10 integers like this it

will initialize all of the indices in

the array to the zero value so this

would be an array of 10 zeros basically

um if we know what we want to store at

each index in the array then we can use

an initialize literal here so we're

saying we have an array of six integers

and in the first index I wanted to two

and then a three and then a five and so

on so let's jump into an assignment and

see how this works the assignment says

when a message is not responded to we

allow our clients to have up to two

additional messages that are sent as

nudging reminders get message with

retries returns an array of three

strings where index zero is the first

message if the first message is not

answered by the recipient we send the

second and then we'd send the third

update get message with reti to return

the three following strings in an array

click here to sign up PR please click

here we beg you to sign up Okay cool so

this is pretty straightforward here

we're just going to

return an array and you can see the

return type up here it's a string array

of size three so we just need to create

an array literal and return it and in

this case we want an array of strings of

size three so array string size three

and we can use these curly

brackets um to be kind of where we put

the string literal so the first string

is going to be click here to sign up

right this is the first message that's

sent pretty please click

here and we beg you we beg you to sign

up and then just remember that in go you

do have to put that last comma um if

you're going to use a new

line okay um pretty straightforward

right let's see how that

works

sending sending to Bob click here to

sign up they responded sending to Alice

click here to sign up pry please click

here they responded okay this is looking

this is looking good to

me going to kind of get a peek at the

uh at the test

Suite cool let's submit it and see how

we did so we've talked about how arrays

are fixed in size and you might be

wondering well that's not very useful

why would I care about an ordered list

of things if I can't even add to or

remove from the list well that's where

slices come into play so let's draw out

a simple

array I'll do it in yellow let's just

say it's storing some numbers we might

have some numbers like six 3 2

6 five and I'll draw the indices let's

do that in pink so the index of the

first item is zero and then 1 2 3 4

right and the size of the array is five

which in go we would write like like

this we would say we have an array of

five items and they are integers Okay

cool so we understand what an array is

but what's a slice well slices in go are

written with this syntax open close

bracket int and you'll notice that the

size is missing okay so a slice is a

dynamically sized flexible view into an

array so slices are built on top of

arrays so that means for example that I

could create a slice that just looks at

this kind of middle

portion of this array if I were to write

this in code I would basically say if

this array is named a so a is this

yellow array here if if I want to create

a slice on top of that array then I

could write

B colon equals

a from we're using square brackets here

index

one up to but not including index 4 okay

so the first the first number is

inclusive the second number is exclusive

and now B is this slice of kind of just

that middle view of the array and here's

the important thing to understand in go

we actually almost never deal with

arrays directly 99 times out of 100

you'll just be working with slices

because slices provide a much better

developer experience they're built on

top of arrays for kind of memory

management reasons which we'll talk

about in just a second but you really

want to be working um for the most part

with slices because you don't have to

worry about that fixed size problem so

just review slices sort of in code um we

can create an array literal like this

right this is an array because we have

we have the uh size of the array there

six integers and then we can create a

slice on top of the array like this cool

um let's jump into the assignment so you

can kind of get a feel for how this all

works okay the assignment says retries

are a premium feature now textos free

users only get one retry message while

Pro members get an unlimited amount

complete the get message with retries

for plan function it takes a plan

variable as input that's a string

matches up to one of these um if the

plan is a Pro Plan return all of the

strings from get message with retries

Okay cool so get message with retries it

looks like

returns an array of three

strings okay let's just jump right into

it if plan is plan

Pro then we'll return all messages right

return all the strings yep and a nil

error otherwise if the

plan is plan

free return the first two strings right

the original string and kind of the one

the first retry message so return all

messages and we're going to slice it

from index zero up to but not including

index two so that'll be indexes zero and

one right two two strings and then we'll

also return

nil and finally if it's neither of those

return an error that says unsupported

plan so return nil errors. new

unsupported plan and nil um is just kind

of the zero value of

slice cool um this is looking good we

need to make sure we import the errors

package let's go ahead and run this and

see what

happens o we got an error cannot use all

messages variable of type

array size three string as slice of

string Okay cool so we have an

array all messages is an array not a

slice right so we actually need to slice

this to change its type but we want all

of the values inside of the array so

we're just going to use this colon

syntax to get access to everything in

the underlying array let's run that

again

cool sending to

osar click here to sign up pretty please

click here so that's two two messages

with no

response um and I'm guessing because yep

ozer is on a free plan Jess Jeff is on a

Pro Plan so he gets all three messages

this is looking correct to me these next

few questions will reference kind of

excerpts from the effective gobook which

is definitely a book I recommend reading

although it is a bit out of date it was

written a while ago um and the authors

have basically made the decision not to

update um the book over time kind of

keeping it as a snapshot so it has a lot

of great stuff in there and go has very

strong backwards compatibility so it's

still a great read um just kind of be

aware that it hasn't been updated um in

a while cool um that said everything we

explained here I'll obviously provide uh

context um for so the thing that's

important to understand in this section

is that slices are references to kind of

what goes on underneath the hood with

arrays so what that really means to you

as a developer is when you use slices

and more specifically when you pass them

around say into a function you're

actually passing a reference which means

if you change the values in that slice

within a function the caller the person

who called your function or I should say

the bit of code that called your

function will actually have access to

those changes it will see those changes

even if you don't explicitly return the

slice again now this is different um

from sort of normal primitive values

which are passed by value you might

remember us talking about pass by value

earlier in the course typically if you

pass in say a string or an integer into

a function and then within that function

you change it the caller won't see those

changes you have your own copy of that

data that's that does not hold true with

slices so just understand that when you

pass a slice into a function it might

get

modified okay cool um so which

references the other is the question do

arrays reference slices or do slices

reference arrays and the answer is that

slices reference arrays the next

question is can multiple slices point to

the same array is that true or false

multiple slices point to the same array

um that is true remember slices are just

kind of a view into an array so it makes

sense that you can have multiple views

into the same underlying array so

multiple slices can point to the same

array now here's that question um that

we talked about earlier a function that

only has access to a slice can modify

the underlying array the answer to this

is that is true even if the function

doesn't return that slice it can modify

the values in the underlying array let's

talk about how slices work um kind of

specifically how work in relation to

your computer's Hardware or your

computer's Ram now Ram just stands for

Random Access Memory it's where

variables are stored the best way to

think about Ram is just a mapping of

addresses so

address to

data right it gives us a place to store

stuff so for example at address

Z we might have some data that

represents I don't know the number four

right and then at address one we might

have some data representing the number

five I don't know I'm just making stuff

up but you get the idea we have

addresses and we have data associated

with that address slices and the arrays

that they are built on top of are stored

in contiguous memory basically what that

means is a slice or an array is an

address in memory where where the slice

or array starts so for example at

address zero we might say this is the

start of a

slice and the slice actually continues

for the next you know several uh kind of

bytes of data let's say that it's a

slice of length three so it actually

would reach across all three of these

addresses so if you have an array or a

slice um and its address is zero and its

length is three then you know kind of

how many uh stores of data in memory um

your slice or array will use now this is

primarily important for performance

because all of the data is stored next

to each other in memory it's going to be

faster to kind of iterate over all of

the values in our slice if we stored

each index in kind of random places in

memory it would take a lot longer to go

collect all of that data just you know

from a hardware perspective however

there is a downside to having to store

all of our memory um kind of next to

each other let's pretend that we have

this slice or this array that starts at

address zero and has a length of three

so it's using kind of these three

addresses in memory or these three bytes

of memory and let's say here at address

3 we're storing a different value maybe

we're just storing I don't know the

number six um but this is a different

variable

this is some other variable the problem

is if we want to expand our slice say

add another value to it we're going to

run into the next thing in physical

memory that's a huge problem we don't

want to overwrite some other variable

just because we're growing our slice so

this is why arrays are fixed in size if

we just can't grow them then we'll never

have this overwriting problem so the the

question of course is how do slices do

it right well slices are built on top of

rays and basically what happens is I can

draw this out for us when we want to

grow a

slice whose underlying array has run out

of room right so we have our slice um

built on top of this length three array

and we want to grow it into a length of

four what happens under the hood and

this all kind of happens without you

seeing it as a developer you'll you'll

see later when we get to the syntax it's

actually really simple um what happens

is this data is copied into a new

location memory so we just take this

four we put it over here five over here

uh actually I'm going to use the same

colors that would probably be easier to

understand so four comes over here five

comes over here three comes over here

and then let's say that we um we know we

want to grow our slice significantly so

the new underlying

array let's say will have a length of

six now so it had three here now the new

array has allocated pre-allocated right

we've essentially reserved memory for up

to six spaces let me draw all of that

out cool and these addresses over here

are going to be totally different right

maybe it's address 15 address 16 17 18

19 and

20 cool so all the data from the old

array gets copied over and now we're

able to expand our slice

our slice to a length of

four right so here our slice was length

three and the underlying array was

length three now we've copied over the

data we've created a much larger

underlying array and now we have a slice

of length four maybe we wanted to append

say the number two to the end of the

slice so again as the developer you're

not going to have to do all of this

array management manually but it's

important to understand that this is

what's going on under the hood because

it has performance implications copying

data isn't super efficient if you're

copying data from one section in memory

to another um over and over and over

again it can slow down your programs so

now that we've covered all of that

memory stuff and how it works under the

hood what does that mean in code right

well this is how we can create a slice

without explicitly creating an array

under the hood right so this will

automatically create an an array under

the hood for us if we use this syntax so

this is basically saying I want a new

slice of integers I want its initial

length to be five so the length of the

slice right the length of the view into

the array will be five and the capacity

will be 10 so the capacity is kind of

the total space that we have to grow the

slice until we need to allocate a new

array under the hood so you could almost

think of this capacity is just the

length of the underlying array now I

told you that you don't need to think

about the size of the under the Ling

array and that is true typically you'll

actually use this syntax where you don't

even specify a capacity so if you do not

specify a capacity it defaults to the

length so the kind of length of the

underlying array for a slice of integers

with length five will just be five and

if you grow it past that the memory

copying will happen and you'll create a

new underlying array now you might be

thinking oh that's terrible for

performance in reality it's not that bad

the only reason you would start to kind

of fuss with specific capacities and

optimizing your memory copying is if

you're having performance problems

generally speaking the convenience of

keeping your code simple and easy to

understand is going to outweigh kind of

the performance cost that it'll have

it's it's a very small one generally

speaking and then it's also just worth

pointing out that we can also create

slice literals right so this just

creates a new slice slice of length

three um and initializes these three

values into that slice rather than what

would happen up here which is that we

create kind of all of the zero values um

to fill out the slice kind of of the

given length so this would be a slice of

five zeros right and then to just point

out two more things regarding syntax

there is a built-in length function that

Returns the length of a slice and a

built-in cap function that Returns the

capacity so now that we are experts on

slices let's jump into the

assignment says we send a lot of text

messages at texo and our API is getting

slow and unresponsive so I just

mentioned how you probably shouldn't

worry about performance well here's a

case where you should worry about

performance right you shouldn't worry

about performance until well it starts

to become a problem so we're starting to

have a problem with um this memory

copying being slow so we've been asked

to preallocate our

slices it says um if we know the Rough

Side of the before we fill it up we can

make our program Faster by creating the

slice with that size ahead of time all

right so complete the message get

message costs function it takes a slice

of messages and returns a slice of

message costs FL 64s right reallocate a

slice for the message cost with the same

length as the message slice let's go

ahead and start off with that so

costs we'll make a new slice and it's

going to be a slice of float

64 and a length of length messages right

same same length cool um now we want to

fill the co fill the cost slice with

cost reach message so let's go ahead and

iterate over each message so for I colum

equals

0 I is less than length of

messages

i++ let's get the message at that index

messages

zero oh not a zero excuse me at

I okay the cost in the cost slice should

correspond to the message and the

message slice at the same index the cost

of a message is the length of the

message multiplied by 01 so cost equals

the length of the message multiplied by

01 that's going to need to be cast to a

float

64 perfect cool and then we just need to

save that into the costs slice so costs

at I equals

cost right correspond with the same

index and we know that that um that

index already exists because we

pre-allocated it to the correct size

cool so now we can just return costs

let's go ahead and run

that and see if these make

sense okay these costs line up with the

length of the messages so this is is

looking good to me let's review the

difference between the length and the

capacity of a slice sometimes this can

be a little bit confusing the length is

the thing that you're going to care

about most often the length just tells

you how many things are in that slice

right if I have five items then the

length of the slice is going to be five

the

capacity the capacity of a slice reports

the maximum length the slice can assume

right before it gets kind of reassigned

into a new array so capacity is really

again only something you're going to

care about if you're worried about

performance but the length you'll be

concerned about just for kind of normal

business logic reasons right just

because you want to know how many things

are stored in your slice so to answer

this question it says what does the cap

function return answers are the last

last element of a slice or the maximum

length the slice of the slice before

reallocation of the underlying array is

necessary the answer is going to be the

maximum length the next question is what

does the length function return current

length of the slice or the maximum

length of the slice before the

reallocation is necessary and the answer

is going to be the current length of the

slice and we haven't really talked about

this yet but I'll just kind of inform

you as we answer this question says what

do length and cap the two functions do

when a slice is nil do they Panic or

return zero and the answer is that they

return zero they are safe functions to

call um they won't make your code panic

and error and crash right um I don't

know how much we've talked about

panicking up to this point in the course

but panicking just means runtime error

that's unrecoverable

unrecoverable um generally speaking you

don't want your code panicking and you

want to write your code in such a way

that it can't Panic um so again length

and cap here um are safe they will never

Panic if um a slice happens to be um the

zero value which is nil time for some

vartic functions um this sounds like a

really complex thing but we've actually

been using vartic functions up to this

point in the course because the S printf

print F print line all of those

functions are actually vartic so a

vartic function receives the vartic

arguments as a slice let's take a look

at the syntax so here we have a sum

function and its function signature is

just maybe a little bit different than

you're used to basically we have this

nums uh parameter which is of type dot

dot do int now here's the thing dot dot

do

int as far as the function definition is

concerned is just a slice we treat this

just like we would if it said you know

square brackets int it's it's just a

slice of integers so you're probably

sitting there thinking well why can't I

just use a slice of integers why can't

we just keep it simple why do we have to

do everything differently ah okay well

uh don't don't worry too much um the

difference is on the caller's side so

the function definition is the same

whether you use dot dot dot int or

square brackets int but if you use a

vartic function then the calling code so

the code that uses the sum function can

actually pass in kind of any number of

arguments and they'll come into the

function as a slice of integers so here

we could call for example sum 1 2 3 and

the sum function gets a slice of

integers with you know the values one

two and three in the first three indexes

of the slice um this means that the

caller could also call some one comma 2

right and we'd have a slice of length

two so it kind of just gives the collar

of the function a different syntax um

and specifically kind of a more flexible

syntax uh for how they're able to pass

in sort of a dynamic number of arguments

into the function now again we've

already been using vartic functions you

probably remember the print line

function right this is how we print text

to the console um it's a vartic function

dot dot dot interface right so it can

take any number of arbitrary inputs and

it sort of prints them all out with new

lines in between each element now along

with vartic function definitions we also

have another operator called the spread

operator and the spread operator is kind

of like the inverse

of a vartic function by using the spread

operator we're able to take a slice of

values and pass them into a vartic

function so this isn't the intended use

case 100% of the time otherwise you just

Define your your function to take a

slice of strings and you'd pass in a

slice of strings but if you do have a

function that is already vartic and you

want to pass in a slice as the variable

part then you can use this spread

operator this trailing dot dot dot to

sort of spread out in this case this

name slice into the vartic function

let's get our hands dirty with this so

it says we need to sum up the costs of

all individual messages so that we can

send an end of Monon Bill to our

customers complete the sum function so

that it Returns the sum of all of its

inputs cool so this is going to be very

similar to this sum function right the

the difference here is that we're using

float 64s and we're going to write it

from scratch uh so that we get our own

our own crack at it okay so first things

first uh let's create kind of the

default sum which is going to be

0.0.0 so uh let's say

total now remember we can treat nums as

just another slice of float 64s so 4 I

colon equals 0 I is less than length of

nums

i++ total plus

equals nums at

I

right return

total cool pretty straightforward um

let's go ahead and run

that so summing three costs bill for the

month $6

5 costs 15 10 costs 55 do these match up

looks like yep that should be

six 6 + 4 + 5 that's 6+ 9 that's 15 Yep

this is looking good I'm going to go

ahead and submit that now I told you

that resizing slices is possible we just

haven't really done it yet um that's

what the append function is for so the

built-in append function is actually a

VAR adic function but it allows us to

just add new things to the end of a

slice and automatically takes care of

adjusting the length and the capacity of

the slice accordingly right allocating

new underlying arrays as necessary now

here are your syntax options for using

the append function if you just want to

append one thing then you'll use this

top option let's say we have a slice

called slice we want to append a

variable called one thing to it

basically we call the append function we

pass in the slice we want to append to

as the first uh item we pass the

variable that we want to append onto the

end as the next thing and then we

reassign back into that same slice now

because append is a vartic function we

can append multiple things right so um

if we want to append the first thing and

then the second thing after that um we

could do it like this and obviously we

could also use the spread operator if we

want to to be 100% honest though 99% of

the time you'll be using this first one

because you'll just be appending items

one at a time let's hop into the

assignment it says we've been asked to

bucket costs for an entire month into

the costs that occurred on each day of

the month so complete the get cost by

day function it to return a slice of

float 64s where each element is the

total cost for that day okay so we have

like this giant list of costs and we

need to kind of uh condense all the

costs that happened on a specific day

into one index for that day makes sense

to me the length of the slice should be

equal to the number of days represented

in the costs

slice including any days that have no

costs up to the last day represented in

the slice Okay cool so if we have costs

just for say the first month or the

first day of the month and the fifth day

of the month then we should have um kind

of five indexes in our resulting array

with kind of a non-zero value in the

first and the fifth indexes zeros in the

middle and nothing after that okay here

we've got an example

um given this input so day cost so we

have costs on days on days 0o one and

five this would be the resulting array

right $4 on the first day 5.2 on the

second day because we sum those right

and then on that last day we'd have

2.5 cool let's write the

function so first things first we're

going to need

um we're going to need a slice to append

into so costs by day we'll make a new uh

a new slice of float 64 and here I'm

just using the slice literal syntax um

instead of the make function they're

pretty dang

similar now we're probably going to want

to iterate over all of the cost so for I

equals 0 I is less than length

costs

i++ costs at

I okay so a cost is this structure here

and we can take a look at the day

there um we're going to need to figure

out basically when we're appending to

this costs by day slice and when we're

just adding to an existing index so I

think the easiest thing to do would

basically be to

say um

if day is greater than the length of

costs by

day actually it's going to be a four so

like while the day is greater than the

length of cost by day we're going to

append cost by day equals append cost by

day

0.0 right so in effect this for Loop

here just says if I've encountered a day

that I don't yet have room for I'm going

to grow the slice by just appending

zeros until I have enough room so once

we're done with that Loop we should be

able to assign directly into the costs

by

day I basically saying cost by day plus

equals

cost.

value right because it starts at zero so

then we can just

add we just add the cost and again if if

the day is less than cost by day then we

just don't do this step we just skip

over this for Loop so that's looking

correct to me I'm going to go ahead and

return costs by

day and let's run that code see what we

get undefined day what did I screw up

here yeah needs to be cost. day right

access that

field invalid operation cost by day plus

equals cost. value so cost. value is a

float

64 costs by

day is a slice of flow

64s right because this is a slice so

costs by

a

at at cost.

day

right right because our the slice that

we're

returning um the indexes in each or the

indexes of the slice represent each day

in the month so we need to index back

into the

day okay try

that whoa what do we got

Panic runtime error index out of range

zero with length

zero

okay what did we screw

up

so somewhere we are indexing into a

slice where the value doesn't like the

the the index that we're indexing with

is outside the range of the slice so um

we haven't really talked about this this

is probably great that we ran into this

bug um if you try to index which is this

operation here so like this is indexing

into index five right but here we're

indexing into cost. day which holds an

integer um if you try to index into an

index that is outside the length of the

slice so you have a slice of length say

three and you try to access index six

then you'll encounter this error that

that's what we're seeing here so it

looks like that's what we are doing

so for cost. day is greater than the

length now let's think about that if the

day is five and the length is

five we are not going to do our growth

so I'm actually I think I have an off by

one error here right I actually what I

actually want to do is say if the cost

if the if the cost. day is greater than

or equal to the length right because an

array or a slice of length four actually

only has

three um kind of indexes I mean it has

four indexes but they start at zero so

like length four the indexes are 0 1 2

and three right let's go ahead and run

that

again cool no more

Panic day one $1 or day Zero $1 day one

510 day 2 250 let's see if that lines up

with the test

Suite so here it looks like Day Zero

should have one day one should have yep

5.1 if we add those together and day 3

should have 5 point what's that

6.3 yep 6.3 okay this is looking correct

to

me slices can hold other slices right

this kind of creates a 2d Matrix um of

values right so for example here a 10x10

Matrix of integers would look something

like this where the First Slice is just

a slice of slices hopefully that makes

some amount of sense if not don't worry

we'll get into the assignment here in

just a second so it says we support

various graphs and dashboards on Tex

that display message analytics for our

users the UI for our graphs and charts

is built on top of a grid system let's

build that grid logic so this is super

common in graphics development right

we're kind of building on 2D screens so

we need sort of an X and A Y um cell

within a matrix which is again often

represented as a slice of slices the

assignment says complete the create

Matrix function it takes a number of

rows and columns and returns a 2d slice

of integers where the value of each cell

is I * J where I and J are the indexes

of the row and column

respectively okay cool so create Matrix

we get two integers representing how big

we want the Matrix to be and we just

have to return the Matrix Okay

cool

so let's go ahead and start building

that out first we need to create um or

initialize the Matrix so let's say

Matrix slice let's use make make slice

slice

in right and we can just initialize it

to a length of zero it doesn't matter

we're going to grow it and four I col

equals 0 I is less than length of

rows

i++ and then we're going to need an

inner for

Loop manage J which is going

to deal with the number of columns

columns

j++ okay so what do we do

um when we get to the first row well the

first thing we need to do is make a new

slice to represent the row so we'll say

row make and we can just

do a a single slice of integers again

row uh length of Zer is fine um we could

pre-allocate but it probably doesn't

matter too much at this

point um and then for each J a we're now

going to append into the row so we do

row equals

append

row I * J I believe was the formula

right we want every cell to be the

result of I * J so the values will sort

of grow out um as the Matrix gets larger

and

larger cool so that's adding the like

this inner loop is adding values to each

individual row and then we just need to

append the row to The Matrix so

Matrix equals append

Matrix

row and then when we're done appending

all of the rows to The Matrix we can

return the Matrix

itself go aad and run

that invalid argument row variable of

type int for length see what we got

here where did I screw up

this time

right I don't know why I'm checking a

length here Rose is just an integer it's

not a slice with a size let's try that

again cool creating a 3X3

Matrix does that math check

out 1 * 1 is 1 1 * 2 is 2 2 * 2 is 4 yep

that looks good cool let's submit it I

want to show you a common Pitfall that

you might fall into uh when dealing with

slices and how you can just outright

avoid it um this is something you should

pretty much never do when you want to

append to um other slice in this case

you want to append elements to other

slice you should always reassign into

the same slice so this should read other

slice equals append other slice element

you don't want to be pending um kind of

into one thing and reassigning into a

separate slice you'll run into some bugs

and we're going to talk about how that

works right now so in this first example

we have these slices a b and c and by

the way I would highly recommend coming

here on bootd so that you can actually

kind of look and puzzle through what's

going on in the code rather than just

seeing it on the screen um but basically

we have these slices and when we append

to them

we're we're breaking the rule basically

we're uh appending for example here um

four onto a but then returning the

value the value returned by a pend we're

kind of saving it into a new slice

called B which again you you generally

should not do you should just save it

back into the same slice a um but

anyways we're going along um kind of

doing that pattern and at the end you'll

notice that nothing too terrible

happened um basically we ended up with

an a with three zeros B had four

appended to it properly and C had five

appended to it properly so you could

kind of take away from this example well

maybe there's nothing wrong maybe we can

just kind of uh break the rule and

append into new slices seems like

everything's working like I'd expect and

it's worth pointing out that we can even

print out the addresses in memory of the

slices B and C and see the addresses are

different in other words when we called

this append functions where we append

five onto um you know the slice a and

save it back into the variable C we can

see that actually C is being kind of

copied into a new location so again

everything's kind of working as we'd

expect now it's really in this example

two that something very strange happens

if we look

down here we're a pending onto

J the value four and then we're

appending onto G here the value five but

the interesting thing is that after we

append five to G if we print out J again

we can see that J was actually changed

kind of under the hood right up here J

had four in its fourth

index and then we never touched J again

directly but by appending onto G we

actually screwed up J we mutated J and

the reason for that is because in this

example because of the way we've

sloppily used the append function G and

J actually point to the same address in

memory so mutating G changed J now I

already mentioned that we were doing the

same thing up here right we were using

the same kind of sloppy use of the a

pend function that I'm recommending to

avoid but we only had the bug in example

two and the reason for that is because

the original slice in example two has a

capacity of

eight while the original slice in

example one had a capacity of three so

what that means is when we used the

append function in the first example

once we went over the capacity we

allocated a new underlying array which

is why we got different memory addresses

and so when we mutate C here C is in a

different place in memory than b so

they're kind of operating independently

which is again what you usually want in

your

code however because the capacity was

already large enough in example two

there was no need for the append

function to create a new underlying

array so G and J point to the same the

same array in memory again which means

if we mutate G under the hood we just

mutating J so again the way you can

avoid all of this

headache is to just not do this right

append onto the same slice pretty much

every time unless you have like some

crazy specific reason not to do so which

like I'm skeptical that exists I

certainly haven't run into it in you

know many years of writing application

code in go so the question for this quiz

is why is five the final value in the

last index of array J right so why why

did we have a five here even though we

appended for um and the answers are J

and G point to the same underlying array

so G is aend over OJ the go team is

trolling I think that's obviously not it

uh and because a pend only works

properly when the number of elements is

less than 10 uh that would be very silly

so it's it's definitely this middle one

we're overwriting the same location in

memory next question on the same topic

is why doesn't the bug regarding slices

J and G in example two occur in example

one as well and the the answers are

because there are fewer elements and

goes runtime can't handle more than

eight elements that would be awful um or

the array's cap is exceeded so a new

underlying array is allocated and and

that one is the answer so the next

question is how can you best avoid these

types of bugs don't use the append

function always assign the result of the

append pend function back into the same

slice or always assign the result of the

append function to a new slice well it's

not using a new slice that's how we got

into this trouble in the first place and

we definitely want to use the append

function it's pretty useful so again

always assign the result of the append

function back into the same slice you'll

avoid a lot of headache that way finally

some syntactic sugar to help us iterate

over the elements of a slice you've

probably been wondering for the majority

of this chapter uh do I have to do this

I equals z i is less than the length

every time I want to iterate over the

elements of the slice other languages

have syntactic sugar to make it easier

so does go so the syntax is pretty

simple um this is it right here and

basically by writing it this way index

at each iteration of the loop will be

equal to the index in the loop starting

at zero right so 0 1 2 3 and then

element is the value associated with

that Index right and then obviously

slice here is the name of the slice so

range is a real

the interesting keyword that allows us

to iterate over everything stored in a

slice to give a more concrete example

here we have a slice of strings called

fruits and we can arrange over the

fruits and if we print I and fruit in

this example that we print zero apple

one banana two grape and so on let's

jump into the assignment it says we need

to be able to quickly detect bad words

in the messages that our system sends

complete the index of first first bad

word function okay so that's this um it

finds any bad words in the message if it

finds any bad words in the message it

should return the index of the first bad

word in the message slice this will help

us filter out naughty words uh from our

messaging system if no bad words are

found will return negative one instead

use the range

keyword Okay cool so the bad words

themselves are defined for us and passed

into our function and then the message

itself is already broken up into words

it looks like and passed in is an array

of strings right so we can I'm kind of

just figuring this out by looking uh

looking down here so we have a slice of

bad words and a slice of words in the

message hey there John Okay

cool so um let's

start by iterating over all of the words

in the message right seems like a

reasonable place to start so

for I word colon equals range

message and then we want to check and

see

if if one of these words is equal to one

of the bad words so we're going to use a

nested Loop

actually we'll do

J bad word in range bad

words right and then here we can say if

word equals equals bad

word that means we found the bad word

and we can

return we want to return the index so we

return I right that would be the index

of the bad

word otherwise if we don't find a bad

word we'll just keep going um in fact

we'll just keep going through all the

bad words and then we'll keep going

through all the rest of the

words and if we get to the end of

everything without finding any matches

then we can just return negative

1 makes sense right

cool let's run

that J declared not used right um so

we've come across this syntax before we

can ignore variables with an underscore

right let's run

that let's take a look at our test Suite

scanning message hey there John for bad

words index negative one that means none

were found right which makes sense we

didn't have any scanning message uh oh

my freck for bad words brick is a bad

word index 3 okay this is looking good

to me I'm going to go ahead and submit

that if you're familiar with object

literals in JavaScript or python

dictionaries then maps and go are

essentially the same thing maps are just

a way to associate a key with a value so

let's take a look at this example we

create a new map with this syntax here

we're going to use this built-in make

function and then pass in the type of

the map so map of string to integer so

we're mapping strings to integers and

we're going to say inside of the ages

map we're going to set the key John to

the integer 37 so again we're mapping

that name John to the value 37 rather

than creating an empty map and then kind

of adding key value pairs one at a time

we can also declare the entire map up

front and use kind of this colon syntax

to separate the keys and the values

and then we can also check how many keys

I guess keys and values are in the map

by using the built-in length function

similarly to how you would use it on a

slice um so in this case we create a new

map we create two keys each with their

Associated values and then by printing

the length we'll just print the number

two so let's jump right into the

assignment that's usually the best way

um to get an idea for how all the syntax

Works assignment says we can speed up

our contact info lookups by using a map

look up a value in a map by its key is

much faster than searching through a

slice so when we look up something in a

map by a given key that's going to be an

instant

lookup if we had stored it in a slice

then we'd have to search through the

entire slice sort of index by index

looking for the value that we want so

Maps can be a great way to make our code

more

efficient the assignment says complete

the get user map function it takes a

slice of names and a slice of phone

numbers and returns a map of of name to

user structs and potentially an error

okay so let me expand our coding window

here okay so we're returning a map of

string to user structs looks like the

user struct is defined right here if the

length of names and phone numbers is not

equal return error with the string

invalid sizes the first name in the name

slice matches the first number and so on

Okay cool so first things first we're

going to have to create a new map so

we'll do um user map

colon equals and I'm just going to

create a literal a new map literal

actually no I won't I'll do I'll use the

syntax from up here this works just fine

so we'll use the make function so make

map of string to

user right so that's now an empty

map and then what we're going to do is

check and make sure that these are the

same length so if the length of names

does not equal the length

of phone

numbers then we'll return nil so nil is

the zero value of a

map we could also return an empty map of

the same type but I'd say you should

prefer nil um for slices and maps and

things um and then the

error should say invalid sizes so

errors. new

invalid

sizes we'll import the errors package

Okay cool so if we get down to line 13

now we should know that both of these

slices names and phone numbers are of

the same size which means we can Loop um

like this so four I starting at zero and

I is less than the length of it doesn't

matter because they'll be the same right

length of

names

i++ then we can say

name is names at

I and we can say fun phone

number phone

numbers at

I

okay and then we're going to want to

insert values into the user map so we'll

do user map at the key in this case the

key is the name right so key is the name

and we'll set it equal to a new instance

of a user struct so

user and the user ruct has two Fields

name which will just again be the name

and the phone

number uh which will just be this phone

number

here

cool so that should fill the entire user

map with all of the names and phone

numbers and then by the end we should

just be able to

return user map

nil okay cool I think we got everything

let's go ahead and run that

and see what we get so creating map key

John value name number key Bob value

name number this is looking this is

looking correct to me here we have

creating map with invalid

sizes um if we take a look at the

tests uh yep that makes sense the second

test has two names but three numbers so

I would expect it to get that invalid

sizes error cool let's uh let's submit

that so the primary way you interact

with maps is just by setting and

deleting uh values at a given key right

they're very associative right a value

maps to a key but there's no other

ordering Maps aren't ordered from you

know index 0 1 2 3 uh like a slice is

everything's unordered you're literally

just mapping values to Keys Okay cool so

let's take a look at some of the

different syntax that we can use to

interact with maps so we can insert an

element by just setting the key equal to

the value um we can get an element out

just by accessing it directly at its key

we can delete Elements by using the

built-in delete function where we're

passing in the map itself and the key

that we want to delete notice that we're

not passing in the value at all we're

just passing in the key and then we can

also check if a key exists by parsing

the return value of kind of this access

syntax into two separate values where

the first value will be the element

itself and the second value is a Boolean

if the Boolean is true then the element

will be whatever element was stored of

that key however if the Boolean is false

that tells you that that key didn't

exist in the map and the element will

just be the zero value for its type

let's jump into the assignment so it

says in fact let me uh let me resize

this a

bit says it's important to keep up with

privacy regulations and to respect our

users data we need a function that will

delete user records okay complete the

delete if necessary function um it takes

a a map of users and a name which I'm

going to guess is the key in the map and

it will return a Boolean saying whether

or not the user was deleted and then an

error if something went wrong okay cool

so if the user does not exist in the map

return the error not found oh

interesting so if we're trying to delete

something and it's not there um that's

an error if they exist but aren't

scheduled for deletion then return

deleted as false so we this will be

false um and there won't be any errors

um but if they exist and are scheduled

for deletion then we'll return uh the

deleted Boolean as true with no other

errors okay that's making sense to me

and then a note on how maps are passed

into functions is that like slices maps

are actually passed by reference so even

though this function delete if necessary

does not return a map if we mutate this

users map it will be mutated for the

color of the function so that's how

we're able to delete something from the

map even though we're not returning the

map once we're done with it so the first

thing we need to do is just check and

see if the name that we're trying to

delete exists so let's do this if blank

okay colon equals

users at

name not not okay so uh this is that

kind of special if statement syntax

right um where we're uh actually

ignoring the value at self um we're just

interested in that Boolean value telling

us whether or not this um this key

exists in the map and if it does not

then we're going to go ahead and return

uh return the error not found so false

because we always do zero values for

everything besides the error and then

errors.

new not found and we'll make sure to

import that errors

package okay cool and again I'm just I'm

just uh using this syntax here to check

if a key exists

cool moving on okay so if we get past uh

past that guard Clause to line 12 then

we know um that the user exists so um at

this point ah we need to check if

they're scheduled for deletion so I'm

actually going to switch up my syntax

here the user struct has the scheduled

for deletion Boolean so I'm going to go

ahead and do this on a separate

line and I will save that user so I'll

do um existing user

and then we'll just do if not

okay so that down here now I can use

that existing user struct so I can say

if existing user. scheduled for

deletion so if they exist and are

schedul for deletion return deleted as

true with no errors and delete the

record from the map so we need to use

this built-in delete function so we'll

delete

users name and then we'll return true

n all right so if they are scheduled for

deletion we'll delete them and report

back that we deleted them cool um

otherwise if they're not scheduled for

deletion return deleted as false with no

errors so

return false

no okay that looks right to me let's go

ahead and run

that attempting to delete John deleted

JN attempting to delete musk not found

Santa not found attempt to delete Kade

did not delete Kade Okay cool so I mean

all that look it looks like all the

cases were covered let's just come down

here and take a

look okay so we had a John and JN was

deleted and then attempting to delete

musk there's not actually a musk in the

map so not found makes sense um there's

also not a Santa and Cade was not

scheduled for deletion so he did not get

deleted and then the final map still has

those keys that looks correct to me in

the this next section we're going to be

covering some of the material from the

go blog now I'm not going to read all of

this out uh that would be a little dry

but I definitely recommend reading this

over if you have the time otherwise I'm

going to cover kind of the key points so

the first question is what makes a type

qualify to be able to be used as a map

key okay so any type can be used as a

map value but not every type can be used

as a map key and that's because map Keys

make may be of any type that is

comparable so things like strings

booleans um numbers all those can be

compared for a quality what cannot be

compared for equality are slices maps

and functions and kind of one of the

reasons for that is slices and maps and

functions they're kind of just pointers

to addresses in memory so if you compare

one slice to another slice you're not

really comparing the underlying values

you're actually comparing kind of where

those two slices are stored in your

computer's

RAM and because they're stored in

different places you'll actually get two

slices with maybe the exact same values

stored in them say slice one has the

numbers one two three in the first three

indexes and the second slice has the

same they might still be compared as

unequal because they're stored in

different addresses in memory so I mean

all that being said long story short you

just can't use slices and maps maps and

functions as map keys so to answer the

question what makes type qualifi to be

used as a map key the type is comparable

this next question is interesting and

kind of plays on the idea that we can

Nest Maps um kind of one inside the

other or we could do something that's

arguably simpler let me show you what I

mean so here is an example of a map of

strings that maps to another map which

maps from strings to integers so like

the first string kind of maps to the

second string which maps to an integer

if you want to think about it that way

if you're familiar with Json objects

this would be like mapping Json objects

kind of down multiple uh levels of keys

so in the example given in the go blog

essentially what's being said is we're

mapping um two strings to a count and so

what that looks like in code is if we

want to get access to the count we

actually have to go to the map index the

nested map with a key and then index

into that next map with another key

before we get the value out now this

looks simple on the surface but what

actually happens is when you need when

you go down those nested levels you

actually can't be sure that the inner

map exists and So to avoid panicking

your code will actually Panic by the way

if you try to access a key in a map that

is nil So to avoid panicking you have to

check and make sure that those nested

Maps actually exist which just results

in a lot of extra code so while nesting

Maps definitely works and I've used it

quite a bit there can in some instances

be a simpler way which is to actually

use a struct as a key notice that a

struct was not named as one of the

non-comparable types structs are

comparable so if you want to create a

map that kind of has multiple keys that

kind of combine together to form a

composite key then just create a new

struct right with two values inside of

it and those two values kind of unique

together create their own key so this

simplifies a lot of things where now we

can have one map and we can use that

struct key to create kind of uniqueness

across two different values this might

be useful for example if you're trying

to create a map That's Unique for first

last name combinations right you want

Lane Wagner stored in two different

fields first name and last name to be

unique together so to answer the

question which is simpler to use a

struct directly as a key or to Nest maps

and um the authors of the go blog and I

would agree argue that using a struct

directly is going to be simpler let's

jump right into this next assignment

says we have a slice of user IDs okay so

those are strings and each instance of

an ID in the slice indicates that a

message was sent to that user we need to

count up how many times each user's ID

appears in the slice to track how how

many messages they received implement

the get counts function okay so that's

this one it should return a map of

string to int so that each int is a

count of how many times each string was

found in the slice okay cool simple

enough so let's create a new map so this

will be the counts map and it's going to

be a map of string to

integer and then let's Loop over all of

the user IDs so four blank user ID

in range user

IDs we're just we're going to ignore the

index because we don't care about

it and the first thing we're going to do

is check to see if um a value in the map

for the given user ID already exists so

count okay colon

equals user

IDs sorry

counts at user ID

right cool um in fact now like now that

I type that out I'm not actually sure

that I need this because if I don't use

this this access will still work it's

just if if the key didn't exist count

will be zero which is fine so actually I

I don't even think I care um cool so we

get the count it'll be zero if it didn't

yet exist and then we just increment it

by one so count Plus+

and then we'll save it back into the map

so counts at user ID equals count so

we're just grabbing it out incrementing

it by one and putting it back that seems

like what we want to do right and then

at the end we'll just return

counts

cool let's go ahead and run that and see

what we

get Jing counts for 10,000 user IDs

Counts from selected IDs 0 0 has 31 f F

has 27 DD has 37 okay and if I look down

here it looks like the IDS are being

generated

randomly cool so let's go ahead and

submit it because this feels

right cool we're good to go this next

section is about a piece or an excerpt

from the effective go book um that is a

book that i' highly recommend reading um

some of the stuff's a bit outdated

they've made the decision not to

continuously update effective go but it

is an open-source book you can go read

the whole thing for free um and the link

is right there so go check that out if

you're interested um that said you don't

need to I'll be talking through um the

parts that we care about here so Maps

can have at most blank values associated

with the same key the answers are one

any number of three and two well maps

are associative right they map a single

key to a single value and you can't have

duplicates of the same key in a map that

wouldn't make any sense right then when

you put in a key you would maybe get

back a slice like that doesn't quite

work so the answer is Maps can have at

most one value associated with the same

key the next question says attempting to

get a value from a map where the key

does not exist Returns the closest Value

panics or Returns the zero value um

that's covered here in the section on

missing keys but basically to summarize

if you attempt to get a I mean we

actually covered this in the last um the

last coding assignment but if you

attempt to access a key in a map where

the key doesn't exist you'll just get

back the zero value so for example if

it's a map of strings to integers and

you access a string that doesn't exist

you'll get back as the value zero and

that's kind of nice just because

accessing values in a map is a safe

operation your code will not will not

panic so to answer the question it

Returns the zero value and it's also

worth pointing out really quickly that

if the map doesn't exist so not that the

key that you're trying to access doesn't

exist but if the map itself doesn't

exist if it's a nil map then your code

will Panic so that is a dangerous

operation you want to make sure you're

always accessing values in maps that

have been initialized the next question

is a function can mutate the values

stored in a map and those changes blank

the colar affect or do not affect the

collar now the answer to this one is in

this first section that Maps like slices

are references so when we pass a map

into a function that function can change

what's in the map and those changes will

be visible outside of the function this

is different from Primitives right

strings integers um booleans those are

all passed into functions by value if

you mutate them within a function uh the

the the CER of that function will not

see those changes unless you return

those values but the same does not hold

true for slices and maps so to answer

the question uh a function can mutate

the values uh stored in a map and those

changes they do affect the CER the next

question says what does the second

return value from a retrieve operation

in a map indicate so let's take a look

at this code example here so we've got

this time zone map where we're accessing

the map at a given a given key and it

can return two values the first value is

the value associated with the key and

the second value is a Boolean right we

used this in the last coding assignment

so a Boolean that indicates whether the

value at the key is a nil value nope

that's not accurate a Boolean that

indicates whether the key exists that's

the

one let's practice with some nested Maps

so like we talked about earlier Maps can

contain other Maps as their values not

as not as their keys right so let's jump

into the assignment says because texo is

a glorified customer database right I

mean we're sending sms and email

messages to a giant list of customers or

basically just a big customer database

um we have a lot of internal Logic for

sorting and dealing with customer names

complete the get name counts function it

takes a slice of strings

names and returns a nested map this is

going to be very similar to the last

assignment we did um but this time it's

going to be a nested map where the first

key is all the unique First characters

of the names and the second key is all

of the names themselves so this could be

useful if for some reason we wanted to

get access to all of the names that

start with a very quickly so to kind of

visualize this we've got this example if

the input names slice is this slice here

Billy Billy Bob Joe it would create the

following nested map so the first key is

just a

letter the second key is the full name

and then the value is um the number of

times that name showed up in the

original list and then it's worth

pointing out here that the return value

is a map of runes to a map of strings

and integers in go we often just

represent individual characters as runes

rather than strings of length one it

just gives us a little more um kind of

assurity in our type system okay so

let's start by creating a new top level

map so we'll call it counts and we'll

make that full map now it's important to

understand because this map contains

Maps inside of it we we will need to

continuously initialize new maps I'll

show you what that looks like so now

let's just uh loop over all these names

so

for um we don't care about the index

name and range

names Okay so we've got a name the first

thing we need to do is actually check

and see if we already have a map

associated with the first character of

this name so let's get that first

character let's do um if we probably

need to do some safety checking so like

if length of

name actually the easiest thing to do

would just be if name is the empty

string then we'll

continue we don't care about blank names

they they don't do anything for us right

so we'll just we'll just skip them great

if it's not the empty string then we can

say first character is name zero okay so

that gives us the Rune at

um the first index in the

name and then what we can do is look up

in our map so counts at first oops

counts at first

character um we can see if the inner

map

exists so if it does not exist not if

not

okay let's just keep it simple if it

doesn't exist we'll just initialize it

so if it does not exist we'll say counts

at first

character equals and we'll initialize

the new inner map so we just need a new

map of string to

integer at that first character key

right right in fact to be explicit I'm

going to ignore the inner map

there so by the time we get down here to

line 18 we should be 100% certain that

counts at first character contains an

initialized map so then we can just

simply do counts at first character

at

name

Plus+

right because we've we've made sure that

the inner map exists and if the name key

doesn't exist it will return a zero

which we could then increment and save

back into the map so that should work

just

fine at the end we can return

counts cool hopefully that makes

sense and we've got some test cases down

here Matthew George Drew Philip Bryant

and then a big list okay cool let's run

it and see what

happens whoops cannot use first Char

variable of type bite as Rune

value right so when you you index into a

string right so name is a single string

in go then it is a bite type um but we

want a rune type

so going go ahead and cast

it and run it

again cool uh Jing counts for 50 for the

first 50 names count for M Matthew is

three G George is One D Drew is four we

don't have any pan X so these counts

look totally plausible to me let's go

ahead and submit it it's time to talk

about first class and higher order

functions which are just really kind of

confusing complex terms for a much

simpler idea which is functions as data

a programming language is said to

support first class functions if it

allows you to pass around functions just

like you pass around any other variable

storing essentially an entire function

at as a value and then a function that

uses that first class function so a

function that accepts another function

as a parameter or returns a function as

a return value is said to be called a

higher order function let's take a look

at a concrete example okay so here we

have two functions add and multiply um

these are very simple functions you

should be able to understand uh what

they do just by looking at them for a

second um but here we have kind of an

interesting function it's called

Aggregate and it takes as input three

integers a b and c and it takes as input

an entire function right so it takes a

function and we're calling it here

arithmetic it's the fourth parameter to

the aggregate function and this function

has a specific signature this function

arithmetic must take as its parameters

two

integers right and return return an

integer itself and then the aggregate

function just returns an integer so what

does the aggregate function do well it

calls the function it was given Twice

first it calls it once with A and B and

then it calls it again with the results

of A and B and C so for example if we

call aggregate with the numbers 2 3 4

and the function add then it will add

all three of those numbers together

right which would in this case print n

and then we can also use that same

aggregate function with the same numbers

2 3 and four but this time pass in that

multiply function and here we'll get 24

right because we're multiplying um all

of the variables together instead of

adding them it's okay if this is a bit

confusing uh if this is the first time

you've worked with functions as data

take a second to really kind of stare at

this code and and figure out these this

crazy function signature um it's

actually not that complex once you kind

of get past the scary syntax um but but

don't feel bad if you have to pause the

video and take a good look let's get our

hands dirty with this assignment says

texo is launching a new email messaging

product

maleo I guess uh SMS and email right um

fix the compile time bug in the get

formatted messages function the function

body is correct but the function

signature is not okay so this formatter

function here looks like it will be a

problem let's go ahead and run the code

and see what kind of an error we get so

this is a compile time error uh saying

we have a syntax problem and that makes

sense because here we're we're basically

saying well the formatter input is a

function but we're not saying what type

of function it is and that doesn't work

because get formatted messages is going

to use the formatter function so it

needs to know essentially what

parameters it takes as input and what

it's going to return right uh kind of

like uh the arithmetic function here

takes two integers and returns an

integer uh we need to update this

function signature to kind of inform the

get formatted messages function what

this formatter function actually does so

if we look at the code because we know

the function body um is correct it looks

like formatter accepts a messages input

which is a

string and it's going to return whatever

should be appended to this formatted

messages slice which is a string so it

it looks like it takes one string as

input and and returns one string as

output that kind of makes sense for a

formatter function um so we say takes a

string and it returns a

string let's go ahead and run that and

see what we get cool at least it

compiled says thanks for getting back to

me which return thanks for getting back

to me kind

regards Okay cool so the ad signature

ads kinds to the end and add greeting

thanks for getting back to me hello

thanks for getting back to me cool let's

go ahead and run

that awesome so this might seem like an

exercise in complexity right like why do

I need to pass around functions as data

that just seems to add a bunch of well

needless complexity and for the most

part you're right you really should only

use higher order and first class

functions if you have a very good reason

to do so so the question is kind of what

are the good reasons to do so well first

class and higher order functions are

very often used for um on the back end

side of the stack HTTP handlers right so

if you have some front-end code that

needs to reach out to a backend server

and get some data those handlers are

typically first class or higher order

functions because we need some code

right the Handler function to run like

in the future we don't want to call it

now right we want to call it when

something happens in the UI World kind

of on the on the front end side of the

stack uh they're often used in onclick

handlers right so I write a function and

I don't necessarily call it when my

program starts but I call it when

something interesting happens like the

user clicks a button right when a button

click happens I want to call you know

this function and so typically in code

we can represent that with a higher

order function we say onclick do this

and then we kind of give it the name of

a function to call and then just to

review the definitions uh very quickly a

first class function is a function that

is kind of being passed around as data

and a higher order function is the

function that's using that first class

function right it's a function that

accepts a function as input or returns

it um as one of its return values so the

question is what is a higher order

function um it is a function that takes

another function as an argument or or

returns a function um but it's not a

function that is first in the call stack

or a function with Superior

logic so the next question is what is a

first class function um it is a function

that is treated like any other variable

right it's a function that we're going

to pass around as as data to probably be

called sometime in the future function

currying is kind of like a special kind

of higher order function it's a function

that accepts another function as input

we're kind of familiar with that idea

but that also returns a new function as

its output so it's kind of a way of like

enhancing a function with new Behavior

it's kind of a weird concept to think

about abstractly so let's jump into this

example okay so here we have a function

called self math and self math is the

curried function it takes a math

function as input that accepts two

integers and returns an integer and it

returns a new function that only takes a

single integer as input and returns an

integer and then what it does again it

returns a function right that takes a

single integer an input and returns an

integer and it calls the math function

that it was given with the same input

twice right so we're kind of mapping a

function that accepts two uh different

integers into a function that kind of

forces both of those integers to be the

same integer so like what does that do

in practice well basically we can use

our self math function to convert a

multiply function into a square function

right so multiply takes X and Y and

multiplies them together this new Square

function that we created dynamically

only takes a single value and multiplies

it by itself right um same with the add

function we can kind of use the self

maath function to convert it into a

function that just doubles its input

right so we Square Five we get 25 we

double five and we get 10 so when would

currying be used in the real world uh to

be honest I don't use it very often um

but in backend server land I do

sometimes use it for middleware

functions so a middleware function is a

function that basically changes the HTTP

Handler of a backend server um and just

as a spoiler we will be covering this in

the project at the end of this course um

but it's for kind of injecting some

additional logic into a function so say

we have an HTTP Handler that accepts as

input a user ID and returns an entire

user object with you know say their

first name their last name that sort of

thing

um a middleware function might do

something like require an authentication

token right so we can write all of our

HTTP handlers that serve different data

sort of independently and then we can

use a curried function to kind of

require authentication Logic on all of

our HTTP handlers um in fact in go

currying is very often used to handle

the sort of middleware problem now if

all of that went straight over your head

again that's okay it's kind of hard to

talk about um something that we're not

working on at the moment so again we're

going to cover middleware and HTTP

handlers in the project at the end of

this course so stick around for that so

jumping into the assignment it says the

maleo API needs a very robust error

logging system so we can see when things

are going arai in the back end we need a

function that can create a custom logger

a function that prints to the console

given a specific formatter Okay cool so

this function get logger should return a

logger which is a function right it's a

function that takes two strings as input

and apparently prints them because it

doesn't return anything right and get

logger takes as input a formatter which

accepts two strings as input and returns

a single

string okay so it says complete the get

logger function it should return a new

function um the inputs should be passed

into the format or function the order

they given to the loger function okay

so let's start writing this so we're

going to return a

function that takes two strings as input

right and I'm going to reference up here

for the syntax we're interested in so

I'm going to do a

string B string all right and this

function should return nothing so we can

just go straight into the

body and it

says this function prints the formatted

inputs so formatter returns a single

string so we can just do fmt do print

line and we're going to need to oh we

already have fmt imported perfect so we

need to print the result of the

formatter functions it's going to be

formatter and we'll pass into the format

A and

B right so we're returning a new

function a logger that accepts two

inputs formats them given the formatter

that we were given right and then just

prints it to the console cool let's go

ahead and run

that error on database server out of

memory error on database server CPU is

pegged this all looks good let's see how

the test site actually

works it looks like these are the

formatters colon delimit and comma

delimit and if you take a look at our

messages some are delimited by a colon

some are delimited by a

comma so that's how that is working very

cool all right I'm going to go ahead and

submit that I think this is

correct time to talk about the defer

keyword uh this is a really kind of

unique thing to go um if you're familiar

with any other programming languages

it's unlikely um that you're familiar

with something similar to the defer

keyword um at least I've never used it

or used a concept uh that is similar to

the defer keyword in another language um

fairly go specific

okay so the defer keyword allows us to

execute some function at the end of the

current function or when the current

function exits the defer keyword is very

often used as sort of a cleanup step um

for example in this in this function

here copy

file we open a source file from the file

system and then we defer closing the

file right so every time you open access

to a file in the file system you need to

remember to close that file otherwise

you're sort of wasting Computer

Resources um the problem is closing the

file at the end of the function is a

little tedious because we have multiple

return statements here so we'd kind of

have to close it before both of them if

that makes sense by using the defer

keyword we can just tell the go

programming language hey I want to call

source.

close right before the copy file

function ends and just defers it kind of

until the end and it will only call it

once um no matter where the function

actually returns from on to the

assignment it says there is a bug in the

log and delete function fix it let me

expand this a little bit so we can see

it this function should always delete

the user from the users map Okay cool so

we're given a user's map we're given a

name and we know that Maps uh are passed

by reference so if we delete a map uh it

will be deleted in the callers code as

well um it should return log string that

indicates to the caller some information

about the user's deletion okay so delete

should always happen and then the kind

of the appropriate log message should be

returned from the function that makes

sense um but it looks like there's a bug

okay so let's go ahead and run the code

and see what we

get so initial users Brianna Elon John

Cade attempting to delete John deleting

Santa deleting

Cade okay so John's still there the

problem is that we're trying to delete

JN but Jon's not actually getting

deleted right so we need to fix that

bug and if we take a look John is an

admin and here we are returning log

admin but we're not deleting admins so

so that's that's the real problem right

the users should always be

deleted now here's the problem we can do

this um this will work if I run this my

guess is this should fix the bug yep JN

is no longer there he was deleted

successfully but this is kind of gross

right we we're calling delete three

different times um what if in the future

we add another case and we forget we

forget to add the delete again we'll

have another bug um well what we could

do what we could do is just delete at

the top

once

right but the problem is if we do

that we delete the user from the users

map too soon and now this okay variable

that's checking for existence so it can

change which log is returned like that

logic won't work it will just always be

not okay so we'll always just return log

not found so that's a problem what we

can do is defer the deletion so this

code says we'll call this delete

function right before login delete

returns so it it's almost like um the

equivalent of you know adding this at

every step of the way so let's go ahead

and run that make sure it

works John's there John's gone perfect

and we have different logs getting

returned so that looks good I'm going to

go ahead and submit that this chapter is

not called Advanced functions uh for no

reason let's talk about closures

closures are um I don't want to like

intimidate you and say they're really

hard but they're a little weird so let's

let's take a second to understand uh how

they work okay a closure is a function

that references variables from outside

its own function body the function May

access and assign to the referenced

variables so in this example the concat

function returns a function that has a

reference to the enclosed doc value okay

so concat is a function it returns a new

function right and that's what's

happening

here and it's enclosed using this doc

string within the function so it's

getting initialized outside of the

function and then getting used within

the function and what happens is

basically when we call concat to to make

this new like concat

function we're saving a reference to

this doc variable so every kind of

concurrent not concurrent every uh

subsequent call to this function that is

returned we'll keep adding on right plus

equals word we'll keep adding on to the

same doc variable so let's look at what

that uh kind of looks like in usage so

we're calling concat and we're getting

back this Harry Potter aggregator right

that's what we're assigning this

function we're assigning this function

into this variable so Harry Potter

aggregator is a function right it's it's

specifically it's this function right

here cool and then we're going to call

it with mis and then we'll call it again

with and and Mrs dersley Right we're

calling it over and over and over and

what's happening under the hood is we

are appending those words Mr and Mrs

onto that doc variable so at the end

when we finally

print what's being returned which is the

doc variable itself we get the full

sentence Mr and Mrs Durley of number

four privet drive now closures are one

of those Advanced things that you to be

honest again don't usually use in

production code maybe every once in a

while um but they're very important to

understand because it is very common to

have kind of bugs surrounding closures

so if you don't understand what's going

on under the hood it can be really hard

to debug kind of complex code that might

even be using closures by accident so

the assignment says keeping track of how

many emails we send is Mission critical

at maleo complete the adder function

it's return a function that adds its

input an integer to an enclosed sum

value and then Returns the new sum in

other words it keeps a running total of

the sum variable uh within a closure

Okay cool so it's going to be very

similar to this right so we'll start by

creating a sum value so sum colon equals

zero right we're we're working with

integers not flows and then we need to

return a function with the signature so

return Funk X int returns an

INT oh not not returns an X returns an

INT and then here we need to add X to

sum right so sum plus equals

X and then we need to

return the new

sum right and then if we go take a look

at this test case let's

see okay so we're adding these email

bills with a bunch of different

numbers the test Ates over the bills ah

okay so we're creating two adders here

so we're creating a count adder and a

cost

adder and then let me expand

this going to just make that basically

full

screen so the test actually creates two

different adders two different instances

of our Adder function right and one of

them is going to count how many bills

there are and the other one will keep a

running total of the cost of all of the

builds

right so we're actually using our

function twice for two different things

and they'll each have their own enclosed

some count that they keep track of

differently right the count will have

its own the cost will have its own the

count is simple it just adds one every

time the cost will add the actual cost

in pennies cool let's go ahead and run

this so um and these values are getting

interpolated into this message so youve

sent one email cost 45 cents two emails

77 cents three emails 120 cents so like

all of these are going up that makes

sense I mean we could even go verify

right 45 + 32 77 that looks right to me

let's go ahead and submit it all right

we're on to a little quiz about closures

can a closure mutate a variable outside

of its body uh yes that's basically the

entire point of a closure another little

review question here says when a

variable is enclosed in a closure the

enclosing function has access to blank a

copy of the value or a mutable reference

to the original value well if it was a

copy then our sum never would have

worked right because we'd be working

with a new copy of the sum variable

every time so it's actually a mutable

reference to the original value we've

already been using Anonymous functions

kind of all throughout this chapter um

now let's kind of just talk about what

they are so Anonymous functions are

exactly what they sound like they're

just functions that do not have a name

they have no name um Anonymous functions

are really useful when you're kind of

just oneoff maybe creating a closure

you're returning a new type of function

um if if you're not defining the

function for like use across the entire

program but you're more using it as a

value using it as a first class function

um that's when you're going to see

Anonymous functions use the most so as

an example um here we have an anonymous

function declaration right we're

creating a new function we're defining

its internal logic it's its function

body um but we're not giving it a name

right there's no name uh for this

function that we're passing into do math

it is an anonymous function the

assignment says complete the print

reports function call Print cost report

once for each message okay let's take a

look print cost report looks like it

takes as input a function cost

calculator great okay um call Print cost

report once for each message pass an

anonymous function as the cost

calculator that returns an int equal to

twice the length of the input message

okay let's go ahead and do that

so um it says to do it once for each

message yeah so

four

message range

messages call Print cost report print

cost

report and print cost report takes a

cost calculator which is a function that

takes us string and returns an

INT said to use an anonymous function

right so funks we need to actually

Define our X string int we need to

define the body um that returns an INT

equal to twice the length of the input

message so X is a string in fact I'm

going to name this um message and we'll

return the length of

message time

2 right twice the length of the input

message and then print cost report takes

us second parameter which is the message

itself

right I think am I am I reading this

correctly cost report FES the calculator

and the message itself yep because it's

going to it's then going to call the

cost calculator and then and then print

kind of a little report okay cool um

that's looking pretty good to me we

don't return anything from print reports

okay let's go ahead and run this

so message here's Johnny cost 28 cents

go ahead make my day 42 cents you had me

at hello 38 cents that's looking correct

right there's

19

28 not 19 what's half of 28 14 14

characters there looks good to me okay

let's go ahead and submit

that let's talk about pointers and in

order to understand pointers we need to

um talk a little bit about Ram or memory

right Random Access memory which is

basically the part of the hardware in

our computer that stores data right

because pointers and variables are all

about kind of how we store data in the

memory of our computer let's start with

something

simple let's create a new variable in

our

program and let's call it X and we'll

set x equal to

5 under the hood what happens

automatically when we create a new

variable uh and set it equal to five is

somewhere in our computer's memory that

variable's value is going to get stored

so let's say uh for the sake of the

example that it's stored here in memory

address 169 Now Memory in your computer

you could think of it as fairly simply a

memory address that stores a value so

we've got kind of you know millions of

different memory addresses in which we

can store data and somewhere in memory

uh that value needs to live so let's

just say it gets assigned again automat

aut atically um to address 169 great now

what happens if I create a new variable

let's call it Y and set it equal to the

current value of

x y actually gets a new copy of the

value so X lives here at address 169 y

let's just say is going to live at

address 170 and we get a copy of that

five so down here in this table this is

where we're going to keep track of all

of our variables we'll say that X so X

is the variable name lives at address

169 and it stores the value

five now

y lives at address

170 and stores also the value five at

its most basic a pointer is just a

variable that stores a memory address so

let's say for example that we create a

new variable called

Z and we set it to point which is uh

which uses the Ampersand I can't draw an

ampersand pretend that that's an

ampersand uh the the the a reference to

X right it points to x what that does is

that we're creating a new variable

called

Z it's going to get a new address

anytime we create a new variable it's

going to live in a new address in memory

let's say it lives at address

171 but its value instead of being five

instead of being a copy of X because we

used kind of the pointer syntax the

reference

syntax the value is going to be the

address of

X so we're going to

store 169 which is the again the address

of X as the value and Z is going to be a

pointer type so kind of the way the go

programming language works works is it

knows that Z is effectively pointing to

the value five right because its address

is

171 which stores a pointer to 169 so we

can look up the value five at address

169 so what this means is if we update

the value that Z points to under the

hood we're updating X so we can do

things like pass pointers into functions

change the underlying value and the

value outside of that function is also

changed which again in a language like

go doesn't happen normally because

typically if you pass a variable like X

into a function and then change it those

changes are not seen outside of the

function you would need to return the

updated value and then assign it into a

new variable so pointers basically allow

us to change the value of something from

within a function right from within a

different scope let me show you what

that looks like in a quick example so

remember that Z stores the value

169 which points to this

address which stores the value

five so if we want to update the value

of x without having access to the

original variable x what we can do is

use the dfference operator which is an

asterisk we can dreference Z now this

dfference operator essentially follows

this chain and finds the value right and

we reassign into it let's say the value

six so this becomes six and this

location and memory is updated now to

hold the value six so we've updated the

value of x without even without even

using right the name X so now that we've

kind of covered what a pointer is let's

look at just a little bit more of the

syntax in code so the type of a pointer

is not the type of the underlying value

alone so if I want a pointer to an

integer um I actually have to use this

syntax here I'm creating a new variable

called p and it's being initialized as a

pointer to an integer so a pointer is a

specific type in go now to be fair um

it's not super common that you're

creating blank pointers and the zero

value for a pointer is nil um more often

than not what you're going to do is have

a concrete value like this my string

hello and then you'll create a pointer

to that value by using the Ampersand

like we talked about so in this case the

type of my string is string and the type

of my string pointer is a pointer to a

string which would be syntactically star

string there kind of two primary reasons

that you would use a pointer in the go

programming language the first is the

more common reason which is you want to

be able to pass a value into a function

and change the value and have those

changes kind of persist outside of the

function right because normally when you

pass a value into a function a copy is

passed in so if you want to pass in sort

of the original value so it can be

changed and updated uh you might use a

pointer the second reason is if you're

very concerned about the performance of

your program every time you create a

copy of a variable in memory you have to

copy that variable in memory right which

takes some time so if you're dealing

with lots and lots of data and you're

trying to be very performant you can

make micro optimizations and kind of use

pointers under the hood if you want to

avoid all of that memory copying now I

will say that you usually won't want to

do this upfront because pointers are

dangerous and they can lead to bugs if

not used properly so generally speaking

I would recommend against making those

performance optimizations unless you

really need them let's jump into the

assignment says fix the bug in the send

message function it's supposed to print

a nicely formatted message to the

console containing an sms's uh recipient

and message body however it's not

working as expected okay so let's run

the

code and we get these kind of weird

weird looking values that are getting

printed here in the two and the message

Fields now this is heximal it's not

binary it's not decimal it's hexadecimal

and this is the default formatting for a

memory address so we have these amp

perents here they're creating pointers

to the underlying values that's not what

we want it's not what we want here right

that's why this looks disgusting uh we

need to dreference or or sorry we need

to remove the reference so I guess D

reference

um we need to remove the amperian so

that we are no longer creating pointers

so run it again and we get the values

themselves which is what what we've been

asked to do

let's recap some syntax sometimes it can

get a little confusing between the

asterisk and the Ampersand what each of

them mean and in what context so when

we're talking about the type of a

variable in go a Pointer's type is star

and then you know the type of the

underlying value so a pointer to an INT

is star int an ampersand is used to

reference a value so if we want to

create a pointer to the my string

variable or the my string value then we

use an ampersand so the Ampersand

followed by the name of a variable

creates a pointer to that variable now

here's where it can get just a little

bit tricky the asterisk is again used to

dreference a pointer so the asterisk is

used in a Pointer's type it's also used

as an operator to dreference a pointer

so when we say say asterisk my string

pointer this refers to the underlying

value so we can actually change the

underlying value Say by assigning it to

in this case a new string so in short

ampersands to create new references or

new pointers to a value and the asterisk

is used to dreference a pointer and get

back at that underlying value let's hop

into the assignment it says complete the

remove profanity function it should use

the strings. replace all function so

this is a a built-in uh function in the

standard library in the strings package

uh to replace all instances of the

following words in the input message

with asterisks it should mutate the

value in the pointer and return nothing

do not alter the function signature Okay

cool so remove profanity takes as input

a a a a message variable which is a

pointer to a string so because it's a

pointer we're going to be able to mutate

it without returning anything explicitly

okay let's jump into it so first thing

we're going to do is dreference

the message pointer and store its value

in a new variable called message value

and then we'll just update

this um by using that strings. replace

all functions strings. replace

all we want to replace the values in

message value we want to or I should say

we want to replace subrings from message

value uh we'll look for the word dang

and we'll replace it with four

asterisks and we want to do the same

thing twice more with shoot which has

five letters so let's add an asterisk

and heck which has four so that should

be good cool let's let's run this I need

to import the strings package before I

forget and see what happens

so in its current state we actually did

not update anything right shoot is still

there dang is still there that's because

we actually need

to point the

message pointer to a string back at the

updated value so we can do dereferenced

message

equals message value let's run

that perfect let's submit it

now we've got a pointer quiz so the

question is what is the value of

Ampersand y after the code on the left

executes so we've got X set to 50 Y is a

pointer to an

integer okay well in this case it's just

going to be 100 because we're explicitly

setting it to 100 on the last line of

the code so that one was pretty easy now

this question is a little trickier says

what is the value of x after the code on

the left executes

well X is set to

50 Y is a pointer to X and then we

dreference y instead of equal to 100 so

that's actually also going to be 100

because we're setting X through Y which

is a pointer to X I mentioned earlier

that pointers can be dangerous and that

is definitely the case um if a pointer

points to nothing then its zero value is

nil right so this is the same for

interfaces or errors right in go fairly

often you'll be checking at runtime if a

value is nil or not and the thing about

pointers is if you ever try to

dreference a pointer that doesn't point

to anything your code will Panic so

pretty much any time you dreference

something you should be checking before

you dreference it to make sure that the

pointer actually points to a valid

location in memory so this assignment

says let's make our Prof profanity

Checker safe update the remove profanity

function If the message is nil return

early to avoid a panic okay so let me

run it in its current state and you'll

see we get this nasty Panic here it says

invalid memory address or

nil okay so what we need to do here is

if

message equals equals

nil return nothing right if we've been

given an invalid input we'll just bail

early um another way to do this um if

the assignment expected something

different we could return an error here

right we might do something like return

errors. new uh invalid input I think

that would also be a good way to write

this function uh but we've been asked to

just do a naked return so we will do

that let's submit it so let's talk about

how pointers are used in conjunction

with methods so you'll very frequently

see that methods actually take a pointer

receip

rather than a non-pointer receiver and

typically that's done because the method

will be making changes to the instance

of the type itself in this case a struct

right so we have this car with a color

field and the set color method on the

car is going to change the color right

and so here if we create a new car we

set the color to blue and then print it

you can see it's been updated to Blue

instead of white now contrast that with

a non-pointer receiver

this acts like a normal function right

we don't have a pointer so we don't have

a reference to the location in memory so

if we update the cars color to Blue it

actually just stays white it doesn't

persist that change so that's why I say

that it's uh more common that you'll see

pointer receivers on methods than

non-pointer receivers but but you will

definitely see both so uh the question

is which is more widely used in go and

the answer is pointer receivers now when

it comes to pointer to receivers one

thing that's important to understand

from like a syntactic point of view is

that even though the uh the input on the

left hand side right the receiver is a

pointer when you actually call the

method you can call in this case right

the grow method you can actually call it

on just a normal value or a pointer it

will sort of cast the value under the

hood to a pointer if it isn't one

already right so C in this case is just

a circle it's not a pointer to a circle

but when we call c. grow the pointer to

the circle is passed into the method so

we didn't need to kind of explicitly you

know cast c to a pointer to a circle by

you know adding an Amper sand right here

okay so with that understood um let's

move on to the assignment so the

assignment says fix the bug and the

codes that set message sets the message

field of the given email structure and

the new value persists outside the scope

of the set message method Okay so we've

got this email struct we've got the set

message uh

the set message method if I run the code

in its current

state we've got before message this my

first draft Sandra Bullock after looks

identical right and if we go and take a

look at the test Suite then we can

see

that set message is being called this is

my second draft so we would have

expected this message to say this is my

second draft instead of this is my my

first draft the reason it's not

happening is because this function

essentially doesn't do anything this

method does nothing because this is not

a pointer to an email let's go ahead and

run that

again first draft second draft perfect

let's submit

that everything we've done up to this

point in the course has been in the

browser we've been writing code right in

our text editor on boot Dev now we're

going to break out of that environment

and do some local development on our own

machine we're going to figure out how to

use the go tool chain to build real

production go

programs but before we do that let's

talk a little bit about packages we need

to understand packages in order to build

our own go programs now you've probably

noticed that up until this point in the

course every coding assignment has had

the words package main at the top of the

file that just means that we've been

writing code within the main

package and that's actually really

important the main package is a special

type of package it's a package that runs

as a standalone program so anytime

you're writing an actual application

that you need to run say on the command

line or as a server you'll be writing

code within the main package a package

with any other name so any name besides

main is a library package and basically

what that means is it's imported by

other libraries and application code so

some oftentimes it's just imported by a

main package so that it can use it if

you're familiar with npm from JavaScript

or pip from python that's effectively

what a non-main package is in go it's

just some code that you can publish as

kind of a standalone library that then

other developers can use in their main

packages in their actual applications so

let's take a look at an example here so

you're probably familiar with this style

of code it's what we've been writing uh

all throughout this course we've been

writing within the main package because

we've been writing executable scripts

right code that actually runs and does

something and then we have this import

statement where we've typically just

been importing from the standard library

but the standard library is made up of

Library packages right like the fmt

package or the math SL random package

the interesting thing about the main

package is it always has a main function

and that main function serves as the

entry point to the program so packages

that are not main packages their Library

packages will just export functions

named functions to be used Again by

other libraries and application code

only main packages will have a main

function that runs when the program

starts so to jump into the coding

assignment it just says fix the bug in

the code so let's go ahead and run the

code and see what happens

nothing happens right we're stuck in

this infinite Loop apparently apparently

this code compiles and then does nothing

it's kind of a weird Behavior right um

in order to fix this all we need to do

is update

this to be a main package so that we get

as output for our code a runnable

executable a script that we can actually

execute in the browser so let's go ahead

and run that and we get starting maleo

server stopping maleo server kind of as

we would expect uh based on uh based on

this code here so I'm going to go ahead

and submit that so we're familiar with

main packages but what about Library

packages well by convention a package's

name is the same as the last element of

its import path so for example the math

Rand or math SL Rand package from the

ghost standard Library um has files that

begin with package Rand so the Rand

package lives at math SL Rand now it's

important to point out that the standard

Library actually has another Rand

package at crypto Rand so they're both

kind of the Rand package but they have

different import paths when a package

isn't part of the standard Library when

for example you make your own Library

package the import path is typically the

same as the remote URL that you you'd

use to go look at that library's source

code so for example in our fictitious

maleo products right part of the textio

conglomerate of messaging products uh

they might have their own GitHub

namespace it's slmo so github.com is

their GitHub organization and then maybe

they create their own package or their

own excuse me repository on GitHub

called Rand and that's where the

repository for their Rand package lives

that's where the source code lives on

the internet right github.com

Rand now that package's name by

convention should be Rand because that's

the last section of the import path but

that's just a convention they could if

they wanted to change the name of the

package to say random and then all of

the files in their source code would say

package random now again it is possible

to use a different package name one

that's not the same as the last section

of the import path but I highly

discourage it um it is best practice to

just use the convention and keep

everything consistent now one last thing

to point out here is that in go packages

live at the directory level rather than

the file level so if you're used to say

python or JavaScript you might be used

to importing code directly from other

files in go if all of the code lives

within the same directory then it's part

of the same package and you don't need

to Import and Export code between files

in the same package or in the same

directory so in go you would only need

to import code if it lives in a

different directory or a different

package and packages and directories are

one and the same you can't have multiple

packages in the same directory so the

quiz question for this section is what

would be the conventional package name

of a package with the path github.com

waglan parser and the answer is going to

be parer because it should match the

last section of the import path the next

question on the topic of package naming

is given the import path of path to Rand

path2 Rand which of these is a valid

package name so notice it's not asking

which is a conventional it's asking

which one is actually valid we've got

random Rand spam any of these path well

Rand would be the conventional name but

actually any of these could technically

be used okay it's time to write some go

code on our local machines and you're

going to need three things in order to

make it through the rest of this chapter

the first thing is you're going to need

an editor I'll be using VSS code

throughout the rest of this chapter to

do all of our local development stuff

you can use vs code or you can use

something else uh that you're more

familiar with if you do use vs code

you'll probably want to install the

official goang plug-in the next thing

you'll need is a Unix like or sh like

terminal so if you're on Mac or Linux

then the built-in terminal will work

just fine if you're on Windows you have

a few different options personally I

would recommend installing Ubuntu in

wsl2 I'll link uh in the description

down below how to do that uh but you

will need to have a terminal in order to

follow along with these instructions if

you choose to use something like the

default Windows command line you're

going to have to change some of the

instructions in the terminal uh to kind

of translate them to your own machine

the last thing you'll need is just to

install the go tool chain on your local

machine and I would recommend one of two

different ways the first is to use uh

the official download page and the

second is to use um the Webby download

script either of them will work and I've

linked them both on this page so you can

go check them out and get go downloaded

now once you've downloaded and installed

go the way you can test to make sure

that everything is working correctly is

type Go version in your terminal if you

get back a valid Go version of at least

version

1.20 which is what I'm using at the time

of recording this video uh then you

should be good to go now I need to point

out at this point that some people get

confused and think this is Go version

1.2 it's not it's Go version 1.20 which

is the same as Go version 1.20 which is

one version greater than go 1.19 or go

1.19 so make sure that you're not on Go

1.2 that would be very very old if

you're having trouble getting go

installed so that you can use it within

your terminal uh the first thing I'll

have you do is definitely to try closing

your shell session and restarting it um

a lot of times that can help just

getting go into your path uh if that

doesn't work then Googling around uh C

can can be one method to kind of try to

figure out what's going on on your

machine it's really hard for me to kind

of predict what issues you might have

especially considering the fact that Mac

OS windows and Linux can all be a little

different but what I will recommend is

that if you are having trouble jump into

the bootd Discord and ask a specific

question about the trouble you're having

and we'll be happy to help you out so

the question for this step really just

to confirm that we installed go

correctly and that we can use it uh asks

what does the Go version command print

and if we check the output we can see it

says Go version go 1.20 so that's the

that's the version of the go tool chain

we have uh Darwin I'm on a Mac so this

is like the core Unix operating system

and then amd64 which is my CPU

architecture so it's going to be this

bottom one so we've talked about

packages and we've talked about how

packages exist basically at the

directory level and go now we need to

talk about modules a module is a bigger

idea than just a package a module is

kind of a releasable collection of go

packages so sometimes it's just a single

package right you have a single package

a single module and you release it um as

one package but other times you might

break that main package up into sub

packages and you'd release all of those

packages together as one go module now a

repository is not a unique idea to go

but it's sort of even greater than just

a module repository or a git repository

is just a collection of code that you

kind of keep in Source control all at

the same level and it can contain one or

more modules though it's actually really

common for a single repository to just

have a single go module with within it

so while one monor repo can have many

different go modules inside of it I

would argue that's not usually the case

typically you'll have one go module

living in one repository that's not a

convention that's just the way I've seen

it more often than not so for the sake

of example let's assume a git repository

that contains a single module and that

means that at the root of the git

repository we'd have a single go dood

file that looks something like this the

first line contains the path prefix for

the entire module so remember a module

can contain multiple packages and every

package in that module its import path

is going to be prefixed with the path of

the entire module uh the next line just

specifies the Go version um and the last

line will specify any dependencies that

this module depends on so to answer the

question what is a go module an

executable main package um no that could

be part of a go module but it's not a go

module

itself a collection of packages that are

released together that is accurate a

file of go code no a module will contain

many many files of go code um or a

library package and again no not

necessarily you could have a module

that's just a single Library package but

a go module can be many more packages

than that or it could be a main package

for example so it's going to be a

collection of packages that are released

together so we need to talk just a

little bit more about these import paths

now if you're familiar with npm from the

JavaScript e ecosystem uh cargo from the

rust ecosystem or pip from the python

ecosystem then you're probably familiar

with the idea of a namespace for a third

party package for example I might make a

package called Left pad publish it up to

npms uh Central repository and now

anyone in the world just knowing my kind

of namespace name uh leftpad can

download use my code as a dependency the

interesting thing about the go ecosystem

is that there is no central location for

thirdparty packages like npmjs.com in

JavaScript land instead the gotool chain

sort of works on top of git and actually

uses the import path as the remote URL

and it looks to that import path for

where it can go download code so more

often than not you'll see modules with

import paths that start with github.com

or gitlab.com because that's where the

code itself is hosted an important

exception to this rule that the import

path is where you go to download the

code is the standard Library you don't

need to download standard Library code

it comes packaged with the go tool chain

so the question is do packages in the

standard Library have a module path

prefix the answer is

no the next question is what is an

import path and I know we've already

talked about this but I to show you a

more concrete example so this is the

github.com

waglan go- rabbitmq GitHub repository so

this is a GitHub repository that I

maintain it's just a little package for

Rabbid mq users a little go client for

Rabbid mq so this is a library module

and a library package it's intended for

other developers to actually import this

code into their applications it's not a

standalone you know main package so

let's take a look at the file structure

at the very root of the repository we

have the go dood file now this is that

kind of simple standard setup where one

git repository happens to have one go

modable or one sort of releasable unit

of code and if we take a peek inside we

can see that the go dood file uh

specifies the import path github.com

waglan go- rabbitmq Q so this matches

the URL of the git repository hosted on

GitHub now here's the interesting thing

this module only has one package that's

exported to the outside world and it

exists here at this top level so you can

see all of these go files consume. Go

consumer options. go they exist at the

top level of the repository so when you

import this package to use it you just

import from this root path because the

root package is what you're importing

there are no sub packages to import here

but let's pretend for a second that we

did want to export another package in

the same go module so we have our top

level go module G rabbit mq and the top

level package that can be accessed at

the same import path as the module let's

say we added another directory we could

call it maybe networks and inside it

would be the networks package if someone

wanted to import that package then they

would take the import path for the

entire module github.com

waglan rabbitmq which points to the root

package like we already talked about and

it would just append another slash

networks onto the end right so the

module path serves as a prefix for any

nested packages so to answer the

original question what is an import path

well it's not an HTTP connection and

it's not a restful server it's a module

path

plus an optional package subdirectory so

we've talked about repositories modules

packages you've got go installed now

let's talk about how you can set up your

local development environment and some

of this stuff isn't going to be

necessary and I'll point that out but I

do want to show you how I've set up my

machine um and you can emulate the way I

do it if you like that style now I need

to mention the go paath if you're

Googling around trying to figure out how

to set up your local development

environment for go you will almost

certainly come across old outdated

articles that talk about the go path in

kind of any version newer than I think

it's 1.13 right so we're on

1.20 now um you can basically forget

about the go path you don't need to

worry about it um you used to have to

put your code in the go path um now the

recommended way is actually to not put

your code in the go path can be a little

confusing but again generally speaking

you can just forget about the go path

and if you find any articles that talk

about it they're probably outdated the

entire idea of go modules is what

replaced the old go path so the question

is do you need to put your code inside

of your go path um the answers are yes

it doesn't matter and no in fact you

shouldn't and actually in fact you

[Music]

shouldn't so I've altered my window

layout um so that's a little bit easier

for you to see what I'm doing I've got

the boot Dev instructions over here on

the left and then I've got vs code over

here on the right with my terminal at

the bottom cool so I'm just here in my

file system I'm not within the go path

I'm just kind of in my personal

workspace um and we'll just follow these

instructions it says create a new

directory and enter it so we'll make

directory hello

go and me just LS show you the new

directory was created and we'll enter

that directory cool now inside of that

new hello go directory I'm going to

create a new go module so we'll do go

mod in it

and I keep all of my code on GitHub so

I'll do github.com

SL my username because that's my

namespace on GitHub so Wags Lane slash

the name of this project which uh we're

just calling hello go cool says go

creating new module um now if I LS I

should see that new go.mod file next

let's go ahead and take a look at that

file so you can see it just created a

new module

github.com wax laneel go with the Go

version and there are no dependencies

yet so there's no other sections to the

go module file so now that we're done

with this step the question is why does

go include a remote URL in module paths

right so this is a remote URL in theory

right when we push this up to GitHub

we'll push it up to this URL um and the

answ are to confuse new Gophers uh to

ensure that developers are using Source

control or to simplify remote

downloading of packages and it is

definitely that last one the next

question on the same step asks what is

Hello go in our case the repository SL

directory name or the module path prefix

and in our case it's actually the name

of the repository so again if we were to

push this up to GitHub um GitHub is the

name of the website where it's hosted

wag Lane is my namespace on GitHub and

hello go would be the name of the

directory that we are in and the name of

the repository up on GitHub

then this next question is just to make

sure that we completed the step properly

what does the first line of go dood

contain and it contains module followed

by the module path now so that VSS code

will work properly with all my syntax

highlighting with the go plugin I'm

actually going to reopen uh vs code to

that same directory the hello go

directory so we'll just be working

within this module uh for a

second and the instructions say inside

of hello go so now I'm inside of this

hello go directory at kind of the top

level of uh my vs code window um it says

create a new file called main.go so

let's go ahead and do

that conventionally the file in the main

package uh that contains the main

function is called main.go uh paste the

following code into your file Okay cool

so we should all be familiar with this

code by now right we've we've probably

written code like this uh I don't know

almost a hundred times by now in the

boot Dev platform next it looks like

we're just going to run the code using

the go tool chains interpreter so gun

main.go

and we get a nice hello world printed to

the console there's sort of two main

ways to run go code locally one is with

the G run command like we just used the

other is to use the go build command

which we'll get into in just a second

and actually in general I prefer the go

build method uh G run is really only

suitable for when you're running uh tiny

little scripts like this one and just to

be clear about the difference G run so

gun main.go runs the go code in the file

that we pass in right in this case

main.go and and that's all it does go

build actually builds a production

executable um which is how you'll use

your go code in the real world so I

typically prefer building that

production executable um just because

it's more accurately reflects how your

code will run in production so the

question on this step is does g run

build a production executable and the

answer is no it just kind of oneoff runs

your code it doesn't build any uh

production ready artifacts now at the

end of this same step we were asked to

execute the go help run command in our

Shelf so go help run um which just

prints out a bunch of help information

on how to use uh the G run command and

the question for the step says uh which

can go run except as arguments if we

scroll to the top so here's where I ran

go help run uh we can see the usage

information and it says run compiles and

runs the named main go package typically

the package is specified as a list of.go

source files from a single directory but

it can also be an import path file

system path or pattern matching a single

known package so which can go run accept

as arguments package names file names um

it actually looks like it can handle

both great now we get to use go build so

you can for the most part just forget

about G run you probably don't need to

use it um all too often so go build

compiles go code into an executable

program so all you need to do is make

sure that you're in the same uh kind of

main package that you want to build so

I'm here in the hell go directory

um I can LS to prove it to you we've got

the main.go file here package main Funk

main all that good stuff uh we'll run go

build we don't even need to pass in

package or file names it just builds uh

the package of the current directory so

as you can see here we have this new

executable binary in our current helloo

directory now if you remember way back

to I think chapter one of this course we

talked about the difference between

interpreted languages and and compiled

languages and one of the amazing things

about go is that we build compiled

executables that we can execute anywhere

so this hello go binary we can now copy

this put it on another machine and run

it without even needing to install the

go tool chain on that machine this is

compiled machine code so we can now run

this hello go program like we would any

other executable /hello go and it prints

hello world now I do want to show you a

little tip here because every time you

update your code let's say I change this

to hello world 2 if I just rerun hello

go it still will just print hello world

and that's because I didn't recompile my

code so a lot of new go developers kind

of forget to recompile their code and

they think they have bugs or their

codee's not doing what they expect you

have to recompile what I'd recommend

doing is just every time you update your

code and want to rerun it uh you should

build a compile and you can just do it

in the same step uh by doing go build

and then double Amper sand do/ the name

of your binary so this basically says

compile my code if that succeeds run the

compiled binary and the question for

this step is what was created after

running go build an executable file

named main an executable file named

hello go or a package named CMD and in

this case it was an executable file

named hello go right we've got it right

there it just kind of defaults to the

name um of the directory the next

question for this step is what happens

when you run /hello go and I actually

changed this to hello world to but if we

do it again after changing the code back

um the options are program panics hello

world is printed or the code compiles um

hello world is printed and it's

important to understand here the reason

we don't say the code compiles is

because at this Steph Helo all we are

doing is running the compiled binary

we're not recompiling the code the next

command in the go tool chain that we're

going to talk about is go install now to

be honest I don't use it a ton but I

still think it's important to understand

because you'll see it around okay so Ure

you're in your hello repo then run go

install so I'm here in the hello

directory and we run go

install and next we navigate out of our

project directory so I'm going to go up

one

level and what it's telling me is go has

installed the hello go program globally

so the go tool chain when we ran go

install basically compiled that code and

then made it globally accessible to our

entire machine so now if I run hello go

notice without the dot slash because I'm

not running a program in my current

directory I'm running now a program

that's in my

path it prints hello world so now I can

use this script that I built anywhere on

my machine which is just super useful um

if you're building kind of scripts for

your own local productivity so the

question for this step is what does go

install do saves local code to the

remote Source control provider installs

dependencies or compiles and installs

the program locally and the answer is

that it compiles and installs the

program locally again you would really

only use this if you're building scripts

for your own personal use on your

machine the next question for this same

step is code must be compiled with go

build before running go install it's

true false now if you were paying

attention you probably noticed the

answer here but we actually ran go

andall

without a binary existing in our current

directory so if I go back into the hello

go directory and run go install you'll

see there's actually no hello go binary

that exists here um and it works just

the same so the codee does not need to

be compiled with go build

first all right so we've created a main

package and a executable program uh now

we're going to build a library package a

custom Library package so uh what we're

supposed to do is create a directory at

the same level as the hello go directory

so I'm in the hell go directory

currently I'm going to go up one level

and let's see so we've got helloo in

here I'm going to make a new directory

called my

strings and then we'll go into my

strings and here we need to initialize a

new go module so I'll do go mod in it

github.com Wags

Lane slash my

strings and that module is created now

to get my VSS code toing all working

properly again I'm going to just

reopen VSS code to that level so we'll

go back and find the

myrings directory and open directly into

that

directory

okay next we create a new file called

myrings Dogo so this is the go dood that

we created with the go mod in nit

command and now we're creating a new

file called myrings Dogo

and we want to paste the following

code okay so package my strings that's

the first thing to notice right this is

not a main package so we won't be able

to build this package as a standalone

executable this package will be kind of

the intention is for us to use it in our

other hello go package the other thing

to notice about this code aside from the

package name is that there is no main

function here again because it's not an

executable program we're just going to

be exporting functions that can be used

in our main package let's talk a little

bit about this reverse function so this

is the only function in the myrings

package at the moment and uh you know

theoretically it reverses a string from

left to right although I haven't tested

it um but the important thing is that we

need to capitalize we need to capitalize

the first letter of the function's name

and that's because in go that's how we

export a function if it were little r

then this function would not be able to

be used outside of this package but we

want to export it because we want to be

able to use it in our main package right

in the helloo directory um and and kind

of import this logic and use it now

we're told to run the go build command

here in this directory and you'll notice

it doesn't actually seem to do anything

there again there was no executable file

that was built because this is not a

main package um but it is worth pointing

out that go build is still a useful

command because it checks for compile

time errors so for example if I uh

create an invalid token here and then

run go build uh we will get compile time

errors so it is um still kind of useful

just to make sure that this code

compiles so the question for the step is

what was the output of the go build

command in the library package um was it

an executable program or was the

compiled package silently saved to the

local build cache well we didn't get an

executable package right uh this is not

a main package so we don't get um a nice

runnable executable instead it is

silently saved to the local build cache

so it can be used later in an actual

executable program and then the next

question is why is the function capital

r reverse instead of lowercase are

reverse and it's lowercase names aren't

exported for external use or

conventionally uppercase names are used

in go the answer is that lowercase names

are not exported so by convention

functions can have either a lowercase

name or an uppercase name and uppercase

names are exported from the package so

this next question is does a package in

a folder named date parser need to also

be called Date parser right does the

package need to be date parser now

you'll notice that we created a

directory called my strings and a

package called my strings and if you

remember back to earlier in this chapter

we talked about how by convention that's

the best way to do it it's not necessary

um but it is it is the convention okay

so now let's use our reverse function

back in the main package in the hello

directory right so it says um modify

helloo main.go so I need to

reopen I'm going to open vs code back

into the hello go

directory it says modify hello Go's

main.go file okay so we'll use

parenthesis here so that we can do some

multip Le

Imports and we'll be using the import

path that matches the module name of our

my strings package so in my case it was

github.com Wags Lane slm

strings and then here we just copy this

code from the instructions and in fact

let me space this out so we can see it

just a little bit better Okay cool so

we've imported the myrings package and

then down in our code we we can use my

strings which is the name of the

package.

reverse to call that exported function

okay now because we've added a

dependency we need to update our go dood

file so edit the hell Go's go.mod file

to contain the

following this is the important part

down

here so we need to

add replace example.com username my

strings with do dotm strings and require

example.com

username myrings version z now I do need

to update this right because I didn't

use example.com I used github.com Wags

Lane now what's going on here right Go's

dependency management is very heavily

based on git and remote URLs so normally

what you would do is take your my

streams my strings package and push it

up to GitHub and then import it from

there and and sort of all of the go

packages in the world that require the

my strings package will point up to that

remote location that remote server what

we are doing here with this replace and

require well specifically the replace is

we're kind of doing a little hack to get

things to work locally without having to

publish to get so we're basically saying

I want you to take this string this

import path right github.com waglan

myrings and don't go look for it out on

the internet instead just resolve it to

this path dot do my strings right and

now because well I should probably get

back into the hello go

directory right do do/

myrings this is the directory containing

the my strings package

right so we're basically just saying

replace this with my local uh file

system we're telling go how to find this

package on our machine so now that we've

made those changes uh we can build and

run this program again so go

build slh

heloo build and run and it looks like

it's working correctly this this

function is supposed to reverse the

string and we get this nasty little

and the question is just asking us what

was printed and that's what we got on

the same step this next question asks

how does the go tool chain know where to

find the imported code npm hosts the

files publicly it downloads it from

Google's servers we use the replace

keyword in the Goot dood to point it to

the relative location of myrings or it

was fetched from GitHub now again I want

to point out that most of the time

you'll be fetching code from GitHub or

gitlab or some remote Source when you're

using thirdparty dependencies in our

case we used this replace keyword uh to

point the go tool chain to the location

of the myrings package on our machine so

we already briefly talked about this but

I just want to reiterate that this

little replace hack is useful for kind

of testing and doing things on our local

machine but it's not suitable for

production generally what you would do

is push up that my strings get repos

repository to GitHub and then import

from there so you will typically not see

replace aliases in production go dood

files very often you'll just see um

packages sort of required vanilla from

their remote location so now we're going

to practice using a remote thirdparty

module says create a new directory in

the same uh Parent Directory as hello

and myrings called Date test so let's go

back up one level and create a new

directory make dur date test and then

I'm going to go ahead and again reopen

vs

code into that

directory okay create a main.go with

this

code we can do

that next initialize a module so we do

to go mod and it and again I'll just use

good

hub.com Wags Lane SL date

test creating new go.mod to add module

requirements and Subs do go mod tidy

okay cool um I'm going to ignore that

for just a second and instead I'm going

to follow the instructions it says

download and install the remote go tiny

date package using go

get Okay so we've used go install in the

past right go install installs an

executable on our machine to be used

anywhere um goget is how we go download

and install third party dependencies so

we're going and grabbing the github.com

waglan slgo tiny time

module and it gets added

automatically to our go.mod you'll see

that it just kind of grabs the latest

version cool um print the contents of

your go onod uh I don't need to run that

because we've got it open here in vs

code um and then compile and run our

program again so let's do that go

build and run and it's going to compile

to a file called Date test right because

that's the name of our

directory cool and as you can see it's

printing out this date here so what did

we do right we used goget to download

code from this remote location which

also happens to be the import path right

because that's how go packages work

typically so let me go grab that and

just show you this

is this is a package that's hosted on

GitHub so the go tool chain actually

went to GitHub and downloaded this code

right added it to the go dood as a

dependency and then created this new

file called go. sum that kind of

contains any uh transient dependencies

or dependencies used by the go tiny time

package that we just imported so kind of

keeps track of everything that we're

using and the question for this one is

how did the go tool chain know where to

download the Go tiny time package oh man

this uh this question is not optimized

for this ridiculously zoomed in view it

says the module import path is used for

remote lookups EG github.com Wags Lane

go timing time um or the go tool chain

has free open source go modules location

memorized uh that is not true it just it

just does a remote lookup right it goes

and fetches that from the remote git URL

and then just to make sure that we did

the step correctly uh it's asking us

what was printed after running the new

date test program can see it right there

it looks like it's this

2020-4 d03 right it's it's this

hardcoded date in RFC 3339 format

so hopefully that last section gave you

a taste of local development at least

showing you how to build and compile

some code on your own machine we'll

obviously be doing a lot more local

development at the end of this video

with the project uh but for now for the

rest of this course we'll be back

working in the boot Dev web interface

cool so we're on to talking about clean

packages and this is kind of just a an

article that I'm not going to bother

reading out loud on screen but I'll talk

about each individual section as the

question questions are asked so the

question is should you export code from

the main package and that's talked about

um down here it's basically simple don't

export code from the main package and if

you think about it it makes sense

there's no reason to capitalize function

names in the main package because no

other packages can import from a main

package a main package is built into its

own Standalone executable it's not a

library so capitalizing functions in the

main package is just kind kind of

confusing because it kind of signals to

developers that you're writing code

that's meant to be imported and it's

not this next question says when should

you not export a function variable or

type now this is an interesting question

I think a lot of newer developers think

well maybe I should just export more

stuff because maybe the users of my

package will find it useful um you

actually want to think in the reverse

you want to export as few things as

possible when you're building Library

packages because anytime you export a

function you now need to support that

function right you can't really take it

away later everyone's code will break

right so you should really think about

what you're exposing to your users as

like the surface area of a shape and you

want to keep that surface area as small

as possible to keep the maintenance

burden down and to make your package

easy to use right the few things that

your users need to know about in order

to effectively use your package the

easier it'll be to use so when should

you not export a function variable or

type um when the end user doesn't need

to know about it hide everything that

they don't need to know about the next

question is should you often change a

packages exported API so API stands for

application programming interface and

basically anytime you export something

from a library package uh you're adding

that thing to the package's API right

it's the interface that other developers

will use to access your package so

should you often change a package's

exported API the answer is that no you

should try to keep changes to your

internal functionality right imagine if

the go programming language uh let's say

the standard Library changed fmt do

print line to fm. print right and just

removed fm. print line that would break

and an immense amount of code right so

you don't want to go about uh publishing

packages that you intend to kind of

update the API for uh very rapidly

stable apis are good apis so should you

often change a package as exported API

no try to keep the changes to internal

functionality yes move fast and break

things or if the package is main then

yes uh the answer is just no try to keep

changes to internal functionality again

if the package is main then it's

irrelevant because you're not building

uh a

library I want to talk about the

difference between concurrent or

parallel programming and synchronous or

sequential programming now it's worth

pointing out at this point that

concurrency and parallelism are

different and we'll talk about their

differences in a future course for for

now we're going to kind of treat them as

the same idea and I'll just kind of

refer to them as concurrency uh

similarly sequential Pro programming and

synchronous they're slightly different

terms but um I'm going to kind of bucket

them for the purpose of this discussion

we'll be really comparing uh concurrent

code to synchronous uh or sequential

code so let's start with the easy one

let's talk about synchronous or

sequential programming say we have some

code x colal 5

x++ and then maybe fmt do print.

print line

X the nice thing about this code and

what makes it synchronous or sequential

is that the code executes in order from

top to bottom right first we create a

variable named X set equal to 5 then we

increment it by one and then we print X

right everything's happening in order

from top to bottom one thing at a time

now this is usually what you want it's

simple it's easy to reason about it's

easy to write code this way the problem

is sometimes it's not the most efficient

way to write performance code or code

that can run as fast as possible on a

given set of Hardware so in order to

understand how we can maybe optimize

this we need to look into how your

computer's

CPU or Central Processing Unit

works so your CPU has a clock speed um

which basically like from a very high

level means how many instructions how

many

instructions it can do per let's say set

those aren't necessarily the units but

it is basically how many computations it

can do um per amount of time we just say

it seconds to keep things simple okay so

when we're analyzing this code over here

on the right basically what needs to

happen is first we set x equal to five

and that takes up one instruction right

after that we get to increment X by six

that'll take up another instruction and

then we get to print X so the speed at

which we can execute this little program

here is dependent on how fast the cpu's

clock speed is so if we want our program

to go faster we can basically do one of

two things either we can reduce the

number of instructions required uh for

our program to execute or we can get a

faster CPU one that can do more

instructions per second the problem is

getting a faster CPU sometimes is really

really expensive and so instead of

getting a faster CPU what we've kind

have done over the years is instead add

more

CPUs and in this case um we've kind of

broken the CPU up actually into what we

call different cores so you might

actually have a quad core processor Each

of which let's say does I don't know

5,000 instructions per Nan I'm totally

making these units up um but you get the

idea any one of these CPU cores can only

do 5,000 but the interest thing is they

can all do 5,000 per nond at the same

time so if we distribute our program

across all of the cores in theory we

should able to go uh we should be able

to go about four times as fast again if

we use all four cores instead of just

one the problem is that most code we

write can't take advantage of all four

cores for example let's look at this

code over here we set x equal to 5 and

then we increment it and then we print

it it has to happen in 1 2

3 right in order 1 2 3 we can't do all

of these instructions at the same time

if we did then x++ would have nothing to

increment because we never would have

set um an X variable equal to five in

the first place and print line X would

have nothing to print because X hasn't

been set yet so writing concurrent or

parallel code can drastically speed up

the performance of our programs because

we're able to distribute um kind of all

the instructions that we need to compute

across multiple cores the problem is we

do actually need to write our code in a

different way we need to expect that

some of the instructions are going to

happen at the same time and that's

what's going to speed up our program so

let's say we had a little bit more code

in our program here maybe we have X or

excuse me y colal

6 y

-- FM

t.

print

line

Y okay this code here in this block kind

of dependent on each other right we have

to do it in one two three order um and

the same goes for this block here but we

don't have to necessarily do this block

of code where we calculate and print X

before or after we calculate and print y

they're they're kind of separate in that

way so what we can actually do is take

this block of code code and execute it

in one core and at the same time execute

this other block of code in another core

doing them at the same time so let's

sort of visualize the runtime of this

program here if we run this code

synchronously or sequentially right not

taking advantage of two CPU cores but

instead of doing it all in one core then

our running time might look something

like this I don't know let's just say 6

nond but instead if we run it across two

cores in

parallel each core executes at the same

time and they'll each take approximately

let's say three

nond so we're done in half the time

again because we took advantage of the

hardware that was available to us so to

wrap up writing concurrent code in many

cases can drastically reduce of how long

it takes to run our programs and it

depends just a little bit on kind of

fundamentally what we're trying to do so

in this case we literally could take a

program and chop its runtime in half by

utilizing a little bit more Hardware so

this chapter is going to be all about

concurrency in the go programm language

and the great thing about go is how easy

it makes it to write concurrent code so

the question is how do we write

concurrent code and go what's the syntax

well there's actually a really awesome

builtin keyword word to the go program

language the go keyword and it spawns a

new go routine when you use it now a go

routine is kind of unique to the go

programming language but at a high level

you can just think of it as a separate

thread of execution we're essentially

telling the go programming language hey

all this stuff in this function right

that I'm calling with the go keyword can

happen in parallel right we can go

execute that on another core of the CPU

if we need to so whenever we use the go

keyword execution kind of immediately

jumps to the next step after the

function call right so this do something

function will kind of go be executed in

parallel right and then execution

continues in the current function um

kind of just on the next line and then

as a last note before we jump into some

code to see how this really works when

we use the go keyword we're not able to

capture any return values from this

function call which makes sense right

because we're kind of moving on we can't

wait for the function to finish and

return some stuff that's the whole point

we want the function to go kind of do

its thing on another thread so let's try

this out in an assignment says emo we

send a lot of network requests right

requests over the Internet each email we

send must go out over the internet to

serve our millions of customers we need

to we need a single go program to be

capable of sending thousands of emails

at once right so we need to be able to

do lots of things things at once this is

what go routines allow us to do edit the

send email function to execute its

Anonymous function concurrently so that

the received message prints after the

sent message so let's go ahead and run

the code in its current

state and we get email received hello

there Stacy email sent hello there Stacy

right so it looks out of order now

here's our send email function it takes

a message um as a string parameter and

the interesting thing is it calls this

Anonymous function here right so it's

defining this function and then

immediately calling it um where it's

going to wait for 250 milliseconds and

then print email received and then this

function will exit and it will print

email sent right and then print the

message so again that's why this is out

of order right we're we're executing

this function first and then we're

moving on to the next line so the way we

fix this is by using the go

keyword to execute this bit of code at

the same time is this bit of code right

the go keyword will immediately move

down to line 13 on the main thread or

the main go routine and spawn a new go

routine to kind of do this in the

background and because of this waiting

time the email received message should

happen afterwards so let's go ahead and

run this again

sent received sent received looks good

to me so you may have been thinking to

yourself well how useful is it to call a

function in a go routine if I can't even

get the return values the answer in go

is that we use channels typically to

kind of resynchronize our code so

typically we'll use go routines or the

go keyword plus some function to go do a

bunch of computation all at the same

time and then we can kind of

resynchronize either in the main go

routine or in some other go routine by

passing data back and forth between go

routines using channels a channel is

really just a thread safe or go routine

safe cue we can put stuff in one end and

read it out the other end in the same

order so we'll typically have one or

more go routines kind of sending data

into the channel maybe they finished a

calculation they're returning their

results over the channel and then we'll

have one or more go routines on the

other end reading that data off of the

channel and processing it in some way

maybe sending a report maybe printing it

to the console so this is the Syntax for

making a channel and channels are typed

so we can say this is a channel of

integers and then we can send data into

the channel using this Arrow operator

it's it's really pretty intuitive we're

saying 69 is being sent into the channel

and then it's actually the same operator

to read a a value out of a channel we

just move it over to the other side

again super intuitive we're reading a

value out of the channel and saving it

into the variable V in this example now

it's important to understand that both

of these operations sending and

receiving on a channel are blocking

operations so if I'm trying to send a

value into a channel and there's no

other go routine on the other side that

will be able to read it out then my code

will actually stop and wait on this go

routine until there is a reader ready

and the same goes for reading when a go

routine gets to this section of code if

there's nothing being sent into the

channel on another go routine then this

code will just sit and wait until

something is sent so let's move on to

the assignment says run the program

you'll see that it Deadlocks and never

exits so a deadlock is basically when

all the go routines in a program are

blocking and there's nothing for them to

do it means there's a bug in the code so

let's run the code just to see what that

feels like although I think it's just

going to feel like it's running the code

for a long time so I'm going to go and

cancel

that the filter old emails function is

trying to send on a channel and there's

no other go routin running that can

accept the value from the channel okay

so let's take a look filter old emails

takes some emails as an input creates an

is old Channel and that looks like it

Loops over the emails and if they are

before a certain date it's going to pass

the Boolean true into the channel

otherwise it's going to pass in false

and then once that Loop exits it's going

to read out of the channel here and

print to the console you know whether or

not the emails uh were old Okay

cool so this makes sense this makes

sense why this is blocking right this

first send either here or here which

everyone happens first is going to block

because the

reader like that code hasn't happened

yet this is the same this is the same go

routine right this is not happening at

the same time as this is happening so

we'll use a go routine to fix it fix the

deadlock by spawning an anonymous go

routine to write to the is old Channel

instead of using the same go routine

that's reading from it okay cool so we

need to run this Loop essentially in a

new go routine so we'll do go Funk and

we'll just use an anonymous function

here because we don't really care about

naming

it and we'll just run that entire block

of code

in a new Anonymous function so now this

and this will happen at the same time

let's go ahead and run

that cool and this looks like what I

would expect I'll go ahead and submit

that so there's this concept of a token

when we're talking about concurrent

programs a a token is basically a unary

value right so not not binary there's

not two possible values true and false

unary there's just one possible value

and when there's just one possible value

we really don't care much about that

value it's not interesting in any way

right so it's not that we care what is

passed when we're working with tokens

it's that we care when and if something

is passed through a Channel at all so

for example this code here is reading a

value out of this Channel and it's just

discarding whatever it reads out it

doesn't even care what it is it's just

waiting to see uh kind of when something

thing comes through the channel so let's

move on to the assignment um and kind of

put that into practice it says our maleo

server isn't able to boot up until it

receives the signal that all of its

databases are online and it learns about

them being online by waiting for tokens

which are just empty structs um on a

channel complete the wait for DBS

function it should block until it

receives numb DBS so this integer here

um tokens on the DB Chan channel right

so this is a channel of empty structs

and again empty structs are tokens

they're unary values um they're not

interesting they don't have any Fields

each time it reads a token the get

databases Channel go routine will print

a message to the console for you okay so

I'm guessing that's down here yeah it

looks like it's going to watch um and

and print here okay so let's get started

and write some

code it should block until it receives

numb DB's tokens so it's a variable

amount of tokens so I guess the easiest

way to do this would be for with a loop

so 4 I col equals

0 I is less than num

DBS I

++ and then in here we're just going to

wait for a token to come across the DB

channel right so it'll block once and

then it'll move on to the next iteration

of the loop block again move on until

we've waited for you know numb DB's

tokens um and then block until it

receives the tokens each time it reads a

token that's it looks like we don't have

to return anything so let's run

that database one is online two is

online this looks good to me so now

let's talk about buffered channels so

the channels we've been using up until

this point haven't really stored

anything in them right we needed a

sender and a receiver at the same time

as soon as the sender sends the receiver

receives there's nothing kind of stored

in the channel at any given time but

that is exactly what a buffered channel

is so we have a buffer of some length

let's say five different items and

senders can actually send into the

channel even when there's no receivers

until the buffer fills up so a sender

could send five things into the channel

and then the buffer is full the channel

is full right and when a receiver

finally goes to read and pop items off

of the other end it will read and pop

them off in order one by one until the

channel is empty so this this is the

syntax we'd use if we want to make a

Channel of integers with a buffer size

of 100 we just use that optional second

parameter um to the built-in make

function so let's move on to the

assignment it says we want to be able to

send emails in batches a writing go

routine we'll take an entire batch of

email messages to a buffer channel uh

we'll write an entire batch of email

messages to a buffer Channel and later

once the channel is full a reading go

routine will go read all of those

messages so we can actually go find

where that's happening here in the test

Suite okay here so send emails um oh

nope this is where they're getting read

I'm sorry ah I'm silly the function that

we'll be working on is what's writing

into the channel so emails to send is

the channel um we're supposed to write

an entire batch of emails into the

channel and then theoretically sometime

in the

future those emails will be read out of

the channel and actually sent off

Okay cool so what happens if I run the

code in its current

state I'm kind of imagining that it's

going to block

forever yeah that's never going to exit

so at emails toq is getting called here

and send emails is getting called here

and notice that they're getting called

on the same they're both running in the

same go routine Right add emails to Q is

there's no go keyword anywhere that I

see so that's why we are blocking here

there's no reader on the other end right

but because we want to do this batching

we actually should be able to do it all

on the same thread we just need a big

enough batch size so we need a

buffer if we buffer this emails to send

Channel with the length of the emails

slice then we should have enough room to

push all of the emails into the buffer

Channel let's go ahead and try that

cool that looks like it is working

channels in go can actually be closed

and there's really only one reason you'd

want to close a go Channel and it's to

indicate that you're done with it a

channel should always be closed from the

sending side so the sending go routine

the one that's pushing values into the

channel will be the one to close the

channel and that will indicate to any

readers of the channel That this channel

is closed there's nothing else to read

from it and the actual syntax is really

simple it's just the built-in close

function where we pass in the channel

itself now on the reading side we can

actually check if a channel is closed

using this kind of optional second

variable um that comes back when reading

a channel this okay variable it's a

Boolean uh if the Boolean is true the

channel is open if it is false the

channel is closed if the channel happens

to be buffered then okay will remain

true until the channel is emptied out so

okay will only be false once the buffer

channel is empty and closed the last

thing I'll mention before we jump into

the assignment is that you never want to

send a value across a closed Channel if

you do that go routine will panic and

that's why it's really important that

you only ever close a channel from the

sending side because that go routine is

going to be the one that knows when it's

done sending values okay on to the

assignment it says Amo we're all about

tring what our systems are up to with

great logging and Telemetry the send

reports function sends out a batch of

reports to our clients and reports back

how many were sent across a channel it

closes the channel when it's done okay

so the send reports function here sends

the reports or sends the number of

reports across the channel and closes

the channel

great complete the count reports

function it should use an infinite for

Loop to read from the channel if the

channel is closed break out of the loop

otherwise keep a running total of the

number of reports sent and return the

total number of responses Okay cool so

first things first we need to keep track

of a total so let's start it at

zero and we know that at the end of the

function we'll be

returning the

total

right then it says use an infinite for

Loop to read from the channel okay so

four um and then we need to read from

from the channel so we'll do um nums

Cent and read from the nums Cent

Channel okay if the channels closed

break out of the loop ah right so we

need to use that syntax to check if the

channel is closed so if not okay if the

channel is closed then we'll

return

total or I suppose we're returning down

here so we could just break let's just

do that instead break

otherwise uh we do total plus equals

nums Cent and it's important to

understand that as soon as okay is false

num scent will just be a zero value so

it's not a valid value that was sent

across the channel so it's safe to just

just break like that okay cool this is

looking correct to me let's go ahead and

run

that let's see batch of 15 38 and 61

Cent do those add up to 114 uh looks

like they might uh like my terrible in

in my head arithmetic says that that's

perfect so I'm going to go ahead and

submit it the range keyword works with

channels as well as slices and Maps so

we can actually range over the channel

and it will block until a value is ready

it will read it into in this case the

variable item and then execute the body

and it will do that over and over and

over for each new value coming across

the channel um and we'll only exit the

loop once the channel is closed so onto

the assignment it says it's that time

again maleo is hiring and we've been

assigned to do the interviews for some

reason the Fibonacci sequence is melo's

interview problem of choice we've been

tasked with building a small toy program

that we can use in the interview okay so

complete the concurrent Fibonacci

function if you're not familiar with the

Fibonacci sequence um I don't want to go

like too crazy far into it but it's

basically this sequence of numbers here

where each number is the sum of the two

preceding numbers so 1 and 2 equal 3 2

and three equal 5 in fact you probably

can't even see that let me Zoom this in

a little bit so 1 and one or 1 and two

equal 3 2 and 3 equal 5 3 and 5 equal 8

right so it's just this kind of set

sequence of

numbers okay complete the concurrent FIB

function it should create a new channel

of ins so let's go ahead and do that so

Channel

ins make channel of ins great call

Fibonacci in a go routine passing to it

the channel and the number of Fibonacci

numbers to generate okay so we have a

Fibonacci function here and it takes the

numbers and the channel itself so let's

start a go routine in an anonymous

function go

Funk call the

function um and in here we we call

Fibonacci let me just copy and paste

that because I can't spell

it uh it takes n

and this channel of in as input

okay then use a Range Loop to read from

the channel and print out the numbers

one by one each on a new line okay so

the Fibonacci function is going to pass

its results back over this channel so

it's it's taking the channel and it's

going to act as the sender on the

channel so we down here below um kind of

where we're spawning that go routine

need to act as the reader so for V and

range Channel

events print out the numbers one by

one print line

V and then when the Fibonacci function

is done it will close the channel so

we'll exit from the loop cool let's go

ahead and run

that does this look accurate 10 numbers

0er and one 0 + 1 is 1 1 + 2 is 3 2 + 3

is 5 looking good to me on to select

statements so a select statement is

similar to a switch statement if you're

familiar with switch statements from

other languages or from go where it's

kind of this if else uh chain and we're

really looking to kind of match a

specific case but what's interesting

about select statements is they're

unique to channels and they basically

let us listen on two different channels

and kind of execute one block of code um

or or or rather execute a block of code

for the channel that sends a value the

soonest so we can kind of simultaneously

listen on both channels and if this

channel sends a value first then we'll

do you know one thing otherwise when

this one sends something we'll do

another thing so one go r can kind of

process events from multiple channels at

the same time using a select statement

so this is the syntax here we create a

select block and then multiple cases one

for each channel that we are interested

in kind of listening for values on or

reading uh values off of so if this

channel ins has a value ready then this

case will be executed otherwise if this

one uh if Channel strings has a value

ready then this case will be executed if

both have a value ready at the same time

then one will be chosen randomly so you

don't want to kind of be dependent on

any weird ordering um basically as stuff

comes across it's going to get processed

so on to the assignment it says complete

the log messages function using an

infinite for Loop and a select statement

to log the emails and SMS messages as

they come across the two channels okay

so channel of emails channel of SMS

messages add a condition to return from

the function when one of the two

channels closes whichever is first um

use the log SMS and log email function

functions to log the messages Okay cool

so uh infinite for Loop start there and

inside we'll need to

select can use this as our syntax guide

over here U we got case uh

email

okay value from channel of

emails if that case fires then we say if

not okay so if the channel is closed we

just return and this function returns

nothing so we just naked return um

otherwise we need to log email I think

that's yeah log email there it is the

email cool other case uh sms okay from

the channel of

SMS if not

okay

return

otherwise log the

right so this for Loop will just go

forever until one of these two channels

closes in which case it'll return right

and it's important that we return before

we do the logging because when a channel

closes the okay variable um is false and

a zero value comes across the channel um

that wasn't sent into the channel if

that makes sense so like the closure

happens after the last value comes out

let's go ahead and run that

looking good to me we'll submit it the

select statement also has a default case

you don't always need to use the default

case and basically the default case only

fires if you're interested in

nonblocking so for example this select

block here will fire the case uh that

kind of pulls this V value out of this

channel if there is a value ready to be

pulled at the time that we enter the

select block if there's not a value

ready to be read out of the channel um

then the default case is fired

immediately so it kind of turns the

select block into a nonblocking block of

code and then there's a few things we're

going to need to know for this

assignment the first are these uh

several standard Library functions so

time. tick returns a channel that sends

a value on a given interval so we could

say uh pass in a second to time. tick

and we would get back a channel um that

receives a value once per second pretty

cool for like rate limiting doing

something on a set interval um time.

after sends a single value after the

specified time has passed so if we

created a new Channel with time. after

and passed in one second then one value

would come across after a second had

passed and then the channel would be

closed um time dos sleep just blocks for

the specified amount of time in fact I

think we've kind of seen it around um so

far in the course and then we have read

only and write only channels and these

are pretty cool from like a type safety

standpoint uh basically we can take a

channel and we can pass it into a

function but specify that within the

function we are just going to read from

it so then within the function uh the

compiler will not allow us to write to

it so this is a great way to kind of

keep uh go routine safe in terms of

which functions are readers of channels

and which fun fun are writers of

channels um and we can do the same thing

with writers by using this syntax here

so readers read out of the channel

writers right into the channel the

assignment says like all good backed

Engineers we frequently save backup

snapshots of the maleo database complete

the save backups function okay it should

read values from the snapshot ticker and

save after channels simultaneously okay

so the ticker and the save after these

are channels that are created down

here us those standard Library functions

that we just talked

about okay so we need to use a select

statement it looks like read values

continuously so I'm going to use a for

Loop and a select

statement if a value is received from

snapshot ticker call take snapshot okay

so case Val okay we want to read out of

a snapshot ticker

um do we actually do we care about the

channel being closed let's see saved

after no actually we don't so we just

need the value from snapshot

ticker oh and we don't even care about

what the value is so we can just

completely ignore the value um call take

snapshot

okay if the values saved after so

case save

after call Save

snapshot and return from the function

because we're done okay so again we

don't need to return anything from this

function doesn't have any return values

if neither channel has a value ready

call wait for data okay so

default wait for

data and then sleep for 500 milliseconds

so time do sleep

time.

millisecond time

500

okay this is looking good so we've got

this infinite for Loop we'll we're

looking for values um that are coming

across these channels anytime a snapshot

should be taken we take it anytime um

this save after Channel passes us a

value we will save the snapshot and exit

the function otherwise we'll wait for

data whatever that does and sleep for

500 milliseconds in fact I'm curious

what does wait for day to do okay so all

these do um is kind of Print Different

messages so let's go ahead and run

that okay cool so nothing to do waiting

nothing to do waiting right so every 500

milliseconds we're kind of logging out

that we are waiting we're waiting for

things to to do um taking back backups

taking backups and um finally saving the

backups at the end cool let's submit

this looks correct to me Dave Cheney is

a fantastic author and contributor to

the go programming language and the go

ecosystem um and he has this awesome

article that I would definitely

recommend checking out it's called

Channel axioms um I've kind of

summarized it here and we're going to

talk about a few key points so the first

is that Ascend to a nil Channel blocks

forever so the zero value for a channel

is nil if you don't use the make

function to initialize a channel then

the Channel's value is just nil and if

you try to send on a nil Channel your

code's just going to block forever

similarly a receive from a nil channel

will just block forever now this one's a

lot more dangerous trying to send on a

closed Channel panics so you need to be

really careful and make sure you're only

closing channels from the go routine or

the function that's writing to the

channel so that you can be sure you'll

never try to write to that closed

Channel again and then then a receive

from a closed Channel Returns the zero

value immediately so if you're trying to

pull data out of a channel and it's

already closed you'll just get the zero

value and we've already seen how you can

also kind of optionally check for that

okay value uh which will be returned as

false so what happens when you read from

a nil's channel uh the receiver will

block forever and what happens when you

send to a closed channel uh you'll get a

panic and you never really want to panic

and go that's almost always indicative

of a bug so channels are one tool that

we have in go to sort of synchronize

State across different go routines right

we can send data from one go routine to

another safely mutexes are another

builtin primitive well rather they're

not built into the language but they're

built into the standard library and they

allow us to also sort of communicate or

share data between two go routines

mutexes work by locking access to

protected resources so that only one go

routine can access that resource at a

time so the sync. mutex type is exposed

by the standard library and basically

the way it works is you create a new

mutex and then you share it across many

different go routines and then you wrap

whatever code that that is dangerous or

whatever resource that is dangerous um

that you never want two go routines at

the same time kind of getting access to

you wrap them in a call to lock and

unlock so for example in this function

we have this protected function and it

calls mx. lock at the top of the

function and then it defers an unlock

and what this means is when one go

routine calls this protected function um

if it's the first call to this protected

function then this mx. loock will lock

the mutex for this go routine and it

will be able to move on and kind of

complete the rest of the function and

then call uh m tex. unlock every other

go routine that calls this function

right on this shared mutex will actually

block at the mx. loock function call

because the mutex is locked by another

go routine so mutex stands for Mutual

exclusion because it excludes every go

routine except one except for the one

that holds the lock and once that first

one actually unlocks the mutex then one

other go routine is able to pick up the

lock um execute its protected code

and move on from there so it's a way to

take some dangerous resource and sort of

share it across many different go

routines uh safely there are a couple of

different reasons why you would want to

protect a resource and only allow a

single go routine to kind of work on

that resource at a time but one super

common one is Maps so maps are not

thread safe in go if two different go

routines or trying to read from and

write to the same map uh go will

actually panic

uh because that has a very high

likelihood of causing a race condition

and if you're wondering what a race

condition is a race condition is kind of

what it sounds like it's when two

different go routines effectively racing

uh to get access to a specific resource

so imagine a case where we have a count

variable and it's set equal to maybe

five and you have one go routine that

reads that count variable and saves it

into say another variable my count right

and then maybe doubles it and then saves

the doubled value back into count well

what if we have another uh thread of

execution doing the same thing if they

both read count let's say they both read

five

double five so now they both store 25

and they both go to write 25 back into

the variable all you did was double five

once where you were probably expecting

to have two different threads doubling

the variable so you probably were

expecting for it to go 5 to 25 and then

double again 25 s 625 I think um the

point is depending on exactly how those

operations are threaded into the CPU

you'll actually get different Behavior

so race conditions are awful to debug

and mutexes allow us to lock access to

those protected variables so we could

wrap that count variable in a mutex to

avoid it being accessed at the same time

by different go routines so this should

make a lot more sense once we write some

code the assignment says we send emails

across many different go routines at

maleo to keep track of how many we've

sent to a given email address we use an

in-memory map Okay so we've got this

counts map stored within a safe counter

struct the map is of string to integer

and then we've got a pointer to a mutex

uh that we're sharing across all these

different go routines um our safe

counter struct is unsafe update the

increment and the value methods so they

utilize the safe counters mutex to

ensure that the map is not accessed by

multiple go routines at the same time

okay so we've got the safe counter and

it looks like it's going to be kind of

copied across different go routines so

we create one instance of the safe

counter um it's getting passed into this

test function and then we've got this go

routine um it looks like we're spawning

go routines in a for Loop and then uh

and then using that safe counter right

so increment is being called many

different times across many different uh

threads of execution and that is not

safe cool um so let's see what happens

if I run the code right

now Jill has three emails John has

four and if I look down into the tests

like that is wildly inaccurate right so

it it kind of looks like what's

happening is is like the example I

described where maybe you're multiplying

numbers together at the same time so you

kind of end up with a smaller number cuz

everyone's doing it at the same time

then saving the variable back it kind of

looks like that's what's happening we're

getting these tiny results cuz all of

these different go routines are

incrementing uh the number at the same

time okay so we need to lock this

down

sc.

m.m. loock so lock

the the mutex and then defer the unlock

it's important to understand that we

could do this and it would be the

same um right we lock we do the

dangerous thing and then we unlock um

but this is the

preferred the preferred way kind of the

idiomatic go way to do it um it just

it's just a little safer right if we add

multiple Returns the defer will never

not execute so um that's how we're going

to do it and then we also need to lock

um on the Val function because reading

um and writing at the same time is also

dangerous cool let's run that see if we

get some bigger numbers in our

counts notice it's taking a lot longer

to run and and that's because we're

locking and unlocking so every thread

has to kind of go one after the other so

it slows it down um but it's a lot safer

so we get these accurate counts let's go

ahead and submit

that so as we discussed am mutex is

called a mutex because it's short for

Mutual exclusion and the conventional

name for a mutex is um mutex or

sometimes it's abbreviated to MX

personally I use MX a lot so to answer

the question what does it refer to it's

going to be mutual exclusion the next

question is how many threads or go

routines can lock a mutex at once or at

the same time the answer is one right if

any more could lock it at the same time

time it wouldn't be very useful the next

question is why would you use a mutex to

safely access a data structure

concurrently to stop other packages from

using my code to protect data from

network access or to encapsulate private

data members of a struct it's going to

be to safely Access Data

concurrently time to talk about another

type of mutex so we've already covered

pretty much all of the functionality you

need to know about the sync. mutex type

but there's another type there is a

sync. RW mutex or sync. readr mutex so

the sync. readr mutex has a little more

functionality um it has the same lock

and unlock methods and works exactly the

same way as a normal mutex but

additionally it has two more methods

rlock and R unlock so the reason you

would use a read write mutex is because

it allows you to have multiple readers

at the same time for example it's

actually safe to read for from a map on

multiple go routines at the same time as

long as you're not reading and writing

at the same time or writing and writing

at the same time writing is the

dangerous operation so the way this

works is if the mutex is locked like

with the do loock method then no other

go routines can lock or arlock the mutex

however if the mutex is just are locked

then other mutexes can still our locket

so you can get multiple readers but you

can't get readers and writers or writers

and writers it just allows many threads

to concurrently read so what this does

is if you have a program with a shared

resource where most of the threads are

interested with reading the shared

resource and you only have a few writers

you can make your code a lot faster by

using a read write mutex and allowing

multiple readers at the same time your

code will move faster and have fewer

locks slowing down

um and synchronizing your application so

on to the assignment it says let's

update our same code from the last

assignment but this time we can speed it

up by allowing readers to be read from

the map concurrently update The Vow

method to only lock the mutex for

reading notice that if you run the code

with a right lock it will block forever

Okay cool so if I run try to run it

right now um it's going to have issues

because I believe it is are locked um by

the test Suite out of the gate so that's

a problem um we can fix

it by changing those to rlock and R

unlock perfect looks good to me I'm

going to go ahead and submit that so a

quick review on read write mutexes how

many writers can access an RW mutex at

once or at the same time uh the answer

is one and how many readers can access

an RW mutex at once it's going to be

infinite there is no limit the next

question is can readers and writers use

RW mutexes at the same time the answer

is still no right no one can use the

mutex if it's being written to generics

are an amazing new feature in the go

programming language at least they are

new as of the time of this recording

we're on version 1.20 now and generics

were just released in 1.18 and they were

one of the most widely requested

features by go developers so let's talk

about what generics are and why they're

so useful let's take a look at this code

here we have a function called split in

slice so it takes a slice of ins and it

splits it into two smaller slices of

integers it effectively just splits the

slice in half and returns two new slices

the really interesting thing about this

function is that if you take a look at

the function body it doesn't actually

care that this is a slice of ins it

could be a slice of strings or a slice

of booleans the logic in the function

body would be the same right calculate

um kind of the midpoint of the slice and

return two new slices um with all the

values up to that midpoint the annoying

thing is that prior to generics in

version 1.18 if we wanted to split a

slice of strings we would actually need

to write an entirely separate function

because in go we have static typing and

we need to tell the compiler what type

of slice it is that we are splitting now

it is true that prior to generics you

could write a function that takes a

slice of the empty interface which is

essentially a slice of anything and then

returns to slices of the empty interface

the problem with that is that you need

to cast the return values back into

whatever they were which is kind of a

dangerous runtime check so generics or

type parameters are really just a way

for us to write that function with the

empty interface but do it in a compile

safe way because if you think about it

the compiler can know that this function

doesn't care about the types going in

but that anytime it's called the types

coming out will be the same as the types

coming in so how does it work well we

effectively have a new type of parameter

that can be passed into a function so

after the function's name we have these

optional square brackets and here we're

defining a new type we're calling it t

and we're saying it is of type any or it

can be anything now because we using T

the type parameter as both the input and

the output we're telling the go compiler

hey whatever I pass into this function

that's what I'm expecting to get back

out right if I pass in a slice of

integers I expect to get out two slices

of integers so now if we take a look at

how the code is actually used right how

the function is called we can use the

split any slice function give it a slice

of integers and we'll get back two

slices of integers everything is type

safe so in a nutshell the reason to use

generics is to dry up our code right dry

is just an acronym for don't repeat

yourself it's a way of writing code uh

that can be reused uh more easily so

instead of having to write two nearly

identical functions just to deal with

two separate types of slices we can now

write a typ safe function once and reuse

it throughout our application so let's

Jump Right In the assignment says at

maleo we often store all of the emails

of a given email campaign in memory as a

slice we store payments for a single

user in the same way so those are two

very different things right emails and

payments complete the get last function

it should be a generic function that

Returns the last element from a slice no

matter the type stored in the slice if

the slice is empty it should return the

zero value of the type okay cool let's

get started okay so we can kind of use

this syntax as a guide so we're going to

need um to specify type it can be

anything like the assignment said and

we're going to take as input a slice of

that type and return one element of that

type okay now it says um we need to

return the last element from a slice so

uh we need to slice the slice

essentially check its length right so we

can say um if the length of s is zero so

if there's nothing in the slice we're

going to have to just

return uh the m empty type of T which

down here it says we can create uh we

can create a new empty variable like

this so we'll just

do

bar zero Val and then we'll just return

it okay cool so if the slice is empty

we'll return the the zero value um

otherwise we'll

return S

at the length of s minus one right okay

so if there's nothing in the slice we'll

return the Z zero value otherwise we'll

return the element in the last index and

the reason we have to do this guard

Clause is because otherwise this would

be an unsafe operation we'd get an index

out of Bounce error uh if we tried to do

this operation on a slice of zero length

so let's go ahead and run

it and it looks

like okay so the test case with a zero

length slice returns an empty struct

that looks correct to me me getting last

email from a slice of length three

there's the last one looks like it

returned it correctly and then here we

have payments right so a completely

different type and the last one is Jane

example.com yep that looks correct to me

Margo Margo cool let's submit it so why

are there generics in the go programming

language well there's kind of three main

points that are important to understand

the first as we already covered is that

generics reduce repetitive code so

whenever we have code that doesn't

really care about the type or maybe it

only about a small superficial part of

the type then we can write more abstract

and more reusable code if we have access

to generics right because it keeps the

code compile time safe and type safe

before in go if we wanted to reuse code

we had to do sort of dangerous runtime

checking right casting things to empty

interfaces and back from empty

interfaces it's also important to

understand that generics are going to be

used much more frequently in libraries

and packages if you're say about backend

developer and you're building

applications um and not libraries or

packages that are intended to be used by

other people um You probably don't need

to use generics all that often which is

why the go programming language was able

to get away with not even supporting

them for so long now if you do work on

libraries or packages or maybe you're

even a contributor to the go standard

library then you probably are going to

use generics quite a bit more they'll

make it a lot easier to write more

abstract code that's useful uh for more

and more use cases the last Point that's

important to understand is just Why did

it take so long to get generics into the

language right they're super useful why

didn't we add them I don't know five

years ago or a decade ago and go was

kind of getting started the answer is

that one of the philosophies behind the

go programming language is just to kind

of keep it simple go doesn't have all

that many features because go developers

and go maintainers don't buy into the

idea that more features necessarily

makes a better programming language by

having fewer features it means there's

less to learn to get up and running with

the language it also means that anytime

you see a piece of go code you'll have

an easier time understanding it and

working with it so even more so than

other languages the go team is very

hesitant to add new stuff so generics

were in the works for a long time and it

was only after many years of thinking

about it and making sure that we really

needed them uh that they actually got

their way into the language so the

question here is is what code would

generics be most likely to help with a

binary tree detecting whether or not a

string contains a given substring or

calculating the area of a circle well

detecting whether or not a string

contains a substring we'll probably just

use string types and calculating the

area of a circle just sounds like floats

to me um but a binary tree is a data

structure that can store any type it's

kind of like you know a slice in that

way um so I'm going to go with binary

tree on that one the next question is

Go's approach to language design is to

support as many useful features as

possible to resist adding new features

until they're extremely important or

proven extremely important or to never

add new features the language doesn't

change um and the answer is to just

resist adding new features unless

they're proven to be very very important

the next question is generics will

probably be used more heavily in blank

main packages which are executable

applications or Library packages and I

definitely argue that they'll be more

heavily used in library packages okay so

we we talked about how generics are

super useful when the type that is being

used in your function doesn't matter

right when it can be anything but

constraints allow us to write generics

that are actually just useful for a

subset of types right so maybe this

function doesn't care too much about the

types that are being used but it does

care a little bit so let's take a look

at an example this concat function is

similar to the other generics that we've

worked with

the big difference is that the type T

the type parameter instead of being able

to be anything we're saying it has to be

a Stringer right and we've specified the

Stringer interface here it's just

anything with a string method on it that

returns a string with the builtin any

constraint which is effectively the

empty interface we can't really do

anything with the values inside the

functions right which is why it works

for something where we're just say

splitting a slice of that type but in

this function the concat function where

we're actually able to use the type a

little bit we're able to call the method

that's implemented on it and that's just

because the only thing that we know

about these values coming into the

function is that they have that string

method so what does the concat function

do well it takes a slice of

stringers it Loops over all of them

grabs the string representation right by

calling that string method the string

representation of each value and then

kind of just mashes them all together

right it concatenates them and Returns

the result so let's take a look at the

assignment we have different kinds of

line items that we can charge our

customers credit cards for line items

can be things like subscriptions one or

onetime payments great complete the

charge for line item function first it

should check if the user has a balance

with enough funds to be able to pay for

the cost of a new item okay so we're

given a new item which is of type T

given a slice of old items and a balance

is just a float um if they don't have

enough funds then we'll return an

insufficient funds error but if they do

have enough funds then we'll add the

line item to the user's history by

appending new item to the slice of old

old items okay this new slice is your

first return value right so we're

returning three values here so we're

returning kind of the new list of old

items after new item has been

appended um and we need to calculate the

user's New Balance by subtracting the

cost of the new item from their their

balance this is my second return value

Okay cool so we Tak in their balance

we're going to subtract the cost of the

new item and then return the New Balance

um and obviously if nothing went wrong

we'll return a nil error okay so we have

the type here as a line item so line

item is this interface and it looks like

we we kind of have these two methods

available to us um within our function

we can get the cost of a line item or we

can get the name of a line item so the

first thing our function is supposed to

do is check if the user has a balance

with enough funds so we need to do

something like uh new new

balance is equal

to

balance

minus the new

item. get cost right so we're going to

check what the New Balance would be

after subtracting the cost of the item

from the user's balance then we can say

if the new balance

it's less than

zero then we'll return this insufficient

funds error right and zero values for

everything else so it'll be uh nil slice

0.0 float

and errors. new insufficient

funds we'll need the errors

package okay cool otherwise that means

this uh this balance is uh zero or

greater right

um and it says add the line item to the

user's history by appending it to the

slice of old items so we could do old

items equals append old items new

item okay this new slice is your first

return value

great otherwi um and then calculate the

the user's New Balance by subtracting

the cost of the new item from their

balance so we already did that um this

is your second return value so I think

we could just return

um old items New

Balance and

nil right let's go ahead and run

that okay charging customer for a yearly

subscription current balance is 1,000

new balance is 750 total number of line

items is now

one for monthly

subscription new balance is less total

number of line items is now three let's

go take a look at those test cases just

to make sure that this makes

sense okay so they had zero now they

have one

subscription here they had two

subscriptions now they have three

subscriptions cool that looks or or

three L items that looks good to me I'm

going to go ahead and submit it when

generics were released a new syntax for

writing interfaces was also released um

partly just because this new syntax is

super useful if you're trying to use

interface faes as constraints for your

generic functions so let's take a look

at an example um a typ list is pretty

much as simple as it sounds we're

basically just creating a new interface

in this case we're calling it ordered

and then we're just listing all of the

types that we're saying Implement that

interface so there's no methods here but

the interesting thing about all of these

types is that they all support these

inequality operators like less than less

than or equal to greater than and so if

we use ordered as a cons straint then

we're free to use these comparison

operators on that type and the question

that goes along with this is why might

you create an interface using a type

list and the answers are you know

exactly which type satisfy your

interface or it's too much trouble to

define the methods required by your

interface um that second one is a bad

reason uh it's you would really only do

this if you know exactly which types

satisfy your interface let's take a look

at parametric constraints which sounds

like a kind of complex term but it's

actually really simple it basically just

means that we can use type parameters in

interface definitions as well so instead

of just creating interfaces which we

then use in our type parameters for

functions we're actually using type

parameters to Define new interfaces so

for example here we have a

store that takes as a type parameter P

which is a product now a product is just

an interface right um it's a product is

anything that can return a price and a

name so a store which is again an

interface is just anything that can sell

a product now the idea really is that

simple if you want to get an idea for

kind of how this whole uh snippet of

code works the example code I'm not

going to talk through every line that

would take a little bit too long but

feel free to kind of browse through this

and get a feel for how um that interface

Works we're going to jump straight into

the assignment so getting on to the

assign assment says the Chief Architect

at maleo has decided she wants us to

implement billing with generics

specifically she wants us to create a

new biller interface a biller is an

interface that can be used to charge a

customer and it can also report its name

okay so let's take a look at what a

customer is so a customer is this

interface it's just anything that has a

get billing email method on it so in

this case a user is a customer and an

org is a customer

okay um and it can also report its name

okay that's simple enough um there are

two kinds of billers user billers and

org billers Okay so we've got user

biller here and org biller

here create the new biller interface it

should have two methods okay so let's go

ahead and do that

type

biller

interface two methods charge and

name the good news is the architect

already wrote the user biller and org

biller type for us that fill this new B

interface right we took a look at

that use the definitions of the types

and their methods to figure out how to

write the biller interface on line 7

Okay cool so let's start with name it

looks simpler so a user biller um has a

name method it takes no parameters and

returns a string uh same with the or

biller so that one's simple it just

returns a

string okay the charge method for user

biller accepts a user returns a

bill but for the org Biller accepts an

org and returns a bill okay so it always

returns a bill that part's easy but what

it accepts is a little bit

different right and if we take a look

at the customer interface where did it

go customer interface here then we see

that we have

um we have this common interface that we

can use to represent both a user and an

orc

okay so that's convenient because we can

use that interface right as a parametric

uh constraint so let's create a new uh

parametric type or you know but a we'll

create a new type

parameter call it C because it's a

customer should be easy enough and then

charge will actually take as input

C right it will take a customer

rather than specifically a user or an

org okay let's try

that it compiled at least let's see what

we got using basic user biller to create

a bill for Joe example.com

$50 basic user biller for Samuel bogs

$50 Pro user biller for Jade

$100 okay that's looking correct to me

it looks like the pro uh Pro and basic

uh have a discrepancy of $50 and $100

and then the org biller is being used

here you can see it's actually much more

expensive so that looks correct to me so

let's talk about naming generic types uh

we can take a look at this old example

or the example from earlier in the

course where we had to split any slice

right and it has t as a type parameter

um of type any and then we use T um kind

of all throughout the function signature

um T is just a variable name it doesn't

we don't have to use T there we could

name we could name this whatever we want

right we could name it my type uh

whatever the heck we want right uh slice

value it doesn't matter um however it

turns out that capital t is actually

fairly common convention um when there

is just a single type parameter for a

function so the question here is the

name of a type parameter blank can and

should be whatever you want can be

anything but T is a common convention or

must be t uh it turns out it can be

anything but but T is a fairly common

conventional name Rob Pike one of the

creators of the go programming language

created an awesome set of Proverbs that

outlines some more of the philosophies

behind the language I'm not going to

read them all to you but I am going to

cover some of the ones that I think are

the most important and if you are

interested I'd highly recommend going

and watching his talk about the Proverbs

uh if if you want to go more in depth on

them so let's start at the top don't

communicate by sharing memory share

memory by communicating so this

basically is telling us we should

probably try to use channels more often

than we use mutexes when we're trying to

share memory between go routines which

leads right into the third one which is

channels orchestrate and mutexes

serialize so when we use channels we get

kind of this elegant flow of data

through our program right one go routine

did something another go routine can

react to it mutexes are all about just

locking access to protected resources if

we can use channels to express logic in

our program it will tend to work a

little bit better another great one is

that the empty interface says nothing

right every type in go fulfills the

empty interface you should really avoid

using the empty interface just because

it doesn't tell you anything interesting

about your types the empty interface is

sometimes used by new go Developers to

kind of get around the type system and

that just leads to unsafe code go format

style is no one's favorite and yet go

format style is everyone's favorite so

we'll get into this in just a bit when

we jump into the project but the go tool

chain comes with its own formatter and

pretty much every production piece of go

code out there uses the same formatter

which is fantastic because it means all

go code looks the same while not

everyone necessarily agrees on the form

matters choice of say tabs versus spaces

it's still everyone's favorite because

it means we all get something consistent

that works reasonably well the next one

is one of my favorites it's a little

copying is better than a little

dependency now if you've ever worked in

the JavaScript ecosystem with node

modules you'll know exactly what this

means node modules is typically a huge

folder and a lot of times when you're

working on a front-end framework your

dependencies are much greater than your

actual application code and in go we

typically just kind of invert that way

of thinking we want our application code

to be the bulk of the code within our

project and we tend to use far fewer

dependencies as almost a philosophy and

this brings us to the one uh mentioned

here in the question which says which is

better clear or clever and at least

according to rag Pike clear is better

than clever so if you can write your

code in a way that is very clear to

anyone else reading it or even just to

yourself that's better than trying to do

a trick that might seem clever but is

actually hard for humans to understand

remember code is written for humans not

for

machines the next question is which is

better copying a little code or

including a small dependency and Rob

Pike would argue that it's typically

better to copy a little bit of code

rather than include a very small

dependency in your project the next one

I want to point out is that errors are

just values right and go error is just a

specific interface and we return it from

functions just like we do any other

value there's not some special way to

handle errors with tries and catches

errors are just values and we deal with

them just like we would any other

value the last one I want to point out

is that documentation is for users this

is actually an interesting one I think

what he's saying here and I I need to go

rewatch The talk to confirm but that

documentation is primarily for people

who aren't maintaining the code in other

words it's best if the code itself is

really easy to understand so it doesn't

need to be heavily documented so that

other maintainers can work on it right

um documentation in the sense that you

know we should be writing external

documents that explain how the code work

or or how to use it should be for the

users of our code right in the sense

that if we're writing a library we

should be writing documentation for the

users of the library um the developers

calling our exported functions right not

the maintainers of the library itself so

documentation should primarily be

written for the users of your code it's

time to build a fully fledged backend

server Ino from scratch on our local

machines the purpose of the server will

be to aggregate data from RSS feeds if

you're not familiar with RSS it's a

protocol that makes Distributing things

like podcast and blog posts really easy

so what our server will allow users to

do is add different RSS feeds to its

database and then it will go

automatically collect all of the posts

from those feeds and download them and

save them in the database so that we can

then view them later before we get

started there are four things you're

going to need the first is a basic

understanding of SQL the language that's

most often used to query relational

databases if you're not familiar with

SQL yet that's okay I've got a full

course on SQL I'll link that down in the

description below go watch that then

come back here if you're not familiar

with SQL number two is you're going to

need a text editor and a command line

I'm using vs code and zsh uh here in the

video so you'll see me using that uh

feel free to go download those if uh you

want to try them out but you can use

whatever text editor you want as long as

it can edit your files and you have

access to a terminal to run commands

number three is the go programming

language itself if you don't have that

you can go download it I will link uh

the download page down in the

description below and I'd also recom

recommend just installing the go plugin

um if you're in VSS code there is an

official go plugin Go download that

it'll make your life easier with syntax

highlighting and formatting and that

sort of thing number four the last thing

you'll need is an HTTP client so an HTTP

client will allow you to make get and

post and put requests into the web

server that we're building we'll need

that for testing I use the Thunder

client it's a vs code extension but you

can use anything you like even curl on

the command line or post and insomnia

there's tons of choices Google HTTP

clients um or if you don't already have

a preference again if you're in vs code

I'd recommend the Thunder client

extension now that you have all of those

tools installed and hopefully working

let's jump into the project the first

thing we're going to need is just a

main.go file we'll create our entry

point um it will be a part of the main

package and it will need a main function

so Funk main takes no arguments return

those returns no parameters and for now

let's just print hello world make sure

we can kind of build and run this

program um we're going to need to

initialize a new module for our project

so I'm going to do go mod in it and I

like to name my modules after their

remote path right where they will exist

um kind of out on the internet so uh in

my case I use github.com my GitHub uh

namespace which is Wags Lane slash the

name of this repository which again is

where I'll be keeping this code on

GitHub so I highly recommend you keep

track of this code in GitHub this entire

project should be checked into git and

uploaded to GitHub or gitlab or whatever

you prefer um so I'm going to name this

repository um RSS aggregator RSS a so

we'll go ahead and create that that will

create this new go

module and now that that's ready we

should be able to just go

build and execute the new uh binary or

the new executable that will be created

from go build in fact I'll just run it

once so you can see I created this new

binary file here in my current directory

and so from now on I'll be running this

command go build and

slash RSS a so that will build and run

and we got hello world back so we're

good to go like I said before we're

going to be building this project with

Git and storing our code in Source

control as we go so I'm going to go

ahead and create a new

get repository and in vs code it

highlights all the code that has changed

but not yet been committed to Source

control here in green um but I don't

want all of this in my source control

the vs code file is configurations for

my editor um that's a personal thing

that doesn't need to be in the project

itself um same with the RSS a binary we

don't want to commit the binary that

we're building or the executable file

that we're building we just want to

commit our source code so I'm going to

create a newg ignore file

and we're going to ignore the vs code

folder and the RSS a

binary and next um we're going to add

all of the secrets the like

configuration Secrets uh for our project

in a EnV file and read them out of the

file itself so uh for example one of the

configuration variables that we're going

to set is the port that the server will

run on so um I'm going to set that port

to

8,000 and I'm going to also ignore thatv

file in the G

ignore again because configuration data

is something kind of local to my machine

in production this port might be

something different so we don't need to

commit this file to Source control um

but I do want it here in my repo now at

this point I do want to pause and say if

you have no idea what a port is or you

have no idea what HTTP requests are or

rest apis are um we're going to move

fairly quickly in this project so if

you're not familiar with that stuff

again I will link down in the

description below my HTTP course that

would be a good one to go brush up on

before working on this project so now we

need a way to read this port variable

into our program so that we can use it

and the ghost standard library has a

built-in uh function called os. getet n

so it's a an exported function called

get end from the OS package and we can

get the value of a variable by its key

so in this case the key is

port and we'll get back a port

string and then for now let's just uh

let's just say if Port string equals the

empty string then we'll

say uh log. fatal so log. fatal will

exit the program immediately with arrow

code one and a message and we'll say uh

Port is not found in the

environment otherwise we'll

say

port and we'll print the port string

okay cool let's go ahead and run

that Port is not found in the

environment okay so the problem here is

that Port the environment variable

doesn't exist in my current shell

session if I wanted to add it I could

run in my in my command line export Port

equals

8000 and then run this again and then we

get Port equals 8,000 the problem is I

don't want to manually set this

environment variable every time I work

on my server I want to pull it from this

file so we're going to use a package

that allows us to grab environment

variables from a file

um and it is this package here

github.com

jooho go. EnV um that's also the URL of

the library you can paste that into your

browser uh go check it out but we're

just going to install it here

locally and that will add it here to our

go.mod and then I'm going to run go

vendor to copy that code here into uh my

my vendor folder um we get kind of a

local copy of that and we'll run um here

we're going to need to actually use it

so we do go. env. load and by default

load loads the uhv file I think we can

also optionally pass in EnV as the file

path and what's uh what's my error here

could not import no required module

provides

go let's go mod

tidy that should clean up my imports

okay

perfect

and do I need to do anything else what

are we getting here could not import no

required module oh I should probably go

mod vendor

again that should pull in the code okay

so you can see we've kind of imported

and downloaded all of that code from the

package and now I'm not getting error

any errors in my console okay so this

will take the environment variables from

myv file and pull them into my current

environment so that then I can use os.

get EnV to load the variable so to test

that let's go ahead and change uh the

port to

8080 and rerun the

server still says 8,000 so something

went wrong maybe I'm misremembering how

to use this uh use this

package let's try just go. .load

still Port

80 what am I doing wrong does it not

overwrite you know what it might not

overwrite my current session I'm going

to kill my current cell session shell

session and create a new one then we'll

do this again so now I won't have that

exported 8,000 that I had in my terminal

um run that again okay cool so now it's

pulling it from the file because I don't

already have it defined in my shell

session now I want to take just a second

and point out there are text

instructions for this entire project

over on boot. and I'll link that down in

the description below we're going to be

using a lot of text uh you know code

Snippets from those text instructions

and they'll be easier to kind of copy

and paste and grab from boot. directly

than trying to you know retype what

you're seeing me type here on the screen

now we're going to actually spin up our

server and we're going to be using the

chi router to do it it's a third-party

router uh very lightweight built on top

of kind of the the same way that the

standard library in go does http routers

and so let's go ahead and install those

now we'll do go get um github.com

gochi chai or chi I always struggle to

pronounce that one um we'll install that

and we'll install the the cores package

from the same uh the same Nam space the

chi namespace next we'll create a new

router so I'll do router colon equals

chi. new router

fact I should probably go mod

vendor have it there and then I'll do

another go mod tidy and go mod vender to

bring it

in cool so this creates a new router

object next we'll connect up this router

to an HTTP do server so serve colon

equals a pointer to an HTTP do

server and a server needs a Handler

which will be router

itself and we also need a or an address

which is just a colon plus that Port

string so in this case it'll be colon

you know 8080 cool and then we can call

HTTP do listen and

serve or sorry not HTTP listen and serve

we want to call it on the server object

so serve. listen and serve cool and

before we call that in fact I think that

returns an error so let's capture that

error and say if error does not equal

nil log.

fatal pass in the air as a

message okay listen and serve will block

so when we get to line 30 our our code

basically just stops right here and

starts handling HTTP requests if

anything goes wrong in the process of

handling those requests then an error

will be returned and we'll you know log

in and exit the program but kind of the

happy path for our code is that you know

nothing should ever be returned from

listen and serve because our server is

just going to run forever before we run

this let's just add one more kind of

logging statement we'll do log. print

line actually let's do print F and we'll

say server starting on

portent V and we'll pass in that Port

string okay cool with that let's go

ahead and build and run again so go

build see what we

get Hello World server starting on Port

880 I should probably remove should

probably remove that hello world at this

point now that we have a running server

let's go ahead and test it so I'm over

here in the Thunder client tab again

because I'm using the Thunder client

plug-in and I'm going to click new

request and we're going to make a

request to

http SL localhost right we want to make

a request to our own machine on the port

that we running on which I believe is

8080 okay with that let's go ahead and

start up our

server okay server starting on port 8080

so it should be good now you'll see I

don't have a new prompt because my my

server is still running um if I send

this get request perfect we get a 404

that's exactly what we'd expect because

remember in our code we haven't actually

set up any handlers or anything we just

have a server running so we're getting a

404 because we're trying to hit a path

in this case the root path uh and it

doesn't have anything any logic there to

handle that code if we killed our server

and ran it again we just get a

connection refused I've configured my

thunder client to actually store all of

my tests or my HTTP requests as plain

text here in the working directory uh

but I don't want those going into my

source control so I'm going to go ahead

and add that to the G ignore thunder-

tests we'll ignore everything in there

next let's add a Coors configuration to

our router so this is so that people can

make requests to our server from a

browser and we're going to be using some

fairly permissive uh configurations here

and we'll use

router. use and then we'll pass in this

cores. Handler configuration this comes

from that Coors package that we

installed earlier and let me see what am

I doing here we need one more

parentheses there and then I'm going to

go ahead and vendor this as well so go

mod tidy go mod

vendor cool so we should have all of

that code here in our vendor folder as

well I'm not going to go too in depth on

exactly what cores are you can

definitely go look that up but just to

give you a high level overview um this

configuration is essentially telling our

server to you send a bunch of uh extra

HTTP headers in our responses that will

tell browsers hey we allow you to send

uh you know requests to http or https

versions We allow you to use these

methods we allow you to send any headers

um it's just a way to say hey we're

going to allow you to do basically

whatever you want there are ways you can

tighten up this configuration for

security purposes but for now we're just

going to be running our project on our

local machine so we're going to just

open it up make it permissive to avoid

any sort of uh kind of weird testing

issues if we try to connect to our

server through a browser This Server

we're building is going to be a Json

rest API which means all of the request

bodies coming in and response bodies

going back will have a Json format so

let's create a little helper function

that will make it easier to send Json

responses so I'm going to create a new

file call it json. go it's going to be

in the main

package and the function sign is going

to look like this so we've got a

function we're calling it respond with

Json it takes as input a response writer

this is the same HTTP response riter

that uh HTTP handlers Ingo use it's

exposed by the standard Library um it

will take a code so this is the status

code we're going to respond with and

then we'll take an interface which is

just something that we can Marshall to

um a Json structure the first thing the

function will do is Marshall the payload

into a Json object or a Json string and

the way we do that is with the standard

Library so we data and error equals

json.

Marshall and we pass in the

payload so this function will attempt to

Marshall uh whatever it's given into a

Json string and it will return it as

bytes and the reason it returns it as

bytes is so that we can write it in a

binary format directly to the HTTP

response uh which is pretty convenient

if that fails for whatever

reason then what we'll do

is we'll write a header to the response

and we'll use status code 500 we'll say

something went wrong on our end right

internal service error or internal

server error um and then we'll just

return from the function and actually if

something goes wrong we should probably

log it um as well on the server side so

that we can see our own logs and see hey

we tried to do something in a broke uh

so we'll do log dot print

line failed to

Marshall Json respon

response and let's print the

response or let's print what we tried to

Marshall that's probably more more

interesting we'll use print F so that we

can interpolate that value there um next

we're going to need to add a header to

the response to say that we're

responding with Json data so we'll do

W.R

header and or not right header I'm sorry

uh w.

headers do it

header do add and we want to add the

content type key so content

type and the key will be or the value

will be application Json so this adds a

response header to the HTTP request

saying hey we're responding with a

content type of application Json which

is the standard of value for Json

responses um and then we should be able

to uh write the status code so we do w .

WR header 200 so everything went well

and then we need to write the data

itself so w. write and pass in the Json

data this will write the response body

now that we have a way to respond with

some Json data let's create an HTTP

Handler that does that so we'll do

handlers or

Handler

Readiness again this will be in the main

package and we're going to create a new

function

called Handler Readiness and this is a

very specific function signature this is

the function signature that you have to

use if you want to Define an HTTP

Handler in the way that the goh standard

Library expects so it always takes a

response writer as the first parameter

and a pointer to an HTTP request as the

second parameter and then in the body of

this Handler we can just call our

respond with Json function so we'll say

respond with Json we'll pass in that

HTTP response writer we want to respond

with a 200 status code and some some

response payload in this case all we

care about is the 200 okay status code

so I'm actually just going to respond

with an empty struct which should

Marshall to kind of an empty Json object

and now that I'm writing this I realized

that we actually made a mistake or I

made a mistake in the Json uh respond

with Json code we should pass in uh we

should use the pting Response Code

instead of hardcoding the 200 so if

everything goes right we'll use the code

given okay now with that we need to hook

up our Handler Now using the chi router

what we do is we hook up a an HTTP

Handler which is this function to a

specific HTTP method and path okay so

the way we're going to do that is I'm

going to create a new router so V1

router and we'll use that same chi. new

router to do it

and I'm going to specify V1

router.

handle handle Funk excuse me I want to

handle the slash ready

path and I want to handle it with this

Handler Readiness function okay so we're

we're connecting the Handler Readiness

function to the slash ready path and the

reason I created this new V1 router is

because I'm going to mount that so I can

do router. Mount

count to the

slv1 path okay so I'm nesting a V1

router under the slv1 path and I'm

hooking up the Readiness Handler at the

SL ready path so the full path for this

request will be slv1 SL ready and that's

just so that if we make breaking changes

in the future we can kind of have two

different handlers one under version one

and one under version two for our rest

API this is fairly standard practice

and actually I'm going to name this path

health health Z that's just a habit uh

that I'm bringing with me from

kubernetes land it's pretty standard to

have a SL Health Z path um that you can

hit to see if your server is live and

running so that's the purpose of this

Handler it should just respond if the

server is alive and running and

everything's good okay so let's go ahead

and run the server and make sure it's

doing what we'd expect so go build and

slash RSS a that starts up the server

and then we can open up thunder

client and now instead of making a

request to the root which we'd expect to

get a 404 from we'll do

slv1 healz and make that get request and

we get the 200 now here's the weird

thing if I change this to a post request

and I make that I actually still get a

200 but that's not really Our intention

the health Z endpoint should really only

be accessible by get request so I'm

going to make an update here rather than

using the V1 router. handle Funk I'm

going to use V1 router. getet and this

will scope the Handler to only fire on

get requests okay with that let's go

ahead and rebuild our

server and check again post should fail

method not allowed perfect but the get

request should still work so we have a

nice helper function for responding with

arbitrary Json now I want one for

responding with arbitrary error messages

so let's do function respond with there

um it will look very similar but instead

of taking a payload which is an

interface it will take a message string

and this function is basically just

going to format that message into a

consistent uh Json object every single

time okay uh first thing we're going to

do is say if the code is greater than

499 we're going to log a message and

that's because uh error codes in the 400

range are client side errors so we don't

really need to know about them it just

means someone's using our API in a weird

way um but we do need to know whenever

we're sering we're responding with a 500

level error code because that means we

have a bug on our end and we should

probably go fix it so we'll do log.

print line responding with 500 level

error and we'll just tack the message

itself on there okay cool after we do

that logging um we'll use the respond

with Json function uh but we'll be

responding with a

specific uh

structure of Json uh so let's go ahead

and Define that as a struct so type um

air

response is a struct and it has one

field error which just a string and

we'll add this Json tag to just say this

the key that this should Marcel to is

error so in go we typically take a

struct and add these Json reflect tags

to it to specify how we want this json.

Mar function or on the other side the

json. unmarshal function uh to kind of

convert this struct into a Json object

so in this case we're saying I have an

error field it's string and I want the

key for the field to be error so this

struct will Marshall into a Json object

that looks kind of like uh like

this

error you something went wrong

right it wouldn't have actually wouldn't

have that but it would look like that

okay and we'll see that in just a second

okay so now we get to respond with Json

we pass in the response writer a the

same code that we were given and then

we'll just respond with an error

response and the error message will be

the message that we were

given okay let's hook this up to another

Handler so here we can do V1 router.

getet we'll create an error endpoint and

oh I need I need an actual Handler so

we'll create a new one called

Handler

error Handler error and we'll respond

with an error instead of passing in an

empty struct we'll

say something when

wrong and we'll respond with a 400

status code client error right okay now

we can hook up this error

Handler here it will only work on get

requests that seems reasonable and

basically it's just going to call that

respond with error function so it'll be

a good way to test

that okay let's go ahead and rebuild the

server nope what did we screw up

routing pattern must begin with Slash ah

let's go fix

that so you can see here we've got SL

Health zv1 we need to start these with a

slash it's just the way the chai rou or

the chi router

works cool um let's go open up the

Thunder client and send a

request to the slash errror

Handler cool we get the 400 bad request

status code and this is that Json body

um so every single time that we need to

return an error from our server now we

can just use this function and it will

always use this consistent error format

which is great because we can throw this

in our documentation and just tell all

of the users of our API hey this is what

you should expect when something goes

wrong now that we have a little bit of

our boiler plate set up I'm going to

take the opportunity to commit all of

this to get uh so that I don't lose it

um I will say that I generally recommend

committing the vendor folder so you can

think of the vendor folder kind of like

the node modules folder if you're

familiar with JavaScript land and in

JavaScript you would never commit it

it's way too big um but in go we

typically don't have all that many

dependencies so it's actually perfectly

fine to commit the vendor folder in most

scenarios and I'd even recommend it so

I'm going to go ahead and add that and

commit

it we'll say

boilerplate or http

server

complete for this project we're going to

use postgress as our SQL database it's a

production ready database in fact it's

the one I used to build

boot. you're going to need to install

postgress on your local machine make

sure that the postgress server is up and

running and that you have a client

installed that you can use to make kind

of oneoff SQL queries against it I have

detailed instructions on how to do all

of that in the text instructions for

this project over on boot. so again go

check those out if you need to figure

out how to install postgress locally and

get a postgress client up and running on

your machine I use PG admin so that's

what you'll see me using in this

tutorial so if you followed those

instructions then you should have a

postgress server running on your local

machine and a postgress client installed

again I use PG admin that's what you're

seeing here on the screen okay so

because postgress is running locally I

have this Local Host server here in PG

admin that I've connected to again

that's the postgress server running on

my own machine and under databases I

have kind of the built-in postgress

database but I want to create a new

database that we're going to use for

this project so um in this case I'm just

going to name it uh RSS

a and we'll create that

database and then here within the RSS a

database as long as the uh kind of icons

are gold then you're connected and

everything is working at least up to

this point let's run a quick query

against the database just to really make

sure everything's working so I'm right

clicking here on the RSS a database and

I'm going to click query

tool and from this tool I should be able

to just write some raw SQL so I'm going

to go ahead and do a

select version this should just return

the current version of postgress that

I'm using I'm on version 14.7 and as

long as you're on something

14.7 or newer you should be good to go

now it's important to keep in mind here

that PG admin is just a client for

interacting with an SQL database right

we're able to write raw SQL code here

and run it against our database server

if you think about it kind of in an

analogous sense PG admin is basically

just the same thing as the Thunder

client where the Thunder client is a

client for running one-off HTTP requests

against our server PG admin is a client

for running oneoff SQL requests or SQL

queries against our database directly

next we're going to install two command

line tools that will allow us to work

with SQL databases from our go code much

easier now these aren't fully-fledged

orms if you're familiar with that term

these are kind of lightweight libraries

that allow us to work with SQL databases

using the standard library and just sort

of streamline the process for us the

first one is called

sqlc and again you can find all of these

commands in in the text instructions

over on bootd so be sure to be following

along over there but we're going to use

the go install command to go grab uh

sqlc and install it into our command

line once that's done you should be able

to just run

sqlc version to make sure it's working

next we'll install Goose the same way so

go install um and then the installation

path for goose again uh that link is

over in the text instructions and then

you can make sure that goose is

installed working correctly by typing

Goose Das version the great thing about

sqlc and goose is that they work based

on Raw SQL there's no kind of fancy

query language that's unique to those

tools we can just write SQL queries and

we're going to store all of that in our

repository so I'm going to create a new

folder is called SQL and in there I'll

create a new directory called schema and

this is where we'll store all of our

table definitions um or more

specifically our migrations so uh we'll

start with a users table and the way

Goose works is it runs the migrations in

order so we're going to start with

a01 migration and we'll call it users.

SQL from a very high level the way that

database migrations work is they have an

up and a down statement so for example

here we're creating a users table the up

statement will just create a new users

table and the down statement will delete

that same table so any down statement

should just undo the operation of the up

statement and that just makes it easy to

roll back changes to our database schema

if we ever need to the goose command

line tool Works based off of SQL

comments so we'll start with a comment

Das Dash plus Goose

up and dash dash plus goose down and

then anything we type here uh will be

considered an up migration and anything

here will be a down migration so let's

start with the up migration it's going

to be

create create table

users and the first field will just be

called ID it'll be a uyu ID a

universally unique identifier um I

prefer uu IDs to integer primary keys

for a number of reasons um I'll link a

blog post down in the description below

um and that's just going to be a primary

key uh next we're going to need a

created at which is a a

timestamp not null we must have must

have a created at must have an updated

at same

thing and then a user will also have a

name and we'll just make that a text

field again let's say that's not null I

need to remember to terminate my SQL

statements with a semicolon and for the

down M migration um it's pretty simple

we'll just drop the table so drop table

user users all right let's run our

migration but first we're going to need

to be able to connect to our local

database from our program and from our

command line so uh very first thing is

we'll need a DB

URL and we'll set it equal to the URL

that we use to connect to our local

postgress server so this isn't to

connect to PG admin this is the same

connection string that PG admin uses to

connect to the database server we want

to go directly to the database so it's

going to look something like this

postgress is the protocol so colon SL um

again this is just a URL um and then we

have the authentication part uh which in

my case is Wags Lane because that's the

uh user on my machine um and then colon

and then password if you have a password

for your local database this is where it

goes I actually did not set one up

because it's just my local

database and it's going to be at Local

Host col5

432 which is the standard port for

postgress and the last part of the URL

is just going to be the database name uh

that you created so in my case I believe

it was RSS a okay so your url will

should look very similar to this with

maybe you know the username the database

name um something like that could be

could potentially be swapped out on your

machine okay to run our migration here

I'm going to copy I'm going to copy this

database URL

and then I'm going to CD into this

directory so CD SQL

schema and then from here I can run

Goose

postgress so I'm telling I'm telling

Goose that hey I'm using a postgress

database and then I'll paste in my

connection

string and type up so this will run the

up migration a nasty error here turns

out I forgot some commas we need to

separate all of these field names with

commas cool save that file let's try

again so we got okay 001 users. SQL no

more migrations so that should have run

let's check PG admin to make sure that

it worked so now over in PG admin under

my RSS a database I should be able to

come into the schemas tab the tables tag

and I can see here that I've now have

two tables Goose DB version so this is

an automatic table created and managed

by goose and then I've got the users

table that I just created let's go ahead

and do a select star from users and we

should just be able to see uh those

column names come back now let's make

sure that the down migration works as

well go ahead and run the exact same

thing but this time down instead and you

can see that it down migrated the same

file now over in PG admin if I

rightclick on tables and click refresh

you'll see the users table's gone and

this query should fail now okay so let's

reup migrate to get that database table

created again and then the interesting

thing about migrations is you can rerun

the same up migration and you won't get

any errors because Goose knows that

you're already migrated up to the most

recent version of your migrations now

it's time to write a query so we're

using sqlc to handle our queries and

Goose to handle our migrations so to get

sqlc set up we need to create a new file

in the root of our project called sqlc

do yaml I'm going to paste in this

configuration here basically it's just

telling sqlc what version we're using um

what database engine we're using and

where we're going to store our queries

the raw SQL for our queries are going to

live in the SQL directory under a new

subdirectory called queries we've

specified that here right and here I'm

going to create a new file I'm just

going to call it users.

SQL and again this is where the SQL will

live and the way sqlc works is that it

takes the SQL statements and it

generates go code Type safe go code that

matches the SQL every sqlc query starts

off with a comment that starts with its

name so name will do a create user

statement and it returns one record so

we're saying I want a new function

called create user oops and it's going

to return one user that statement will

be insert into users uh ID created

Created at updated at and

name

values dollar sign

one dollar sign 2 dollar sign 3 dollar

sign 4 okay so what's this nonsense

right in sqlc each dollar sign number is

interpolated with the parameters for the

function so this statement will create a

new function called create user

with four parameters and the first

parameter will will go in right here the

second one the third one the fourth one

Etc so it allows us to create queries

that take arguments as input and then

we'll end the query with just return

returning

returning star okay we want to create a

new user and return that record right we

we expect one record back now let's use

sqlc to actually generate the go code

for this query we always run sqlc from

the root of our package rather than

within the query's directory itself um

and the reason that works is because we

have this sqlc do yaml file at the top

level okay so if everything was written

correctly we should be able to do sqlc

generate and what happens is it goes and

reads that query and it also reads our

table

definitions which we've specified here

right SQL schema so it knows the shape

of our tables and it knows the query we

want to create and it can go

automatically generate all of this go

code in the internal SL database package

now we need to actually use the database

in our go code so here in main.go I'm

going to create a new struct called API

config and it's going to hold a

connection to a database now this

database. queries type is actually

exposed by that code that we generated

using sqlc so you can poke around

through this package and kind of get

familiar with the generated code we

never manually update this code that's

generated by sqlc it's completely

managed by sqlc we're just going to

write raw SQL to generate this code okay

uh next thing we need to do is import

our database connection so here in EnV

we have our DB URL and we need to

grab that um and pull it into our

application we're also going to need to

disable SSL mode so SSL mode equals

disable um and it just this just tells

our code hey we don't need to be

connecting to our local database um

using encryption uh we kind of trust our

local database so we'll parse that as a

string so I'll do DB

URL and if the database URL is not found

then

we'll we'll report a message uh or we'll

log an error message and exit after that

we need to actually connect to the

database so the ghost standard library

has a built-in SQL package we can do SQL

doop the driver name that we'll be using

is just

postgress and then we can pass in the

connection string and this will return a

new connection and an

error and again if there's an

error we'll just go ahead and log a

message and

exit can't connect to

database now this is kind of a weird

quirky thing about how go handles

databases but we actually need to import

a database driver into our program um

but we don't actually need to call

anything from it so the sqlc docs

mention this but basically we just need

to include this line at the top of our

program and we do need to import it so

I'll do a goget um on that

libpq and we'll import it using that

underscore just to say include this code

in my program um even though I'm not

calling it directly okay with that there

uh now we should be able to create a new

API

config and let's just call it API

CFG and it takes as one of its Fields a

DB

where am I at I think I scrolled too

far BB oh and I should probably go mod

tidy and go mod

vendor so that I stop getting weird

errors in my in my vs

code okay uh this API CFG takes a

database. queries but if you look here

we don't have a database. queries we

have an SQL DB so we actually need to

convert it into a connection to our

package and we can do that with

database. new and we pass it as input

the connection and we'll get back

queries

eror here we can say if er do not equal

nil and pass in the queries

to the

struct no did I do that wrong maybe this

doesn't return an

error mismatch two variables but

database. new returns one okay cool so

this actually can't fail it's just a

it's just a simple

conversion we could actually even just

do this it's probably

easier great now we have an API config

that we can pass into our handlers so

that they have access to our database

let's write that create user Handler

okay so I'm just going to copy paste

this Handler Readiness and change it to

Handler

user and we'll update this to say

Handler this will be the create user

Handler now here's the interesting thing

about HTTP handlers in go the function

signature can't change but we do want to

pass into this function an additional

piece of data we want

to add this API config so the way we do

it is by making this function a method

so we do API

CFG is a pointer to an API config so our

function signature Remains the

Same right it still just accepts these

two parameters um but now we have some

additional data stored on the struct

itself uh that we can gain access to and

let's hook up this create user Handler

in

main so we'll add it to the V1 Handler

we'll do V1 router Dot

post we want this to be a post request

to/

users and we want to use

the create Handler create user method

which we defined on this struct so we

can pass in API CFG do Handler create

user and now our Handler will have

access to um to the database okay

cool this Handler needs to take as input

a Json body it should

expect some parameters so we'll do type

parameters is instruct and I think for

now we just need a

name and we need to parse the request

body into this struct so we'll do json.

new

decoder and r.

body okay and this respond or this

returns a decoder

we do decoder do

decode and we want to decode into an

instance of the parameter struct so

we'll do prams is an empty parameter

struct and we'll decode

into a pointer to parameters and this

returns an error if anything goes

wrong if there is an error then we

should use that Handler function that we

made earlier respond with error and say

something like well we need to pass in W

um if something goes wrong here it's

probably a client side error right so

I'm just going to pass in a

400 and we'll

say

[Music]

um let's see error parsing

Json cool and then we'll return because

we're done at that that point if there

is an issue okay uh otherwise we have

access to a name so we can use our

database to create a user so we do API

CFG do

db. create user now this is the method

that sqlc generated for us right because

it it read our create user SQL and it

created a create user function for us

right and it created the parameters as a

struct so that's pretty

convenient uh let's see how this works

so create user accepts a context and

some create user pram so I'm going to

use uh I think

it's CTX no r. context there we go so

that's the context for this request and

then we pass in database. create user

prams this is struct and it should have

yep all of our uh types that we need to

pass pass into the create user function

okay so uh first things first an

ID the ID is a

uuid um and this is the first point at

which I think we've needed to use them

so we're going to have to import this

package so github.com gooogle uid this

is a very uh well-known uuid package in

go we will go get

it with that installed we should be able

to do you uu id.

new and that will just create a new

random uuid and if you weren't familiar

this is what a uu ID looks like in

string form it's basically just this

really long random uh bit of I mean in

this case represented as text that we

can use as a primary identifier for

every user so every user will get their

own random

ID cool um I should probably go mod tidy

go mod vendor

it's just good practice every time you

install a new package to make sure you

vendor it and go mod tidy kind of cleans

up any unused Imports um and resolve

some issues

there okay uh created at I'm going to

set to just time. now.

UTC created now and then updated at

should represent the last time it was

updated uh which would also be now right

because we're creating something new and

the user's name will just be pam. name

right it's whatever was passed in

to this HTTP request in the

body oh and I just am now realizing that

I messed up this Json tag should look

like

this okay cool um so create user should

probably return an error yep returns a

new user and an

error again if there was an error

creating the user we'll want to respond

with an

error and we'll

say good

create

user uh 400 seems fine and then we'll

actually respond with the user object

itself okay database. user and see how

that goes well let's let's actually take

a look and see what does a database.

user even look

like I'm

curious yeah so all these I mean all

these fields are exported so they should

Marshall to J on just fine let's go

ahead and run this and see and see what

we get before we run the code though it

looks like I've got a couple little

things to resolve here so errors is

already defined there and then here oh

I'm messing something up we need to pass

that in we need to interpolate that cool

oh and here as

well percent V because those are errors

okay cool um now let's go ahead and run

build and run the code so go build

and run RSS a

okay Ser server has started so let's go

ahead and open up the Thunder

client and now we'll be sending a post

request to the users's

endpoint and we'll be sending in a Json

body oh me grow this just a little

bit and we need to specify a name I'm

going to create a new user called Lane

and let's see what happens couldn't

create user database Wags Lane does not

exist it looks to me like I probably

messed up my connection string let's go

take a look at

that so here in

EnV yeah okay we forgot to or I forgot

to add um the name of the database here

at the end so uh we we need to do slash

name of database all right let's try

that again let's rebuild the server

and resend that request cool we got a

200 response it looks like that is a new

random ID great created at update at and

the name next just to make sure that the

record actually was created in the

database server itself I'm going to pop

back over here to PG admin um refresh my

tables there's our users table and rerun

this select star from users perfect

looks like we've got one record in here

with all of the data that I would expect

now I want to make one more optimization

to our code here you can see in this

Json response that the Fe the key names

in the Json object are the same as the

exported key names here in the user

struct in the database package now we

can't change this struct manually um

again this is generated by sqlc so what

I think we should do is instead create a

new models folder models. go

in the main

package and here we'll create our own

user type so type user struct and it

will be nearly identical so let me go

grab this one be nearly

identical the only difference at this

point is that I'm going to add Json

tags so that I can specify you know what

these names should be and we've been

using kind of this snake case convention

so I'm just going to stick with that so

updated at and name and I'm going to

create a function uh we'll say database

user to user and it will take a DB

user and return a user and all this does

is return a new user struct where uh

we've kind of populate it with all of

the all of the stuff from the database

user so again the purpose of this is

really just I want to own the shape um

that's being returned over the wire

right on our HTTP responses um and now I

have the power to configure that easily

within within my

application so we'll go ahead and just

uh paste these in

here okay and then in my user Handler

rather than responding with the database

user I'm going to respond with our

user cool let's rerun and build

that and let's run our query again now

remember we already have a user in our

database so I'm going

to create a second one uh let's call

this one

Rob and this time you can see we have

those snake case

keys and again I'm going to go check in

PG admin to make sure that Rob is there

perfect now we've got Lane and Rob and

you can see they have different randomly

generated IDs and their timestamps are

slightly different we're going to be

using API keys to authenticate our users

on This Server the nice thing about an

API key is Not only is a little more

secure than a username and a password

but because it's so long it also serves

as a unique ID for that user so we don't

even need a combo of username password

we can just use the API key in order to

kind of uniquely identify people so we

need to run a migration that adds a new

field to the user's table so that we can

store their API Keys now we've already

created this migration that creates the

users's table and we don't want to

modify this because it's generally a

really bad idea to go modifying your

existing migrations instead we create a

new one so I'm going to create a new one

and we'll call it 02 because we want it

to run after uh the first migration and

again Goose uses these numbers to know

in which order it should run uh the

migrations and we'll call it users API

key and the migration statements are

going to look a little bit different

okay so the up statement is going to be

an alter table so alter table users

We'll add a

column and we'll call the column just

API uncore key it's going to be a varar

so

varar 64 now the difference between

varar and text um at least for our

purposes here is that the varar is

exactly 64 characters long so we're

saying we want our API keys to be 64

characters long and we want those API

keys to be unique no two users should

have the same API key um we also don't

want them to be null and we're going to

set a

default a default API key and this is

important because if we didn't set a

default we'd run into an issue when we

run this migration remember we already

have two users in our database currently

so if we just try to add a column that

has these unique not null constraints on

it then what's the SQL database going to

do how is it going to generate new API

keys that are unique and not null

typically it would just default the new

um you you know the field in the

existing records to null but because

we've said they can't be null and they

must be unique we need to provide a

unique unique default for every new

record or for excuse me for every

existing record in the database so the

default value that we need to add again

needs to be unique for every person so

we're actually going to have to use some

random number generation so that we can

generate a unique API key for every user

and this is the snippet of code that

does that again you can go grab this in

the text instructions for this project

over on bootd but let me explain

basically what it's doing we're

generating

some random byes and then we're casting

it into a bite array and we're using the

shaw 256 hash function to get kind of a

a fixed size output so we're saying take

a a big random slice of bytes hash them

with straw 256 so that we get a fixed

size output and then encode it in

hexadecimal and that's so that we get 64

unique heximal characters this makes

more sense when we actually run the

query and you see what the output looks

like and then as far as the down

migration goes we just need to alter

table users and

drop column API key again down

migrations should just undo whatever was

done in the up migration let's go ahead

and run this migration so I'm going to

need to change directory into

SQL uh

schema then we'll run goose postgress

then let me go grab the connection

string now we do need to peel off this

SSL mode disable Goose doesn't need that

um just our code needs that so I'm going

to grab the rest of the string and we'll

run an up

migration cool so it looks like it ran

successfully let's go see if those

default values look good run the select

star statement and there you can see the

new

AES so big old heximal strings that

uniquely identify every user and should

be kept secret by the user because just

the API key is enough to authenticate

the user now that we've got our

migration and we've updated our schema

we actually need to go update our query

right we need to be creating new API

keys for new users so let's go update

our create user function it should now

accept an API key as the last

parameter and pass it in here

actually you know

what if we do it this way we're

basically telling our application code

hey you need to go generate an API key

in the same way that we generated it

here in our SQL I think it would

actually be easier what if we just take

this and plop

that in

here right so now we'll use we'll use

SQL to generate the new API Keys we

don't even need to update the function

signature of our create user function

cool so the SQL will just handle the

creation of new API Keys every time a

new user is created all right now we

should be able to

run sqlc

generate insert has more Expressions

than Target columns let's

see oh right sorry we we do still need

to pass in the API key as the column

name um the difference is because we're

not using dollar sign 5 our function

signature won't change this got a little

confusing I was reading it like a

function signature even though it is it

is SQL okay run that again it went off

without a hitch you can see it updated a

few files in our database package now we

should be able to go use that in our

code but before we test our server let's

add one more thing let's give us a way

to get a user so we'll create a new

function and this one we'll call get

user by API key it should return a

single row

and it's going to be a select statement

so select star

from

users

where API key equals dollar sign

one and we'll run sqlc generate again to

generate the code for that query you can

see it created it here so in our Handler

user function we actually don't need to

make any changes to our create user

Handler right right we didn't change the

number of parameters that we need to

pass in for the API key it's handled

kind of under the hood by the SQL query

but we do need a new Handler for getting

users so let's go ahead and add

that so I'm going to copy paste that do

Handler get user by API

key maybe we can just let's just

simplify this let's just call it Handler

get

user now this Handler is going to look

very different

this is an authenticated endpoint so in

order to create a user on our API

basically to register a new account you

don't need to have an API key but if you

want to get your own user information

you have to give us an API key first

this isn't going to be the only

authenticated endpoint or the endpoint

that you can only do if you're logged in

um so I think it makes sense to kind of

abstract the logic for getting a user by

their API key into a package so under

the internal package here where we have

our database code I'm going to create a

new package and we'll just call it

o and in there I'll create a new file

we'll call it o.o and this whole package

will just be called

off now the only function that we care

to export in this off package is going

to be this one called get API key and

its purpose get API key key will'll say

it

extracts an API key from the headers of

an HTTP request so it's going to go into

the headers look for a specific header

and see if it can find the API key if it

can it'll return it otherwise it will

return an

error now as the authors of This Server

we get to decide what we want the

authentication header to look like so

I'm just going to

say um example

let's expect an authorization header so

the key of the header will be

authorization and the value will be API

key and then some you know like insert

API key here okay so we're looking for a

header of this

format so first let's look and see if we

can find a value associated with the

authorization key um we're just using

the HTTP standard Library here so we can

do headers do

getet authorization and this should

return let's see a string okay so the

value associated with this with this

header key now if value is the empty

string then we can just say uh turn

empty string and an error say errors.

new no authentication

info found so otherwise we have a valid

value so we could do something like this

uh

vows strings.

split

vow okay so strings. split takes a

string as input and a delimiter so we're

going to say we want to split this

string here right the the value given to

us uh by the auth authorization header

uh we want to split on Spaces okay so

next we can say if the length of

vals does not equal

two then again we can return an error

saying like you know maybe

malformed malformed a header right

because we're expecting that the value

of this key is two like two specific

values separated by a space the first

should be API key and the second should

be the API key right the first should

just be the string API key and the

second should be the actual API

key okay so if the length is wrong then

uh next we should probably check and

make sure they typed this in correctly

so we can say uh if vals at zero does

not equal API

key malformed offhe

header we could say malformed first part

of offhe header okay

otherwise we can just

return B at one and no error

right because by that point we sure that

all all this part was correct and we're

extracting just the API

key okay what did I screw up here

errors. new oh right you're not supposed

to capitalize errors in go that is a a

linting error

a stylistic error Okay

cool so now we've got the get API key

function we can go ahead and use this in

our get user Handler so let's go ahead

and grab that API key so API key and

error o. getet API key and we pass in

the HTTP headers so r.

header perfect if there is an error

let's handle it

we can just respond with an error

saying off

error and 400 we should probably do like

a 403 and in fact now that I'm thinking

about HTTP codes creating a user

probably should be a 2011 instead of a

200 like you probably won't run into any

issues for using a 200 um but 201 is the

created code so it's like a little more

correct uh if you're looking at it from

kind of a rest full HTTP standpoint and

then 403 um is one of these kind of

permissions errors so that should be

good okay now that we have an API key we

can use our database query that we

created. get user by API key again we'll

pass in the requests context and the API

key I haven't really touched on this

yet in go um there is a context package

in the standard library and basically it

gives you a way to

track something that's happening across

multiple go routines and the most

important thing that you can do with the

context is you can cancel it so uh by

cancelling the context it would

effectively kill the HTTP request I

don't want to go too much into detail on

how all of that works here um you could

definitely go read up on it um but for

now just make sure that it's important

to kind of use the current context so

every HTTP do request has a context on

it and you should use that context um in

any calls you make within the Handler

that requires a context just in case uh

kind of cancellations happen Okay cool

uh that returns a user and an

error again if there is an

error Let's do let's use a better

uh string here

maybe couldn't get

user and this one let's just go with a

404 or a 400 for

now cool um and then we can respond with

Json this time it will just be a 200

code and again we should cast that

database user to the user uh model that

we defined here right with the the

nicely formatted Json tags and that

should be good okay let's hook up our

get user

Handler to our

router so here we'll do V1 router. getet

so same path SL

users but we'll be hooking up the get

user Handler to the get HTTP method so

again same path different method all

right let's test our new

endpoint um first I'm going to go ahead

and rerun sqlc generate cuz I can't

remember if I've done that and then

we'll build and run the

server okay with that running let's head

over to thunder

client and first let's create another

new

user so Json body me minimize this a

little

bit um let's keep create a new user

we'll call him

Rand and it'll be a post request that

looks good

okay response came back Rand was created

and this is rand's ID ah we screwed

something up we are not responding with

the API key let's go update

that so here in our model I believe it's

because we're not casting so we need API

E

string

bason API

key and then

here need to do that conversion so this

just getting dropped because we weren't

we weren't setting the API key

anywhere okay uh let's

rebuild and we'll create a new user

let's call this one

Joe Okay cool so Joe was created and it

actually returned the API key perfect

now let's go ahead and I'm going to

create a new request

this one also to Local Host

8080 slv1 users but this one will be a

get and we're going to add some headers

or specifically one header right we're

going to add our authorization header

and its value will be API

key and then the actual API key just

paste it in

there okay let's go ahead and run that

and it it's returning Joe it's good to

test failure cases too so let's just see

what happens if

we update this header and let's just

like let's just make something broken

let's just remove a section of the API

key and see what

happens cool we get a 400 batter request

couldn't get user SQL no rows in the

result set so essentially user is not

found perfect so we've got our users set

up and our authentication system now

it's time to actually get to some

business logic right this this is an RSS

feed aggregator so we need a way to

store feeds let's create a new schema or

rather a new migration in our schema

folder this will be O3 we'll call it

feed feeds dsql now this is going to be

a create table migration right we want

to create a feeds table so we'll do

create table

feeds now a feed and the drop will also

drop the feeds table a feed has an ID

just like a user um it also has a

created at and an updated at and it also

has a name like all of that is actually

very similar um what's unique about a

feed is it has a

URL uh which is text as well that is

unique and not

null and it also has a user

ID which

references sorry it's a user ID is a uu

ID which references

users ID and we'll also add the on

delete

[Music]

Cascade essentially what this does is it

says we have a user ID stored in our

feeds table that

references the ID of a user in the user

table right so this is this is

relational data this is a relational

database um essentially what this means

is if we try to create a feed for a user

ID that does not exist in the users

table we'll get an error uh which is

what we want because we don't want feeds

to be able to exist without a user who

created them and then this on delete

Cascade bit just says when a user is

deleted I want all of the feeds

associated with that user to be deleted

automatically it will Cascade and delete

all of them and let's run this migration

so I'm going to hop into the SQL schema

directory and from here we can run goose

postgress postgress and Gra my

connection screen again we don't need

the SSL mode stuff for goose grab the

rest of it and up cool now over here in

PG admin I can do a select star from

feeds and make sure that that table

exists with those fields next we'll need

a query to create a new feed so I'm

going to go ahead and copy this queries

file update it to feeds then we'll

delete this one because we don't need it

and we'll create a create

feed and insert into feeds ID created at

updated at name there will not be an API

key but let's see we need a name URL and

user ID okay name

URL user

ID we won't be generating an API key

here instead all of these values I think

we'll just be passed in from our

application code so 1 2 3 4 5 6 we need

six parameters for this function five

and six and then we'll just return uh

the entire feed row after it's done

being created and then I'll just

navigate back to the root of the

project and run SQL sqlc

generate to create the code for that new

query next we're going to create a new

Handler that will allow users of our API

to create a new feed here's the thing

that hand is also going to need all of

this same

logic that we have in the get user

Handler right we'll need to grab an

authentication uh token or an API key

from the authorization header fetch the

user and then use that user in the

Handler and rather than copying and

pasting uh this what 10 lines of code

into every Handler that's authenticated

instead we're going to build some

middleware to kind of dry up the code

right um let's go ahead and do that so

I'll create a new file I'm going to call

it

middleware

of.go art of the main

package and here we're going to define a

new type and it's our own custom type uh

I'm calling it off Handler and you'll

notice it looks almost exactly like a

regular HTTP Handler the only difference

is that it includes a third parameter it

has a user associated with it so if you

think about this um it makes a lot of

sense uh for any authenticated Handler

to accept three parameters where the

third one is the authenticated user now

the problem with this off Handler type

that we created is that it doesn't match

the function signature of an HTTP do

Handler Funk right uh those functions

with just the response writer and the

request as the only two parameters so

what we're going to do is create a new

function called middleware off uh that

works it's a method on our API config so

it has access to the database um but it

its job is to take an off Handler as

input and return a Handler Funk so that

we can you know use it with the CH

router okay let's Implement that the way

this function will actually work is

we're going to return a closure so we're

returning here a new Anonymous function

with that same function signature as

your normal HTTP Handler funk the

difference is that as we Define this

function we'll have access to everything

within the API config so we'll be able

to query the database so we can

basically just go rip out the code from

our get user Handler and paste it in

here right we're going to go get the API

key from the request well from the

request headers at least and then we can

go ahead and grab uh the user using that

API key

right so we'll have access to the user

here in the function finally all we need

to do is run the Handler that we were

given with the response writer the

request and the user right so by the

time we get to actually calling the a

Handler we're able to give it an actual

user from the database and this is

really great let me show you why so now

that the middle middleware o function

exists we can remove all of this code

from the get user Handler we can update

the get user Handler to accept as

input a database

user user database.

user look at how clean this function

becomes right now it's just now it's

literally just one line cool and now to

hook it up you'll notice we have an

error over here we just need to call our

middleware off

function apic CFG do middleware

off we call this function to convert the

get user Handler into a standard HTTP do

Handler funk I kind of move fast through

that hopefully it all make sense though

basically we're just calling the

middleware off function first to get the

authenticated user and then we're

calling that call back the the get user

Handler the nice thing is now we'll be

able to reuse that middleware across

many different HTTP Handler functions so

now let's create the create feed Handler

I'm going to go ahead and just copy this

Handler user change it to Handler

feed and for now we just need a create

function so I'll delete this get and

we'll call it

Handler create

feed and remember it's an authenticated

endpoint so we can have it accept the

user directly so user database. user

we know who's creating the feed by the

time we get to this function which is

awesome all right in order to create

create a feed use our new create feed

function which takes create feed

pams and create feed pams have ID

created at updated at name that's all

the same the difference is a URL and a

user

ID so

URL and a user ID which is a U ID uh

which actually exists already on the

user object so we can just do user. ID

okay um what do we want as input we need

a URL so we also are going to want a

prams

DOL so we want the user that's creating

a new feed to be able to just send us a

name and a URL and we'll go about

creating the entire uh kind of you know

feed object in the database or feed Row

in the

database so this is what our parameters

should look like uh what error am I

running into here cannot use API cf.

create

feed no new variables on left side of H

that's odd create feed should return a

feed let's take a look at that

definition yeah it does return a feed

what am I messing up

here oh first of all that shouldn't be a

user that should be a feed okay that's

the problem I was over I was trying to

overwrite the database. user type with a

feed type that won't

work okay so we're creating a feed we're

generating a new uid that's great we're

using the current time perfect um this

is getting messed up uh variable of Type

U id. uid as uu id. null U ID ah okay I

see the problem the create feed

pams except a uu id. null uuid that's a

problem we don't ever want a u the null

uuid type from the uid package is a

nullable uuid but we don't want it to be

nullable because we expect that every

feed will be created by a user so let's

go update

our our uh I think it's our is it our

migration let's go look schema

feeds yeah user

uid not

null cool it doesn't need to be unique a

user can have multiple feeds but it

should never be null all right um with

that we're actually going to need to

go uh rerun our migrations so

SQL um

schema and we'll do a down to drop the

table

down and then back up to create the new

table with the proper

schema and then we should

rerun SQL C

generate okay did that

work create feed create feed pams looks

like that error is gone it's now just a

uuid type perfect now at this point we

have a valid database feed should

probably update this error so that it

actually says feed um and we want to

return it um in our HTTP response

trouble is remember we don't want to

just directly return the struct let's go

create a new model for a

feed so we'll do

type feed and then I'm going to go just

copy the types from here and we'll use

those and we'll make our own Json tags

for the type

user

ID

URL name updated at and create at okay

and then we'll want

a what is it database

database feed to feed

and we'll return a

feed all of this should be pretty

straightforward and again this just

gives us more control right now we in

our code that's not generated by SQL c

um are able to Define you know what the

shape of the response will look like if

for whatever reason we needed to store

some data in the database but never

wanted to respond with it in our Json

API we could make those changes here in

this struct okay so now we've got

database feed to feed we'll call

that and now we should be good to go all

right let's test out our new Handler so

going to rebuild our server and run

it and over in the Thunder client let's

see so we just created a new user Joe so

we have our authentication key here or

our API key going to do a new request to

http

localhost 880 slv1 feeds ah now that I

type this out I realize that we never

hooked it

up let's go hook up that feed so feed

Handler Handler create feed we need to

go paste this in

to the main function so this one will go

under slash feeds because we're creating

a resource we're going to use a post

request Handler create

feed okay that should be hooked up now

let's uh restart our

server and over here again I need to

grab that API key all right

what do we want here post

request Local Host 8080 V1

feeds we do need to authenticate again

so qu

headers

auen

authorization API

key paste in that API

key okay uh what do we send in as the

body

let's take a look at our Handler again a

name and a URL okay so name now remember

this is this is this is not a person

this is a feed right and a feed is a URL

that kind of links to an RSS feed out on

the internet so this one I'm going to

put just uh Lanes Lan's

blog and then the URL is going to be

https

tags lane.

deev SL

index.xml so in case you're not familiar

with what an RSS feed is let me just

show you really quick um I'm here on my

blog Wags lane. deev and if you click

RSS up at the top it'll take you to my

RSS feed now every RSS feed um will have

a different URL it's kind of up to the

author of the blog or the podcast what

that feed URL is but you can usually

find it by poke looking around on their

website so in my case um it's just

waglan dodev index.xml and it will look

something like this if you open it up in

a browser it's basically this structured

XML document that describes what each

post on the blog says at least from a

high level it'll usually have something

like a link to the post maybe a short

description um basic stuff like that

again podcasts also work on the same RSS

structure so for testing you can use my

blog or if you know of any other RSS

feeds um out on the web you can use them

so now that I've pasted in that URL uh

let's go ahead and create that

feed and what do we get

back cool the feed's got a new URL

created at updated at the name and the

URL seem to have persisted correctly and

that is the user ID associated with the

API key that we use to create the feed

next we're going to add the ability for

any user to get all of the feeds in the

database this is not an authenticated

endpoint okay so we need new query I'm

going to go ahead and use the same file

um this query will just be called get

feeds and it will return many rows

instead of just one all right and this

one will be uh

select star from

feeds super super simple query here

we're just going to go grab all the

feeds and return them okay um from there

we should be able to sqlc

generate and let's go hook up that

Handler I'm going to use the same uh

Handler feed file U but this one will be

a little bit

different we going

to call this one Handler get

feeds it's not authenticated so we don't

need to pass in a user and it doesn't

even take any parameters right it's just

going to go get all of the feeds so um

apic

cfg.init' to return all of the feeds

this is not a single feed this is now a

slice of database. feeds so not only do

we need to return them but we need to

actually convert them so let's go update

our models a little bit let's create a

new

function this one will be database feeds

to

feeds and the difference is it will

accept a slice of database feeds and it

will'll return a slice of

feeds let's let's do this slice feed

we'll create a new empty slice of feeds

and then

four DB

feed range DB

feeds feeds equals

append

feeds database feeds or database feed

and return feeds sorry not we don't want

to append it directly we have to we have

to call our conversion function okay so

this function will just iterate over all

of the database feeds one by one

converting them into our new feed

structure and then returning them cool

now here we can use that

function to do that

mapping great let's hook up this Handler

so in main.go we'll create a new entry

here this is going to be a get request

and it's not

authenticated it will be

Handler yet

feeds cool let's regenerate I can't

remember if I generated my SQL C so I'll

do that couldn't hurt and then we'll

build and run the

server okay with that running let's go

ahead and create a couple more RSS feeds

so

here update the

body of my request sorry I'm so zoomed

in so that you guys can see and it just

makes it

hard um no this was to create users this

is users here's

feeds okay let's let's just add the same

URL with a couple well no we can't we

can't add the same URL let's just use

some garbage URLs just to test

all

right okay that created properly now

let's test our new

endpoint this one is going to be a get

request to feeds and we don't need to

add any authentication information okay

run

that awesome this looks good to me we've

got an array at the top level and then

two feed objects one for garbage blog

and one's for one for Lane's blog so it

looks like everything's working so we've

given users a way to create feeds and a

way to query all of the feeds now we're

going to give users a way to follow

specific feeds so that they can see kind

of an aggregated view of all of the

feeds that they care about on the system

okay so uh let's go ahead and add a new

migration we need a new table so this

will be the fourth migration and we'll

call this new table feed follows and

this table is just going to store the

relationship between a user and all of

the feeds they're following so it'll be

a many to many uh kind of table of user

IDs to feed

IDs all right um the table is going to

be called feed

follows so create table feed follows

every feed follow like every other

record in our database will have an ID a

created at and an updated at but its

unique Fields will be a little bit

different first it's going to need a

user

ID which is

is oh my gosh why can't I type fingers

the wrong place in the keyboard so a

user ID is a uu ID um that can be it

doesn't let's see it doesn't need to be

unique um but it does need to be not

null then we need a feed

ID also a uu ID not null and then we're

going to create a unique constraint on

the comb ination of user ID to feed ID

so

unique user ID feed ID so again this

constraint is going to make it so that

we can never have two instances of a

follow for the same user feed

relationship right you as a user can

only follow a certain feed once you

can't follow it twice that doesn't

really make sense right so we're going

to ensure that that's unique um also so

I missed a couple things here the user

ID uh should reference so

[Music]

references uh the users

table ID field and on delete we'll

Cascade so if a user is deleted we're

going to go delete all of the data about

what feeds they're

following um and then this one's going

to be very similar except it references

the feeds table

with its ID and again if a feed gets

deleted then we'll go delete all of the

following data related to that

feed cool okay let's go ahead and run

this migration so I'm going to go back

up into the SQL or I should say back

down into the SQL schema

directory and from

here I'll need my connection string do

goose

postgress connection string

ah I didn't grab the whole thing let's

try that

again all of that boo

postgress

up cool feed follows databases or feed

follows table is there so now we need a

way for users to follow feeds all right

let's go ahead and go create that so I'm

going to copy and paste the feed Handler

file and we'll call it

Handler feed

follows and update this so Handler

create feed follow so remember in order

for a user to follow a feed all we need

to do is create a new feed follow record

with that user feed

relationship okay this is an

authenticated endpoint right we so we we

need a user and we need them to be

authenticated have passed an API key

right and let's see what do we need them

to give us as input I think all we need

is a feed

ID right they just need to tell us which

feed they want

to

follow so a feed ID is a uu

ID all right and now we should be able

to create feed oh we we never we never

made we never made the squl query what

am I doing what am I doing I'm getting

way ahead of myself let's go add that

query quickly so

feed follows

and to start we'll need a create feed

follow okay what's in a feed follow

right got all these all of these fields

and I think yeah we're just going to

have them all past in directly that

seems like the easiest way so insert

into feed

follows ID created at updated

at user ID feed ID

that's five parameters right one two

three four five cool that looks

good now I should be able to go back and

run sqlc

generate cool now I should

have

a create feed follow function with

create feed follow

pams all right it accepts a user ID and

a feed ID so the user ID is just the

auth authenticated user the feed ID is

going to be passed in his params

right cool couldn't create feed

follow don't need a get Handler quite

yet and then we're going to just need to

make uh make that uh mapping function as

well for feed

follows so in our models file I'll

create a new feed follow struct and it's

going to have a user ID and a feed

ID and a new function database feed

follow to feed follow

all right DB feed

fall. by the way I'm not using GitHub

co-pilot in this video just so that you

could just just so you can see more of

my thought process um but I typically do

use GitHub co-pilot

and it makes this kind of function just

like way faster to write um it would

guess this kind of function almost

perfectly um so just so you know I I do

recommend those kinds of tools to speed

up the development process um I'm just

not using it uh right now so that you

can see how I think through you know

architecting this this application

without all the AI prompts getting in

the way okay now we should be able to

database feed follow to feed follow and

we're going to be clear that this is a

feed follow not a

feed and that goes

there

Perfect all right let's hook this up so

we're going to need to go into main.go

V1 router. poost is we're creating a

resource slash feed

follows and this is an

authenticated authenticated

Handler Handler create feed follow okay

let's test this new endpoint so we'll

build and run the

server and we'll need a new

request this one will be kind of similar

it'll

be oops a post request to the feed

follows end

point and we're going to need to

authenticate so let's go grab some

authentication

information let's see get users let's go

ahead

and send this couldn't get user sequel

no result okay I need to figure out what

users I have available to me oh that's

right we we changed this API key we

wanted it to break let's go create a new

user we'll make a new one

called uh Billy

and there's Billy's API

key cool we've got some

feeds but our feed

follows need an off

section sorry in the

headers we're doing it

manually

authorization API key there's Billy's

key and then in the body we need to pass

in the ID of the feed that we want to

follow so so let's do a get on all of

the feeds and we can follow either of

these let's follow Lane's

block there's our feed

ID paste that in there and

create amazing new ID for the feed

follow there's the user ID the feed ID

what happens if we try to recreate it

cool couldn't create feed follow

duplicate key value violates unique

constraint that's what we'd expect right

we shouldn't be able to follow the same

feed multiple times we're already

following it we already have a record uh

indicating that we are following it

everything appears to be working just

fine next let's give users a way to see

all of the different feeds that they are

currently following so we'll do get feed

follows and it will return

many and the query will be select star

from

e follows where user ID equals dollar

sign one right so get all the feed

follows for a given

ID let's get that hooked up need to run

SQL C generate to create that query and

then down here we'll create a new

Handler this Handler will also be

authenticated but it's going to be get

feed

follows have the user we don't need any

parameters

here and we're just going to call get

feed follows and we'll just need to pass

in the user's

ID couldn't get feed

follows cool now we've got a list of

feed follows or a slice of feed follows

so we're going to need to convert an

entire slice so again here we'll write

this type of a function it's going to be

database

feed

follows to feed

follows all right

lots of copying and pasting here feed

follows okay so now we have a way to

convert an entire slice of database feed

follows to our own

struct that looks good to

me there feed

[Music]

follows okay cool now we have a Handler

for getting feed follows let's go ahead

and update this

so we need a new V1 router.

getet SL feed

follows middle wear

off get feed

follows Perfect all right let's give

that a

shot so we'll build and run again

and now let's see so this is um this is

the request that we used to

create so let's

grab oh so hardworking on such a small

screen let's grab our API key and create

a new

request 80 slv1 feed follows it's going

to be a get request it does need to be

authenticated okay see if that

works cool we got the one feedback that

we are currently following finally we

need a way to unfollow feeds or to

delete feed follows so let's create a

new one new

query we'll do delete feed follow now

this one is going to be our first quy

that doesn't actually return

anything um it's just going to be an

execute right we're not returning one

record we're not returning many records

we're returning no records we're just

going to run a a SQL query so uh it'll

it's going to be

delete

from bead

follows where ID equals dollar sign one

and user ID equals sign too now it's

important it's important to point out

that we don't actually need the user ID

here for this query to work right the ID

is already a unique identifier the

reason I'm tacking on this user ID is

because this will prevent someone who

doesn't own a feed follow from trying to

unfollow a feed on behalf of somebody

else that makes sense uh if for whatever

reason another user

got access let's say if if for some

reason user B got access to the feed

follow ID of user

a if we didn't have this check here then

that user who hijacked a feed follow ID

would be able to like

unfollow like force the other user to do

an unfollow if that makes sense this

ensures that only the user who actually

owns the follow record can execute the

unfollow Comm command hope hopefully

that makes sense okay uh from here let's

just go ahead and generate

that and go hook it up to a new

endpoint so we'll do

Handler delete feed

follow now this one's going to be a

little

different in that it it is authenticated

but we need to get a feed follow ID and

delete requests so like HTTP delete

requests the delete HTTP method they

don't typically have a body in the

payload it's it's possible but I would

argue it's not super conventional um

it's a little more conventional to pass

the ID in the HTTP path so um it's going

to look something like

this view on router. delete feed follows

slash

feed follow

ID and then this will be

Handler uh Delete feed follow right so

we want the feed follow ID dynamically

passed in the path of the request so the

question is how do we grab this feed

follow ID um in our Handler itself well

the chai router has or Chi oh I'm I'm

never going to say that the proper way

uh the chi router has a I think it's p

is it URL let's see

URL parameter that's the one uh Ur URL

parameter function where we can pass in

the request and a key and in this case

it's going to have to match so feed

follow ID matches whatever we type in

here between the open and close

brackets okay and that's going to return

a string so this is the feed follow ID

string great we're going to take that

and we're going to par it into a uuid so

we'll do U id.

parse and that will return a feed follow

ID and potentially an

error if the error does not equal nil

we'll say couldn't parse feed follow

ID and that will be a 400 level errror

perfect okay from here we should be able

to do apic CFG do database. delete feed

follow and we need to pass in the

request

context

and feed follow params so database. feed

delete feed follow parameters it takes

an ID and a user ID so the ID of the

feed

follow we just parsed and then the user

ID comes in with that user object

because this is an authenticated

request cool and that should return just

an

error right oh we it's just it's just

giv me yellow squigglies because I need

to handle the

air

couldn't elete

speed

follow perfect uh what do we respond

with here I guess we have a couple

different options um the simplest thing

would just be to respond with like an

empty Json object I guess

uh what matters to the client is

probably the 200 Response Code um so we

could like for the sake of Simplicity

just so we can use our respond with Json

function we'll just return an empty Json

object alternatively maybe we could

return an object that says like message

you know unfollow successful or

something um but it it doesn't matter

too much I think as long as it's a 200

level code uh we're pretty much good to

go

okay and that's already been hooked

up so let's go ahead and test

it uh I can't remember if I generated

let me do that again and then we'll

restart the

server and take a

look okay so this was our endpoint it's

returning the feeds that we're currently

following let's go ahead and delete this

feed follow so we need new request

this is going to be a delete request

we're going to unfollow a specific ID

we're going to unfollow this we're going

to delete this feed follow right feed

follow with that with that

ID and the headers we do need to be

authenticated as the same

person so

authorization same API key okay let's

run that delete we got a 200 response

now let's go do a get and make sure that

it's gone yep empty list or empty array

we're good to go okay we've built out

the majority of the crud section of our

API but we haven't built the most

interesting part which is the part of

the server that actually goes out and

fetches posts from the different RSS

feeds that exist in our database again

the whole purpose of this server that

we're building is so that it can keep

track of all of these different feeds in

the database and then go out

periodically and actually download all

of the posts that are on each individual

feed so for example we have a feed for

my personal blog post this server will

actually go out to my blog every I don't

know 10 minutes and check to see if

there's a new blog post to download and

store in the database so the first thing

we need to do is update the feeds table

to have one more column we need a new

column called last fetched at and it's

just so we can keep track of when we

last fetched the posts for a given feed

so let's go ahead and add that we'll

need new migration um and it will look

kind of like this migration uh it's

going to be our fifth migration so far

it's going to be on the feeds table and

we're going to be adding the last

fetched at last fetched at field okay so

alter table feeds add column last

fetched

at and this one is going to

be

timestamp and it will be nullable so we

don't need a notnull constraint

um in fact that's it

um it's okay like we don't need to

specify any defaults uh that should be

it um and then as far as the down

migration goes we'll just be deleting or

dropping the column from the feeds table

okay cool let's run that

migration so Goose

postgress perfect so we don't need to

update the create feed uh

function we want the last fetch St field

to default to null so no changes are

necessary there but we do need a new we

do need a new query this one's going to

be

called get next oh my gosh get next feed

to fetch can't type today get next feed

to fetch and it will return a single

row and this one should say select

star from

feeds order

by last fetched at descending

NS

first limit

one okay so we always this the purpose

of this function is to go get the feed

that next needs to be fetched like we

need to go get posts for this feed next

and the whole idea is first we want to

go find any feeds that have never been

fetched before those need to take

priority after that if every feed has

been fetched then we want to go find the

one that was fetched the longest ago

like the farthest in the past right so

we're ordering by last fetched at um

nulls first in descending

order actually scratch that we're going

to want to do a ascending right

ascending would put the lowest the

smallest time stamps right the ones

further in the past at the top and then

Ascend into the present okay so order by

last fetch thatat ascend ending NS first

perfect okay just to make sure that my

SQL code is valid we'll generate that

looks good okay next we need one more

query this one will be

called uh Mark feed

fetched Mark feed I guess as

fetched this is the one we'll call after

we fetch a feed to say that we fetched

it um and we'll return the updated feed

okay so it's going to be

update feeds

set last fetched at equal to

now and updated at also equal to now so

we haven't really gone over this but the

updated at and created at fields are

mostly for auditing purposes it's pretty

standard practice to set these fields on

basically every record in an SQL

database just so you can see when

they've been created and updated it's

kind of again auditing

purposes okay uh where

ID equals dollar sign

one

and returning

star okay so we update the feeds we set

the last fetch at and the updated at to

the current time for the given ID that

looks good to me let's go ahead and

generate that perfect next we need a way

to kind of take an RSS URL or a feed URL

and parse it into an an actual response

body and in this case we're going to

represent it as a struct let me show you

what I mean so let's create a new file

I'm just going to call it rs.

Go and it's going to be part of the main

package and we need a new function and

we're going to call it RSS

to or actually let's call it

url url to

feed

okay and it's going to take as input a

URL which is just a string and it will

return a new type so we need to specify

the new type type um RSS

feed it will return both an RSS feed and

potentially an error if there's

something wrong uh with the request that

it's making now that RSS feed struct

that we just created is going to

represent basically this giant this

giant document here right so if you go

to Wags lane. deev index.xml which is a

valid RSS feed then you'll see this

giant document and really you can think

of RSS as just structured data in XML

format and XML is just kind of like

crappy Json so the way we parse XML in

go is very similar to The Way We parse

Json let me show you what I mean I've

done the Dirty Work of scanning all of

the valid um values in that big RSS

document and I found that basically

these are the

keys um for the RSS entries in my blog

so RSS is kind of a standardized set of

keys within XML um and basically what

I'm saying is these are the keys that we

care about right at the top level of an

RSS feed we expect a channel key right

in the XML document and we expect a

channel to have a title a link a

description a language and then a slice

of items and then items are kind of

these nested objects that each have

their own title link descriptions and

publication dates right and each item is

a new blog post and if you're asking how

I came up with those names of all of the

different Keys it's because I went and

looked here in this document I saw okay

at the top level we have a channel right

and then we have um this entry with a

title a link a description right so I

just kind of manually looked through

this document and found all the stuff

that I wanted to parse out so let's fill

in the rest of this URL to feed function

so first we're going to need an HTTP

client um I'm just creating a new client

using the HTTP Library um we'll set it

to a timeout of 10 seconds if it takes

more than 10 seconds to fetch an RSS

feed uh we don't want that feed anyway

probably broken okay uh then we can use

that client to make a get request

to the URL of the feed and that's going

to return an HTTP response and

potentially an

error if there's an error we'll just

return let's just

do um for cons for ease of use I'm going

to make this a pointer to an RSS feed so

we can just return nil and the

airor cool um if everything's okay then

we're going to defer a

close on let's close on the resp sorry

it's not it's not the close function

it's resp. body

close Okay and then after that we want

to get all of the data from the response

body so it's going to be io. readall we

have to read everything from resp. body

and that comes back as a slice of bites

and an

error okay this slice of bytes we want

to read

into this RSS feed so dealing with XML

in go is very similar to dealing with

Json and go it's actually going to be

XML

dot

unmarshall pass in the data and a

pointer to where we want to unmarshal

the data so actually I need to create an

empty struct we need RSS

feed is an empty RSS feed

struct then we'll unmarshall into that

location in

memory that will return an

error if everything goes well then we

can just return the new populated RSS

feed perfect now as I type this out I'm

already kind of dissatisfied with this

pointer solution I don't think that

needs to be a pointer I think we should

just return empty

structs um either way would work I think

this is a little cleaner though because

it means the user of this function us

right uh will will get an actual RSS

feedback and not a pointer to an RSS

feed okay let's go ahead and test this

really quick I'm just going to do a

little kind of hacky

thing just right at the top of main I'm

going to call URL to feed and give it

the URL of um my blog so waglan

dodev index.xml

that should return a feed and an

error right and then if error not equal

nil log.

fatal error otherwise I want to just

print out fmt do print line let's just

print out the whole feed it'll be

disgusting but at least we'll get to see

if it kind of worked okay let's build

and run that

there we

go cool so if you kind of scroll through

this you'll see it looks like I mean

there was no errors and then it looks

like we

properly at least you know at first

glance looks like we properly filled out

that struct it's kind of just dumping

all of the data so now that we've done a

sanity test on our URL to feed function

let's go write the actual ual

scraper create a new file just call this

scraper.com so we can really see so we

can actually see what uh what we're

dealing with here so it'll take three

inputs a connection to the database um a

number of

concurrency units I guess the best way

to think about this is how many

different go routines we want to do the

scraping on and then how much time uh we

want in between each request to go

scrape a new RSS feed cool and it

shouldn't return anything because this

is going to be a long running job now

because this worker this scrap rper is

going to be running in the background of

our server I think it's really important

that we have good logging um that kind

of tells us what's going on as it's

happening so when we start scraping I'm

going to do a a little log message here

so log.

printf we say

scraping on percent V go

routines every percent s duration

pass in the concurrency and the time

between

requests cool after that we need to

figure out like how we're going to make

our requests on this interval and

there's a really cool um mechanism in

the standard library and go called a

ticker so we can create a new ticker uh

using the standard Library so time. new

ticker and we give it a duration in this

case time between

requests and it responds with a

ticker and then we can use a for

Loop to execute the body of the for Loop

every time a new value comes across the

ticker's channel so the ticker Has a

Field called C which is a channel where

every kind of let's say that you know

time between request was set to one

minute in that case every one minute a

value would be sent across the channel

so by using this syntax here we could

say run this for Loop every one minute

and the reason I'm passing in an empty

initializes and an empty um middle

section to the for Loop is so that it

executes immediately the first time so

the very first time we get to line 17

the body of the for Loop will requ will

will fire immediately and then it will

wait for the for the uh interval on the

ticker if that makes sense if we just

did this oops if we just did what is it

for

range tier. C uh then it would actually

wait for the minute up front but I want

to do it once immediately um it'll make

it easier to debug and work with now at

this point I realized that I've made a

mistake the purpose of this concurrency

parameter here is to uh you know

indicate to the start scraping function

how many go routines we want to use to

go fetch um all these different feeds

and the whole point is that we can fetch

them at the same time time so that means

that each time that this ticker fires we

need to be potentially go you know going

out to the internet to fetch 10 20 30

different RSS feeds and download all of

their blog posts at the same time which

means we'll actually need to be able to

grab a multiple number of feeds we'll

need to grab more than just one at a

time so rather than get next feed to

fetch let's change this to get next

feeds to fetch and we'll have it return

many

and then rather than limiting to one

let's limit to dollar sign one so we can

actually pass in how many feeds we want

as a parameter to this function okay

then we should be able to regenerate

that and we should oh we're not even

using the function yet so okay so that

was actually the perfect time to do that

okay let's fill out the body of this for

Loop so every interval time between

request we want to go grab the next

batch of feeds to fetch so we can just

call that function that we just wrote

database. getet next feeds to fetch it

takes a context and a limit so the first

thing we'll just use context. background

so again I haven't gone into a ton of

detail on the context package but

basically context. background is like

the global context it's what you use if

you don't have access to a scoped

context like we do for our individual

TTP requests okay so that'll work for

now and then we also need to pass in a

limit so we'll just cast int 32 and the

limit or the sorry the

concurrency and that should return some

feeds and an

err if there's an error we should

probably print something

now notice I'm continuing here that's

because this function should always be

running as our

server operates like there's no time in

which we want this function to ever stop

so if I returned here that would be a

problem it would actually stop scraping

completely just because maybe I don't

know our database connection was down

temporarily so for now we're just going

to log and continue now that we have a

slice of feeds let's write some logic

that goes and fetches each feed

individually and importantly fetches

each individually at the same time so

we're going to need a synchronization

mechanism uh I'm going to use a weight

group so the standard library has this

awesome thing called a sync. weight

group then we can iterate over all of

the feeds so four feed range feeds

okay so the way that the weight group

works is anytime you want to spawn a new

go routine within the context of the

weight group you do a weight group. add

and you add some number to it so here

I'm iterating over all of the feeds that

we want to fetch on individual go

routines and I'm going to add one to the

weight

group then at the end of the loop I can

do a weight group.

weight and and within the loop I can

spawn a new go routine so we're going to

go do some function in fact I guess I

should just name it kind of what we'll

be doing uh let's call it scrape feed go

scrape feed and here we're actually

going to pass the weight group in as one

of the

parameters and

within scrape

bead takes a weight group which is a

pointer to a

sync. weight

group within this function we'll defer a

weight group.

done okay so what happens here

basically we're iterating over the the

the all of the feeds on the same go

routine as the you know the start

scraping uh function so on the main go

routine on the main go routine we are

adding one to the weight group for every

feed right so say we had a concurrency

of 30 we would be adding 30 to the

weight group now we'll be spawning all

of these separate go routines as we do

that and when we get to the end of the

loop we're going to be waiting on the

weight group for 30 30

distinct calls to done so done

effectively decrements the counter by

one right done decrements the counter by

one so we're adding one every time we

iterate over the slice and then we're

calling done when we're done actually

scraping the feed so what this does is

it allows us to call scrape feed at the

same time 30 times we go spawn 30

different go routines to scrape 30

different RSS

feeds and when they're all done line 35

will kind of execute and we'll move past

that until they're like before they're

done we'll be blocking on line 35 which

is what we want to do because we don't

want to continue on to the next

iteration of the loop until we are sure

that we've actually scraped all of the

feeds so we've sort of stubbed out this

scrape feed function right now it

doesn't do anything other than call

weight group. let's actually go scrape

some feeds so it's going to need access

to a database

connection and it's also going to need a

specific feed to go fetch so feed is a

datab base. feed

cool and then here we can pass in

database and

feed great the first thing scrape feed

should do and and keep in mind we're

deferring the weight group. dun so this

will always be called at the end of this

function um the first thing we should do

is Mark that we've fetched this feed or

that we're fetching this feed so it's

going to be database. Mark feed as

fetched we can just use the background

context

again and we need the ID of the feed so

feed dot

ID cool that should return an error if

there was an error I think oh it also

Returns the updated feed I don't think

we care about the updated feed so I

think we can ignore

that say if air is not equal nil now

keep in mind we are not returning

anything from this function remember

we're calling it on a new go routine so

there's nothing to return here if

there's an error instead we'll just log

there was an issue

and return nothing and next we need to

actually do the heavy lifting which is

to go out and scrape the feed so we

already wrote Our URL to feed function

let's just use that so URL to feed and

we'll pass in the feed. URL and we

should get back an RSS feed and an

air and if error does not equal

nil error fetching

feed and we'll return

there otherwise we need to do

some logging so in the future what we'll

do is instead of iterating over all of

the um items in the RSS struct that we

get get back and just printing them to

the console we'll be saving them into

the database but for now just so that we

can test our scrape feed function um

we're just going to log log all of this

to the console so we're going to log um

each individual post or rather that we

found a post um and then how many posts

we found the last thing we need to do is

go hook up this start scraping function

to our main function so that it actually

starts okay so start scraping takes

database concurrency actually I'll just

open this uh my screen's too small to be

working in two tabs at the same time

okay um we're going to need to call it

before listen and serve because remember

this is where our server kind of blocks

and waits forever for incoming requests

so we should probably call it I don't

know

right here seems like a good

spot so um it's just it's just a

function right yeah it's not a method

takes database concurrency and time

between request okay so we go go start

scraping remember we want to call it on

a new go routine so it doesn't interrupt

uh this main flow because remember start

scraping is never going to return it's a

long running function uh this is an

infinite for Loop okay it needs a

database connection so we'll actually

need to save this

in a new variable so that we can use it

in the API config and in the start

scraping

function next we need the currency um

let's just start with 10 seems good and

then time between requests let's do

time.

minute perfect I went ahead and added a

second RSS feed so let's go ahead and

check the database and see what feeds we

have currently so I've got Lane's blog

and the boot Dev blog so there's two now

remember we were setting a concurrency

of 10 so we should definitely be able to

fetch both of these blogs at the same

time on the first iteration of that Loop

if we say deployed this production and

allowed users to start creating feeds

maybe we'd get up to 100 200 400

different feeds in here then we'd only

be fetching 10 at a time right just so

we understand how that mechanism works

but for now this should be good enough

to test I'm going to update our logs

just a bit um so that we can see which

blog each post is from so found post

item.

tile on

feed feed. name okay let's go ahead and

run that

bound post the property sub pointers in

go on feed boot Dev blog perfect we kind

of scroll up we should be able to see

some the boot Dev Blog has way more blog

posts than my personal blog here it is

here's some Lane's blog stuff okay so

that looks like it's working we should

be able to move on to the next step now

where we'll actually save these blog

posts into the database rather than just

logging the titles to the console we're

going to need a new table in our

database so let's start there we'll call

it

posts so the purpose of this table is to

store all of the posts that we are

fetching from all of the different uh

from all of the different RSS feeds okay

um what am I doing this is this is

queries we need to start with a

migration so let's grab this we'll make

it 006

posts.

SQL all right Goose up is going to be

create table

posts what goes in a posts table um we

are going to need an ID created at an

updated at that pretty much never

changes um what else does a post have

well it has a

title

title um is that text. null that makes

sense uh posts also typically have a

description text um I'm going to allow

that one to be nullable I think it's

okay if a post is missing its

description posts also typically have a

published at date so published at is a

timestamp um should we allow that one to

be

nullable no no let's make that not

null what else does a post have it has a

URL a URL should be not null for

sure um I'm also going to say that it

should be

unique

unique I don't think we ever want to

store the same Post in the database

twice there's no point right if we have

a post I don't see why we would need it

a second time so let's let's go ahead

and make that one unique and then lastly

let's just put in a feed

ID and the feed ID is going to be a uu

ID that

uh we're gonna want it to be a reference

so

references um feeds

ID right and that's going to

be does that need to be unique it

doesn't need to be unique but it should

be not null we should always have the

feed ID of a post and let's here put on

delete Cascade if we delete a feed we'll

Cascade and delete all of its posts and

I forgot to put the type here so URL

text. nil unique okay that looks good to

me let's go ahead and run our migration

so it's going to be uh we need to CD

into SQL

schema and run Goose

postgress we'll need this connection

string

up perfect next we'll need a couple of

queries to interact with this table uh

the first one's going to be just a way

to create a post so let's do posts

and we'll

do

create

oops create post return one thing and

we'll just kind of be inserting a bunch

of stuff I think let's take a look at

the post table so we've got ID created

at update at let me just grab this so I

don't forget

it okay so insert into

posts ID created updated

at we also have we have a lot of stuff

so I'm actually going to start spacing

this out a little

bit cre at update at it's going to be a

title and a

description publish

that

URL and a feed ID

okay and the values 1 2 3 4 how many do

we got just

eight

five 6

7 eight returning

star straightforward right insert into

posts all of these fields no fancy logic

that should be good okay let's run sqlc

generate to add that function to our

internal package and then we just need

to go use it so down in the scraper now

instead of just logging all of these

posts to the console let's save them to

the database um I'm going to leave this

log message it says feed blank collected

blank posts found so that'll just log

all of the different feeds we're

collecting but each individual post I

think it's wasteful and kind of busy to

log everything so we're not going to do

that instead we'll just call db. create

post context.

background and what does it take create

post prams database. create post prams

okay cool I kind of like how

sqlc breaks down the parameters into um

into a struct makes it pretty simple to

work with Okay um we've got an ID

created at updated at okay um ID is just

going to be a new ID

created at updated at that'll just be

time.

now

UTC what's next title description

tile item.

tile I just realized I just realized now

that I'm not putting the field names

it's kind of

embarrassing okay title

description do they not have a

description what does an item

have let's take a look at an item items

have title link description yeah it does

have a description what am I messing up

here can I use item. description

variable of type string as SQL n string

ah right okay

so we need to do SQL do null string a

null string has the string itself and

whether or not it's valid so we just uh

put in the string and then we say it is

valid string do valid is a bolean

true although actually this is a problem

right this is a problem because if item.

description is blank if it's an empty

string we're going to be putting in an

empty string and saying that it's there

even though it's not so let's not do

this let's do something a little

different let's

go

description is a new sq.

nring why is why is that giving me

trouble oh because because I'm doing it

within the call to create post do it

right here okay so we'll create a new

SQL n string and then we'll

say if item. description does not equal

the empty string then we get to set

description. string equal to item.

description and description.

valid equals

true and then we'll use the description

here does that make sense so if if the

item's description is blank then we'll

set the value to null in the database

effectively um otherwise we'll create

the valid uh description entity

okay next we need a publish

dat let's see we've got an item. pubdate

which is a string okay so we're going to

need to parse that string to parse that

date there is a time. parse function in

the standard library and we're going to

use this RFC 111

23z layout so this is the layout that

I'm using on the boot Dev blog and on my

blog to be more robust and support all

of the different publishing format for

all the different blogs that we want to

scrip we'd probably need to make this

logic a little bit more robust but for

now I'm just going to say we're parsing

it this way if it's not that way I guess

we take a hike okay um if there's an

error so if error does not equal

nil we can say log. print

line parse date

sent V with air sent V and we'll pass in

the actual Pub

date and an error and that's going to be

a print

F oops cool and then if that's an issue

we'll just continue so if we don't get a

valid time uh then we'll just we'll just

log it log and move

on okay so published at pass in that I

shouldn't use single name variables like

this let's do Hub

at okay what else do we got a URL and a

feed ID so

URL is just going to be the item.

link and feed

ID do we have access to the feed ID

here we do we have the feed right

because we passed in the feed here

perfect

b.id now db. cre post does return an

error so we need to handle that

error what am I screwing up here oh it

also Returns the post itself I don't

think we care about the new post though

I think all we care about is if it

failed so if

error equal

nil fa to create post with

error oh okay let's give that a shot

okay build and

run now remember we're expecting this

time to get logs that just say that the

blogs were collected so 21 posts from

Lane's blog 321 posts from the boot Dev

blog were collected I'm going to go

ahead and kill the server and let's

check PG admin so now if we select star

from

Posts we should see a bunch of stuff in

here IDs created at titles descriptions

published at dates awesome this is

looking

fantastic we scroll down to see how many

rows there are 342 that looks right to

me now I think we have an issue here let

me show you what I mean if we run this

again so remember we've scraped both of

the feeds and pulled in all of the posts

so if I rerun my server at this

point yeah we're getting all of these

issues fail to create post duplicate key

value violates unique constraint posts

URL key right now this makes sense we

didn't want to store duplicate posts in

our database so we have a unique

constraint on the post URL which means

when we go try to recreate the posts it

fails because we already have the posts

in our database so let's do a little

string uh a string detection so that we

don't log this crap every time this

happens because this isn't really an

error this is expected Behavior so um we

can do something like

if string do

contains air.

error uh duplicate

[Music]

duplicate

e then do we continue what are we doing

here yeah then we

continue otherwise we'll log the eror so

we're only going to log the error if

it's not a duplicate key error okay so

let's run that again and make sure we

don't get those

errors perfect we have one last feature

to add to our RSS aggregator we need a

way for users to be able to get a list

of all of the newest posts from the

feeds that they're following so we'll

need a new

query uh we can call this

one get posts for user and it will

return many posts now let's think about

this query for a second it's a little

more complex than the other queries

we've done and that I think we need to

do a join so we have our posts

table right post have IDs created at

updated at but importantly they have a

feed ID so we know what feed every Post

in the database belongs to and we also

have a feed follows table that tells us

which feeds an individual user is

following so if we join those two tables

together right if we take all of the

feed follow information kind of join it

to the posts table then we should be

able to filter by all of the feeds that

a user is actually following so what

does that look

like you can do select posts. star so

everything from the post

table from

Posts

join feed

follows

on oops on post do feed ID equals feed

follows. feed ID okay so this adds

essentially all the feed follow

information to our like the virtual

table for this query right we're joining

those two tables together so now we

should be able to filter um the way we

want Okay so we've we've joined them

together uh

where posts dot wait posts no where feed

follows. user

ID

equals dollar sign one okay so we join

the tables and then we filter all the

posts down or rather the entire table

down by the specific user ID so all of

the posts that belong to feeds that the

user is not following should at this

step get trimmed

out then we can order by let's do post.

published at descending so it give us

the newest stuff first

and we'll limmit by a configurable

amount so dollar sign

two cool let's go ahead and try to

generate

that looks like it worked let's see if

uh see if when we run the actual

application it does what we expect let's

hook that query up to a new endpoint so

I'm here in the users file that seems

like a reasonable place we'll do

Handler get posts for user

it will be an authenticated endpoint so

we'll need that that user data um but

here we're going to call DB dot or sorry

API

config DB doget posts for user and then

we can pass in the request. context and

user. ID oh we also need I think a

limit oh get no no no sorry we take we

take database. get post for user params

right because we had multiple parameters

here so we'll need the user's ID and a

limit the user. ID and for now let's

just say a limit of 10 and that will

return to us some posts and potentially

an

error if we get an error we'll respond

with

it couldn't get

posts otherwise we need to return the

post themselves now we should go create

a special posts model right so that we

get our our own tag so type post

struct go mostly copy this

from our

internal post

model wherever it ended up here it

is

okay add some Json tags

goodness typing is

hard now here's an interesting

thing this SQL null string um is not

something that we're going to want to

use um in this struct because this is a

struct that Marshalls to Json the null

string object is a nested struct so if

we Marshal it directly to Json we would

actually get description as a Json key

and then string as a Json key and then

valid as a Json key so be a little

nested object there that's pretty bad

user experience because Json natively

supports kind of null in the sense that

you can just omit the the key um or use

like the actual value null um so what

we're going to do is instead do a

pointer to a

string and the way Json marshalling and

go works is if you have a pointer to a

string and it is nil then it will

Marshal to what you'd expect in Json

land which is that null

value okay then publish

that URL

and feed

ID okay did I miss anything let me look

over this really

quick that's looking

good and next we need the conversion so

we'll

do database post to post

now this one gets a little hairy right

um we probably need to do some logic

here so we'll say bar description

pointer to a

string and then if DB

post. description.

valid then we'll set description equal

to the address of DB post. description.

string cool then we can just directly

use the description variable

there all right published that

what else we got URL on Feed

ID okay and last but not least we need a

way to do it uh do the conversion for an

entire slice bunk DB or database posts

to posts

and the logic will look pretty much

identical to that but I actually think

it'll be easier to type it out so we'll

do uh posts slice post

it database post

post the database

post

okay there we

go lot of conversion logic there but now

we should be good to just respond with

some

Json and we can pass

in those posts as database posts cool

what am I get in

here truck literally uses unkeyed Fields

oh yeah let's not do

that we want an

ID and I think it's a

limit right what am I messing up user

ID

perfect okay let's build and run the

server

again oh I realize I made a mistake I

need to actually hook this up to

something so let's go back into main.go

we need a new

endpoint we'll do

get um I don't know user

feed now feed's probably a loaded term

in this uh in this application we should

say uh let's just do

posts and it's going to require

middleware so middleware off and API CFG

Dot

Handler get posts for user okay so get

SL posts it's an authenticated endpoint

Perfect all right let's rebuild and run

that

okay opening up thunder

client first we need to check well

actually let's just grab some off

information so

um this clearly has some

moth let's grab that API key create a

new

request HTTP col Local

Host V1

posts headers close

that

authorization API key okay so if I make

that request I'm getting back no posts

now we know we have posts in the

database but my my user that I'm

currently logged in as is not following

anything right I'm getting back the

empty array when I when I check my feed

follows um but I can check which feeds

Exist by running this API

request so let's grab this feed let's

grab the Wags Lane feed and let's go

follow that one so we'll post to feed

follows here this feed ID

okay so now I should be following let's

check my feed

follows great I'm following them so now

if I go get my

posts there we go I should just be

getting

posts from the Wags lane. Dead

Block perfect let's try following let's

try following um

the other one

so where is it feed follows no

feeds let's try following the boot Dev

blog as

well so post to feed

follows send that check my feed follows

now I'm following both now if I go get

my

posts perfect we're seeing stuff from

the boot Dev blog that's it thank than

you for sticking with me through all of

this mess we've created an amazing blog

aggregator that will actually work

pretty darn well at scale you could run

this thing uh you know over a long

period of time collect millions of blog

posts and it would do pretty well I hope

you had a ton of fun with this project I

do want to remind you that this is a

server right we've kind of been running

it stopping it restarting it but at the

end of the day you can just turn it on

ADD new feeds and follows and interact

with it directly and it will once a

minute go out and collect all of those

blog posts so you could just keep this

running on a Raspberry Pi in your house

um to aggregate you know blog posts

podcasts all that kind of stuff um I

will point out that we have done a bit

of happy path programming so happy path

programming is when you're not

necessarily handling every Edge case out

there you're you're handling kind of you

the thing that you expect to happen most

of the time so for example um we only

had one type of date parsing for the

published at dates in our RSS feeds but

maybe there are RSS feeds out there that

use a different date format and we'll

fail to parse them um so one way that

you could extend this project would be

to just add a ton of new RSS feeds and

make sure that you deal with the issues

as they come up make sure you improve

the logging so that you can see the

issues when they come up anyways I hope

you had a ton of fun with this project

and that you learned something I just

want to remind you that we do have an

entire backend learning path over on

boot. in Goan so if you liked this

project if you liked this course and are

looking for some more content definitely

go check out boot. we also have

published a lot of different ways that

you could potentially extend this

project to make it cooler for example

maybe you add a front end or a command

line application that interacts directly

with the API so that you don't need to

use manual client like thunder client

every time that you want to interact

with your posts and then I also just

want to remind you before I go that you

can find me on Twitter at Wags lane or

on YouTube at boot. definitely go

subscribe to our YouTube channel as well

thank you again to free code camp for

allowing us to publish this course and

this project walk through I hope you

enjoyed it and I'll see you in the next

one

Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.