 This is go for Python developers or for Pythonistas. My name is Alishande, but you can call me Alex. It's way easier. And I am a Pythonista at HeadHead. Before I start, I should explain how it works. I will show a small presentation, some couple of slides, to introduce the difference of Python and Go. After, I will do some examples. So, if you can, you can learn a little bit of Go. My Go is not to say if Python is better or if Go is better. No, it's just to you to learn the differences between the languages and after you can choose by yourself which language you think is better. Couple of questions. Who works with Python? Who knows Python? Everyone? Does anyone knows Go or work with Go? Her dog? Okay. So, let's begin. The history of the Go language. It started at Google in 2007, and it was the main, the people that it started was Robert Ruffike and Ken Thompson. You can find some really good talks on YouTube of these guys. The first public release was in 2009, and the first stable release, Akka 1.0, it was in 2012. And why a new language? Why should we, why? So, the main reasons for a new language that it was difficult for Google, that time in 2007, the main language it was Java and C++. So, back that time you didn't have Rust or other new languages. So, the main reason was the frustration with existing languages. C++ wasn't as easy as other languages, and Python wasn't as fast as other languages. So, it started to become too difficult to develop new code at Google. And after many years without any new languages, they decided to think it's time for us to rethink and create a new language. And the main reason of Go is to take advantage of networking and multi-core processors, because this is something that was growing in 2017, now you can see that everything runs on web, and even your cell phone is eight-core. So, features, some features of Go, it compiles to machine code and also compiles to a web assembly. This is, a web assembly is very new. And it's a language that is memory safe. It's memory safe because it has no buffer overflows or no pointer arithmetically, arithmetically. And there is garbage collector and one of the biggest features of Go is concurrency. Go versus Python, code organization, this is something that people struggle with when they come from Python and go to Go. Because code organization, Go is a little bit different. Right now, in older versions, for example 1.10 or even 1.11, you keep everything in the single workspace. That's the GoPath environment variable that defaults to your home path slash Go. And you keep your source files and your binary files inside that path. A workspace contains multiple repositories. It means everything is inside that specific path. And usually the import path is the package location inside your workspace. I will show how does it look like inside the Go workspace. So you can understand a little bit better what does it means your import path is your workspace path. But this is going to change with the package management. Right now, there is no official tool yet. Actually, there is an official tool yet, but it's not fully released. It's just preliminary support in Go 1.11. And it will be released as the standard tool in Go 1.13 in August 29. And you won't need GoPath anymore for your source code. It will be only used for your binary code when you install a location. And right now, the tools that you can do package management, there is DAP, that is the official experiment. The DAP was the experiment for a new tool in the Go language. And there is Go DAP, Go Vendor Glide and many others. Biggest difference is object orientation in Go. You will see that there is no class, no errantes, no generics, but there is interface, composition and type embedding. And you can do object oriented programming with just this. Pointers, something very different. You have pointers in Go. You will find pointers in C and in C++, but not in Python as the way in C. So everything in Go is passed by ballet. No pointer arithmetic is. This is why it makes Go a safe language. Pointers are represented by a series. It's also used to the reference. Ampers returns the memory address and there is the new keyword, but we don't have a freaky word because Go manages with the garbage collected there when your object is destructed. Concurrents, this is, I think the best thing in Go. There is GoRoutines and channels. GoRoutines are, most people say lightweight threads because they share the same address space. It's not a real thread, but GoRoutines run inside multiple OS threads. Channels are the way to communicate between these GoRoutines because when you have threads, you need to synchronize these threads in a way. And channels are the way you synchronize information across your GoRoutines. What else is different from Python? You have no decoration, no decorators, no name or optional arguments, no iterators, no generation, no list comprehension, no dict comprehension. There is no exceptions. You don't have try catch. You'd have error as in rest. And also Go is part of the C family and you also have labels and go to in Go. So your first program in Go will be the hello word and some differences. You can see it looks like C. You have the function man. You have print new line with the hello word. You have the import statement to import the format package to print something. And your files will always start with the package, something. If it's the entry point of your application, it must be package main. But if it's a library, you can name the name of your library. Another example of code, factorial in Python. You can see that factorial in Go is very similar. It's just you have practice and types. But you can see if return the definition and the way it works, it's exactly the same. It just have a little bit more of code. Fibonacci with generators. Since Go has no generators, you can do the same approach with Go routines and channels. You can see that the code will look very, very similar. For example, explaining a little bit, you have the package, you have the import, the Fibonacci function. You see yield A, the C is a channel and I just send the value of E to the channel. And it's the channel I have this for and iterates over the channel and will print out as the same way as in generator in Python. And that's it. What I had to show you the differences. Now, let's start to write some real code. Yeah, channel is a keyword and you need to specify the type of the channel. For example, this channel is an integer type. You can only send ints to that channel. So if you have any other questions during the code that I will show, you can haze your rent and ask the only to wait until the end of the presentation. I will try to explain a little bit better showing go routines and channels running. So, okay, it's time to do some code. Does everyone has Golang installed or Docker? If you don't, you can use the goal playground and you can copy and save your code if you don't have a goal. It's a little bit, can you see or it's, for me, it doesn't look like it's something is, it's not as it should be. So I'm going to start showing some, yes, yes, yes, yes. Yes, yes, yes, I can, I'll go into a shift plus. It's good for everyone. Okay, so let's start showing some code. So, okay, just a moment. It's better now, uh-huh. So, going back to our channels and I think after, before I, let's see, okay, GoPath is not set. That's something interesting, anyway. So, as I said, our first line would be the package and some name, if it's, as it's at the entry point, it is the main, and, okay. So this is, I think there's some problem with the video. Yeah, okay. That's the worst. Yeah, I can just change. Now you can see, right? Yeah. Well, how, let's understand the code that printed that out. You, you have the channel, C is a channel and we create a channel with make chain int. This goal keyword, this is what start a good routine. A good routine. You can, if you remove it, it's just a normal function, but if you apply the goal keyword, it will start this as good routine. So, what does it does? This good routine. It iterates, iterates over from zero to 10. And every time, every iteration, I send the number plus one to the channel C. And when we finish this iteration, we close the channel. And the four here, it's iterating over the channel C. And every time it receives a new integer, it will print out. So that's why it prints one, two, to 10. This, here, here is because you're calling the function. It's a call. If this is an anonymous function, I, for example, I can change this and put here and give it a name and call here. Define it as a name function. You have to give the channel as an argument to the function. Yes, very good, very good. I forgot that. Yes, let's see if it works. Yes, I forgot to put C here. So it works the same way. It's just, it was an anonymous function. So let's do something. So let's start explaining how the channel works. So this is a channel. And we use the make keyword to create a new channel. And you have the channel and you want to send something to that channel. You can use this to send. This means I'm sending something and I will send one to that channel. So let's try to run this and see what will happen. We have an error, a deadlock. Why? Because we have a channel. It's unbuffered. It means someone needs to consume that channel. If no one is listening to that channel, you will have a deadlock because Go is very good in detecting this case. So, okay, let's read it. We're going to read to white. This means to receive something. So I receive any message in the channel. C and I will save it to I. And it is still not going to work. Okay, okay. This is something that I always do. Because I work with Python and I forgot the imports sometimes because you don't need to import anything to print in Python. So sometimes I will forget brackets or imports or other things. This is still does not work because I is undefined. So we need to declare Y. We declare Y and it will receive. No, this is implicit declaration. I can change this and do this. So if it looks a little better. Okay, so it's not a channel type. So it's better to use this way. It's easier. Is it still? We still have deadlock. Why? Because it's a channel and it's synchronous. So it will be locked after this. This won't run. So we need to make another chain. Just create a Go routine to set. Now it works. Because we're not locking our main function. It runs inside the Go routine. So we start the main function and it expounds a Go routine and you are waiting for something here. You are waiting for a message and after you get a message in the channel it will execute the next line that is our print new line. If I remove this, so this will just wait forever for someone but we don't have a producer. We just have a consumer. If I run it again I will have a new deadlock. This is something to keep in mind. You always need to have a producer and a consumer unless you create a buffer channel. So you can have some message in the channel without any consumer. You can publish but no one is listening. It will work because we have a buffer. It works. I have a Go routine that sends a message to a channel and no one is listening to that channel. But since our channel is buffered we can have one message in our channel without any consumer. If I try to do it again, send another, it won't work because our buffer is just for... Oh, it works. Okay. Oh, it's because the... It's a Go routine and it was locked. So yeah, now it does not work because I send one message. But the second time that it will try to send this message it won't work because it's blocked by the first message that no one is listening. So I send two messages and why it only prints one? Because it only reads once. If you want to read multiple times we need to add a for loop. Well, it prints out one in two but I get a deadlock again. Why? Because our iteration over C is locked because we didn't close our channel. So after you finish sending messages you can close a channel. And now it works without a deadlock because the for loop range over C it will iterate over the channel until the channel is closed. If that channel is not closed and no one is publishing a new message in it the range, the for loop will be in a deadlock state. He is waiting but no one is publishing to it. So that's why it raises an exception or throw an error, like panic, not a crazy an exception. Ask. No, no, this is runtime. This is runtime. The compiler error if for example import, for example import sync, we're not using sync. You can do, I have to import this is something that is not very popular. You can change, you can change to do this way as well. That's very similar to Python. You can import multiple statements in the same line. So now I try to compile and we get an error while compiling. It's imported and not use it. Sync. The goal compiler is very strict in some things. For example, you can have undefined functions and not use it, not undefined. Not use it, variables not use it. Imports not use it. So you see that the compiler does a lot of thing, things trying to prevent you of writing some bad code. You can get the same in, for example, in other languages get warnings or in Python you don't get nothing. You just run the code unless you run PyLint you will receive a lot of warnings. But in Go it's not a warning, it's an error. So your code doesn't compile if you have and you knew things that are, you knew not use it. Okay, anyone has questions so far once maybe a better explanation of something that I maybe missed or everyone understands how a channels and Go routines works. Okay. Do you still have 10 numbers send to the channel? Do you have a source code? Yes? Copy, go, root, C, call, twice. So I have two lines with go and root but I don't get 20 numbers out of the channel. I just get 18. Do you know what you code, yes, like this? Okay, let's see the output, did you get this error? So what happened here? Why did I get send on close channel? Because we have two Go routines running using the same channel and inside our function we close that channel. You can close a channel until you don't need it anymore. And for example, probably the first Go routine will run faster than the second one and it will close the channel while the second Go routine is still trying to publish to that channel. No, if you close it, it can't be used anymore. No, it can't be used, it cannot be used. It's like closing a connection and trying to publish to that connection. No, because the Go, one thing about Go is that Go doesn't break things between versions. It tries to not break. Sometimes you can see a small change in some libraries but it's very difficult to break. For example, this way it works in minor changes. For example, we have always new things in newer versions, not things that you have backward compatibility. So if you wrote your code for Python 1.0, it should still works for 1.11. But if you write your code for 1.11 and trying to run it in 1.6, really you have some missing features added in newer versions. So I don't understand why you don't have this error. So you have two correct reading from your channel. The first that closes the channel wins. So one writes some, some. So maybe that's why he's having a different output because. No, you can try to run it. Oh, no, it didn't. That's not only... Ha, that's... You will have a different result each time. Yes, sometimes the runtime can notice. Oh, there is... Surprise, surprise. Yes, I'm surprised. For example, here it just printed for one to 10. So the second time didn't even start to run because when you close the channel, the range, the for loop will break. And we don't have anything waiting for the second, the second one. So why doesn't it re-instantiate it a second time? Do you close it so you run the loop function? Sorry? I close. Why doesn't it run it once? And if it closes, run it again. When you close it, close it again. No, because you close the channel, does it? You close it, you close it, you close it this, this channel. So if this one run first and this will try to run after, we have this for loop that is waiting for messages. And if the channel is closed, the for loop will break its execution and it will exit. So what happens if I remove this? Probably it won't, okay. Okay, that's, it doesn't print anything. Why? Because we're not waiting for the goal routines. The goal routines take some time to spawn. So if you're not waiting for it, it will, the program will exit without waiting for it. So let's try, I'm not sure how can I, let's do something different. So this is something that I explained. I have an example here. This is our program that runs and exits without printing goal. And there is no channels here. It's just a goal routine. And if you run, it won't print anything. But we can change this to become this. So why this does? We have our channel, we have our goal routine, we have our print. And when we finish the print, we send a message to the channel saying, okay, true. And it is waiting here until it receives a message. So now it will print. Because we need to wait in some way. We need to wait the goal routine to execute. So after the execution of the goal routines, we can let the program exit. It's like running a thread. And after you spawn a lot of threads, you do thread.join. So you wait the threads to run until it's finished. And after you finish running all threads, you can continue your execution or exit your code. You can wait with a wait group as well. So this is the same version of this wait, but with a wait group. So you don't have a channel. You just create a wait group and you add something. For example, we're starting spawning one goal routine. So we add one for it. And we, after the goal routine runs, we just do wait group.done. To say, remove that value. Remove on value from this wait group. And here we do the wait group.wait. That is the same as thread.join. So if we run wait. It does the same thing. And what if I add two goal routines and wants to? So it only printed one because we added only one value. So we have two goal routines. We add two values to the wait group because we are waiting for two goal routines. Yes. So you can see that we go again and go. So there is no order for execution of which one we'll print first. It is which one gets look and run first. I don't remember if it will work. Yes, it works. Huh, sorry? I wonder how to define order of execution. Order. Whoa. We have the output of the first one. And then always, then the front line for again. This is a very good question. I never tried to control the execution order of goal routines. Yes. But I'm not sure how could I, I try. But if you want to, the second goal routine to wait for the first to print, there is no reason to use a goal routine. If you, if you... Maybe at some point, the second routine has to repeat. Yeah, but if you, do you do this with threads? Usually no, you don't wait for one thread to run to run the second thread. So I can't think in a way that I could write some code that would make it wait for, I can't think in a way, but it's messy. So I think that's not the point of goal routine. You try to spawn and don't wait for another goal routine to run, you can synchronize some communication between it. So any questions so far? Any other questions? This. Is it an interfunction goal? No, this. Why this? It's because it's a strict, strict. So we create a new instance. So I, I shall, so I should show some, some, how does it works classes and these things. So if no one, if anyone, or if there's no any questions about, about channels and functions, I will show other, other features because for example, I, I learned goal after working with Python for many years and the most difficult concept to understand is general and goal routines. If you work, works with Python, C, Java, or if you have worked with multiple languages in your life, the other things will look the same. They have the same, the same meaning, the same, it's like this, the same way, but you just write your code a little bit different. For example, if, where is the, your for here? It's different from Python, but if you work with C-sharp, C, C++, Java, this looks exactly the same. So the, the different concepts are hard to understand on new languages if you try a new language. So, let's write some, some classes. If I can share, it's not on GitHub, but there is a way to upload to SCAD. I can upload there or send an email to SCAD, to everyone that was subscribed. So if you want to receive that email, you need to go to my talking SCAD and check that you were in this room. So if I send an email, you will receive the email with the link. Okay, let's do some objective oriented stuff. So what features are that have? Has. I know that a duck does quack. What else? I could add to my, so we have an empty struct here because our duck has no attributes yet, but a duck can have a color, right? What else a duck could have a size, maybe? Or duck does quack. So we create a new duck and we can, we can specify, for example, the color in this way, color white, and the size of the duck is, I don't know, 50 centimeters. All right, you can specify a duck now, so this way. You can omit the values, but you need to follow the order here. So sometimes you have a lot of parameters and if you do this and if you add something new to your duck, it won't compile, do some changes. So here I could change, for example, it doesn't matter the position where it is, if it is size or if it's color, but if you omit the names, you have a problem with position, so it becomes positional, so you need to follow the position. And we can call, you can tell our duck to quack. Okay, so let's run and see if it does quack. Well, it does quack. And we can print our object. Okay, we can print our duck color, for example, and duck dot color. Okay, it's not printing a line, forget this. Okay, our duck color is white. Okay, wait, what did I do? It printed out, it printed out the art struct. So there is a special that is this hashtag P that you can print your structure in a nice way, like this way, I can print out its values entirely. What is inside this duck? So we can see that the color is white and the size is 50. What types of duck we have? I can create an interface, and I can say that this interface, the duck does quack. And as in Python, in Go, you have duck typing. You have duck typing. So what is duck typing? If a duck does quack, if the object does quack, it's a duck. Right? If in Python you implement a class, and this class has the quack function or method, you can call this class dot quack. It doesn't matter if it's a cow doing quack or if it's a dog or if it's a duck, it doesn't matter. So if you implement the quack interface, for example, I could call this quackable. So if it's quackable, it does quack and a duck is quackable because it does quack. So let's change and call D, quackable, and this, so D is an interface. It's a quackable interface. And you will see that this does not work. D dot color because D is an interface and interface do not have attributes, only name of methods. So we need to remove. So our duck does not implement quackable. Why? Because it's an interface, we need to pass a pointer. If we're using interface, you need to use pointers. So D, the variable D that we created here is an interface of quackable. And we assign to D our pointer of duck. And if you call D dot quack, it will print out quack. What else does quack? Any other animal? Frog. Frog? Frog does quack? No. No, no, no. No, something that does quack. Just to show, more example. Goose. Goose. Yeah, goose can be. I'm not sure if I ever heard a goose. I'm not sure. So our goose will have the same goose quack and duck quack. So let me change a little bit here just to add another. So we have duck quack and goose quack. And since this is a pointer, we can make it a little bit understandable maybe for some people. You can use a new keyword because the new keyword returns a pointer to goose. So it's the same as the previous example. This creates goose and this returns the pointer of goose. The address. So far, any questions about? I think that is e-colocated. Is this syntax also for e-colocation? This is, if this does the same as. I'm not sure about the underlying things but it works the same. So I'm not sure what happens if there is a bigger difference. I'm not that aware. I know that new allocates something but I'm not sure about this. So, so far we saw channels, go-routines and a little bit of object orientation. So I will show some examples that I have here. There is a microsite that I've wrote as an example. I think everyone is familiar with Flask and this is your Flask application that renders a template, index template. This is, this would be difficult to do in poor Python so I'm using Flask to do this. You can, there are others, other frameworks but Flask very popular, so I chose it. And in Go, you can see there is no need for external libraries. You can do it only with the, template library from the standard library and with the HTTP library. It's very easy to understand if it's a standard library or if it is a third-party library. For example, a third-party library, it would be usually github.com but user.repo or it can be other internal URL or something, there is also go pkg.in that there are some people that use because you can control version on that. And so you always see that there is a domain. There is always a domain in third-party libraries. The standard library, they do not have. So difference between here, it's very small. In Flask, it does a lot of things for you. There's the static, if there is a static folder, it will understand that the static folder is where your stacked files are and that there is a template folder to assume that your templates are there. In Go, you need to specify a little bit that your handle for Flask that will be in the file server, the directory is static. And you still have your handle for the index and in our index function, we create a new template with parse the file and we execute. We execute renders the template. So to understand, for example, to understand the differences. In Python, we have the try accept. We have a raise error and here we don't have. We have, if parser files fails for some reason, it returns the template and returns an error. So if error is new, it means, okay, we're able to parse our file, we can try to execute our template. If not, we will panic. Panic will stop your application if you don't have a recover somewhere. Panic is a way to say, oh, something bad happened and I didn't want to treat that error, so I just, I didn't knew how to treat that error. So I tried to panic. Probably you see a lot of code when you copy paste from somewhere in the internet with panic, you should try to work with your errors, not just panic, because imagine this is a web, this is actually, this is a web page, a web server. So imagine we're throwing panic in our index page. So this will stop our application. So every new request you make will just throw an error and it will stop the execution of that request. So the user will not have some kind of error handling page showing something that could be useful sometimes. We just stop the request. So let's try to run it. So we have some static files. We have DevConf logo here. We have an style just to make the page a little bit better and we have our small, small HTML. We have a static style, static format, the image, the logo and we have just a small message here. So it's listening, the server is up and you see that it printed out this and this list and in serve, this blocks your current application. So if you have anything here, it won't run because this is locking. So we can go to the page page page and okay, our page is here. It's working, but let's suppose I add a panic here after we parse our file before executing our template. It's still listening and if we run, we get that this page isn't working and we have our stack printed out here because you can see here panic serving full, the message that I added here, it will be printed out and also the stack off. So you can track using the logs where it proved this is similar as a trace back, you can track it. What else? What else I have here? Some very popular common that everyone does in Python is reading a file. You open your file.txt and read the lines and do a four-lining lines and print out the line. And in Go, it's not as that easy, but it's very similar. You open your file. Again, if there is an error, you need to work with that error. I just did panic here because it is easier for examples, but I could return instead of an error. Instead of an error, I could do log dot. Oh, I can do this log dot photo. I don't need the return. Okay, so I did not find, for example, and I just add the log here. So let's, okay, this is the output of the file. It's Laurie Epson, very popular for testing. But as I mentioned, I can work with that error and try to do something better. For example, we try to read file one. File one does not exist. So I get a message, file not found, it starts one. But if I just do panic, panic is not free, anyway. Well, this is no such file object. So you have your exception here. So going with our example, what does this, so I open the file. I need to close the file. How it works with Python, you just use the width and the context manager will handle the close of the file for you. In Go, there is the defer keyword. With the defer keyword, you, for example, the file is not closed here because we're still scanning and this will run into the defer. Will be the same as if you add it here. So it defers to the end of the execution of your method. But even if there is some error, like panic or something between this, the defer will execute. So it's a safe way to, for example, if you add the close file dot close here, if something happens between, your file will not be closed and maybe if it's not closed, the file will be locked and no one else will be able to read. But with the defer, if something happens, you'll still be able to run it after. It's like the, it would be like the tricep, finally. You do the try, but finally, if everything, if anything didn't work, you can do something in the final. Yes, probably it is. I think the, but yeah, but for example, if something happens here, like a panic, your application is still running, but your application is in a panic state. So the application doesn't die when you get a panic. The application continues to running. So you can use panic to exit something. Yeah, because if you get an error that we didn't treat it, for example, this, we don't have any way to get an error here, I think, but if we had an error, the application can get into the panic state and you need to recover from a panic state. And if you don't do that, your application will be like a zombie sometimes. It is still there, but it does not work. So the file can be locked in that case. If you open it had some, some panic, the application is still running. The operation system will see that, oh, this file is being using by deep process, but this process is not working anymore. It's just in a panic state. Any questions you had? Okay, any other questions? Any other things that maybe want to see? Or, okay, we need to look into the rejects, rejects model, because it's not something that I usually do. So we have some examples here. Yeah, this is not, let me see if there is a good example. So we have an example here that there is an expression that I think it looks, it's pretty much the same as in Python, you have this, the group here, valley, and you are so group key. You have the, you want the words? Not numbers. So if you run it, you can get some. It should be pretty much the same with differences in name of functions, totally. The regular expression is pretty much the same. I already showed it in the beginning because you arrive it later, right? Which one, it was this? This. It was this? Yeah. Yeah. So we had an issue that we had a problem with this code. The details of the repeating was. No, it's not because it's repeating. You're executing the same function. The same function. It is the same queue. Go like, assume that we have the same channel and we have two loops popping 10, 20, and the other loop and we want to, how do I close the channel then? So I use great group or should I use something else? Okay, you want to run two times, you want two different loop functions. Let this pop in 10, 11, 20, 25. And the first loop is just. Oops. In the first loop, lines are moving. And you want this, right? You want to run both this? Okay. So you want to print out this way. Right? Well, there is, I could write this. You want to do with just one channel? Or with, because I need another channel to, or weight group to know when these are finished. So I can break the forward loop. I need something else. No, it doesn't need to be too tight. But you want, yeah, it's a little bit more complex. You need something to wait for. For example, I can run this, but this is you getting a deadlock state as well because we didn't close the channels with a channel. We only have one channel. So I need to have another channel to control the states. So I know when these two tasks are finished or something else, the best thing it would be, I think it would be to do this. Actually, I have an example. Let me show it. It is here, this example. It would be, I can send these examples after. So you have this. So you have your go-routine two and your go-routine one. You can see that both are running and printing out. So what I have here, I have two channels. Oh, this wasn't good, this. So I have two channels. And each one for each go-routine. And I have this for loop that is like the while two. And I have to select to get the value from go-routine one and go-routine two. And as you can see here, after I run the for loop, I close channels. And I can see if the channel is closed, okay, will be false. And I set to new. And I can see after the selected run, if both channels are new, I can break the for loop and exit. So best way, I think it's with multiple channels. Select is used to select multiple channels. So we can listen to multiple channels. Okay, so this was pretty much of what I had to show to you. So let's go back. And well, conclusion. My opinion go is a simple language. There is some difference from Python that you need to get used to. But when you learn and understand that differences, it's quite pretty easy to work with channels and go-routines. Go is concurrent, very, very, very good for concurrence. It's a robust language and it's also fun. Python is fun, Go is fun. C++ is not that fun. So if you use C, you can try to use Go You can try to use Go for some applications and you see that it will be probably easier to maintain and to work with your code after some time. Okay, next steps. If you are interested in learn more, golang.org, that website that I showed with the packages and there is pretty much everything about Go there. tour.golang.org, it's kind of interactive way of learning. You see some explanation, you see some code, so you can run it in the web browser. You don't need to have anything else, just a web browser to learn in to tour. There is the golang forum, golang notes and the golangbook.com. There is a free book that you can understand the basics of the go language and the same author in the same website. He has a paid book that you can get in Amazon or any other portal. So if you like the book, the free book, maybe you can help the author with the paid version of the book that is more complex. So thank you. If you want to talk with me, I know that we finished before. We, yeah, but I don't have anything else and most people left. So if you want to hang out after, we can talk more about Go or the difference of Python. I hope that you learned something here today. And thank you. What I do, right now I don't work with Go anymore. In my previous job, I mainly use it Go for microservices, so back end. And also web APIs and things related with networking. Right now I'm mainly working with Python in my, so. I think Go is producing complete binary with all the libraries linked in, yeah? Yeah, that's a good thing. If you import anything from GitHub from wherever any source and you compile your code, you just have one single file. So you don't have, for example, you don't need to have any libraries installed on your computer because sometimes with C, to run some application, you need to have some libraries installed in your computer. And this sometimes is a problem because you're trying to run something that is incompatible with the libraries in your system and you need to get the source and compile it by yourself. So this happens a lot. If you compile, yeah, if you compile with Go for Linux, it will pretty much run everywhere. But in practice, I could have mentioned that you have a continuous integration of all your Go applications because if there are some security fields and some libraries, you have to recompile your application each time until you install it. Yeah, that's a good practice of programming. You need to have continuous delivery, continuous integration, so you can pretty much update whenever you want. If there's a new library and I have to take a pilot and I can feed to an application. What about each manager? I used a lot of Go vendor in the past. It's not the best one. There are some big projects like OpenShift, Origin, OKD. They use Glide, but Go is introducing its own package manager. So you can use it in the version 1.11, but it's still a feature flag. You need to enable it to use it fully. But in the version 1.13, in August, it should be released as the standard package manager. So this is a problem that a lot of people complain about Go because Rust was born with its own package manager in the very beginning. And Go, it took some time because they were trying to get the best of the package manager. They were trying to refine because the way that other package managers works, the Go team didn't like so much. So they were experimenting approach on how they could solve that. Any other questions? Rust? Yes, this morning on the workshop. So it was my first time that I wrote some Rust code, but I just know about the language. So that's why I went to the workshop to learn a bit.