Twelve Go Best Practices - Francesc Campoy

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
👍︎︎ 9 👤︎︎ u/[deleted] 📅︎︎ Aug 22 2014 🗫︎ replies

Thanks for the talk, I think it's useful for newbies. (as a part of fully understanding of Effective go) Also I've got a silly question about WriteTo method (at the first part of the video) Why it is necessary to write a len of a name (as int) and then the actual 'string name' bytes to the writer? Thanks in advance.

👍︎︎ 3 👤︎︎ u/q1t 📅︎︎ Aug 22 2014 🗫︎ replies

The slides are pretty good, have read them a couple of times. So, if you are like me and avoid checking videos as much as possible, check the slides (posted by /u/pstibrany above)

👍︎︎ 2 👤︎︎ u/rberenguel 📅︎︎ Aug 22 2014 🗫︎ replies

It's a really boring talk.

👍︎︎ 2 👤︎︎ u/car-show 📅︎︎ Aug 22 2014 🗫︎ replies

Any one has a way to understand the ReadWriter interface?
I couldn't make sense for any of the first example in the slide, it's probably because I never used that interface myself.

👍︎︎ 1 👤︎︎ u/Simpfally 📅︎︎ Aug 22 2014 🗫︎ replies
Captions
okay so yeah in Franciscan poit and I'm a developer advocate for the Google cloud platform but actually I work most of my time with the go team so I've been working with the go team for two years and a half now and since then I've been riding pretty much just go and JavaScript because there's web pages that I have to do and I'm really happy with it so I'm going to be talking about go best practices so first of all why is the best practice so Wikipedia is the source of all truth so a best practice a method or technique that has consistently shown result superior to those achieve with other means so for me it's basically something that normally works better and better for me and go is they it produces code that is simple it's readable and it's maintainable doesn't mean faster and actually muscle the code that I'm going to show it's going to be probably slightly slower but actually the code base that you're going to end up having is going to be way easier to understand and depending on what language is coming from actually having a 1% slower it's not going to make a lot of difference so these best practices for to have a healthy code base again if you need something that performs really really fast of course you can always write some part of your code which is just the code that needs to be really really fast in a slightly not that beautiful way but the rest should be should be readable ok so I'm going to start with bad code so yeah this is pretty awful code but we have it a struct with a gopher a gopher has a CH and years in the name and I want to implement this function which is right - so given a writer so there's actually a there's an interface in the i/o package if you know it which is writer - so it given a writer it returns the net the number of bytes that it has written and an error if something went wrong okay so what I have to do is I have to write first the string and I'm going to be writing it to a binary channel so I have to write further string than the integer then we turn everything so what I start doing is again going to write binary of the size of the string because I want to say this is the size of the string then I'm going to write the actual bytes so I do that getting the length of that string that I want to print has any in 32 because go for names are short and I'm going to print that I'm going to write that into binary so I'm saying okay write that is little endian into this writer and that could fail that could return an error if that error is nil it means that everything went fine I'm going to continue and I'm actually going to say okay so I wrote 4 bytes because 32 bit is 4 bytes and then I'm going to try to write the actual strings the actual string as a slice of bytes so I'm going to actually write those bytes into the into the writer again this could fail I'm going to add the number of bytes because that will be even if it fails it might have failed after writing some bytes so I'm going to write I'm going to add those numbers and say okay so if it doesn't if you didn't fail now I'm going to just write the H in in 64 because Gophers can grow very all and check if the error is down if the error is nail that worked out so I can add four bytes to the count and then return return and return so this is code that is really bad and what's the first thing that you could change I mean there's a lot of things to change in over the urger yeah okay so in go there's something that we do very often that it's early return so do what is the shortest thing to do first so in this case the if the error is not nil what you could do you could just return you don't have anything to do so that's we're going to just change that and all of a sudden the code looks slightly better so now what we're saying is we have the same steps all the time exactly same steps is exactly the same code just doing early return so early return is something that we do very very often that's why and go actually we don't write it else that often it's kind of surprising that else is a keyword that we then use very very often in go so and also the fact that there's less nesting so less tabs it's not only good because it looks slightly better it's also good because when you're reading code you can actually forget about so you say okay did that fail you're done you don't have to understand it's like oh if you're inside of that if is because that error before was actually nail it's like you just keep on reading code and looks it's like you're telling a story so that's the first bear best practice early return very important then again one of the things is we're repeating a lot of things here we're running into binary increasing the size writing to binary increasing the size right into binary increasing the size so that's not very good idea there's the DRI principle don't repeat yourself which is not really really important but when you can apply it you should so we're going to try to do that so what I do is I create this type a bean writer I being writer it's a thing that writes binary stuff and what I'm going to do is I'm going to have a writer inside so when you write into the bean writer actually it's going to write into some other writer and I have the number of bytes that I've written in an arrow is something fail now the right method what it does is it checks if something before fail if something before fail I don't do anything and done but if it did if so far all the operations : this writer were successful what I'm going to do is I'm going to write whatever value I got so it's an anti interface any type is an anti interface because an empty interface is all the types that implement at least no methods so that's any type so it's like the equivalent of Java to object it's the global thing so we're going to try to put that into binary and if that is know if that doesn't fail we will increase the size of bytes that we've written so now thank you I I cannot close it okay thank you Apple anyway so now with this type which is this tiny little utility type that it's not really that useful but you know just right here our code looks like this and it's exactly it's doing exactly the same thing now what I would say is like I'm going to create my bean writer given this writer that the writer that I got passed from from the right - and I'm going to write first the length of the string then the string then the 18 years and then I'm going to return the size and the errors from the from the bean writer and that's it it's exactly the same code but now all of a sudden when I read this code I know what it does when I read this code I hate the developer that brought it so this is now this looks like pretty good code but there's a little problem again which is imagine that there's a new developer that comes we add a new field to the gopher and it's a string and he doesn't realize that actually you have to write first the length and then the actual the actual string he forgets about it and that's probably a nice bug to find so what if instead of having this this information on your code we just move it to the beam writer so what we can do is we can use a switch type on our write method and say okay you can pass whatever you pass you whatever you want to pass if what you're passing so this is switch with the type so basically we're and saying is switch on the type of the visa interface and anti interface so I can say oh if the type of V is a string then s is going to be V as a string this is what we call a type assertion so if that doesn't work if the if he is not of type string it will panic we know that it is in this case because inside of the case so otherwise couldn't work and we say okay so if it's a string actually you have to print first the size as a in 32 then the actual the the the bytes and if it's an integer I want to print them as in 64 integer int is of a variable size depending on the architecture so we want to make sure that all our machines have the same format and otherwise do what you were doing before and now our code that it's kinda hidden now let's just write the name and then write the age that's it now this something that we try to do with go which is the code should be very simple to to read and with that repetition with that stutter and there's a thing that we repeat here which is oh if it's a string get it a string if it's an integer gaze and an integer is there a way to model to remove this line at this line yes exactly so what you can do is you can say that V dot type you're getting that value and you're declaring as as far as a variable and this variable will be available in every single branch in every single case but in every single case it will have a different type meaning that now X in this case is a string so you can do length of that string but in here it's an integer so you can actually do the n64 of that and in this case default it would be empty interface so the type of X and here is just empty interface which works so now with this the code is just like it was before here but now it's just slightly simpler two lines less but can be useful yes now int is an integer that is the size of the machines the how to explain it so if your machine is a 32-bit or 64-bit you have eight of six 32-bit or 64-bit so when you don't care about the size of your int you just use int if you actually care and if you're running to binary you should care you're going to write either in 32 and 64 or in 8 or 16 or whatever you want to use okay so now what we're going to add on top of this is imagine that we're actually encoding binary in to network and that we want to either write everything into the network or nothing we don't want to start writing an offer and then fail in the middle so what we're going to do is we're just going to replace the number of bits the number of bytes that we have written before by a buffer so this is a byte stop buffer which qualifies it pretty well it's a buffer of bytes so what we're going to do is just simply changing this line here so before what we're doing is we write it into the into the we write the value into the writer and we count how many bytes we wrote now instead we're just going to write it to the buffer that's it but now the problem is the buffer has to be flushed if you don't flush the buffer you're not writing anything into the network so what we're going to do is modify our code to actually call flush and it turns out that flush returns two values the number of bytes that were written and an error if something failed so actually what you have right now is you're saying okay when you do flush on this writer if there was an error before say you didn't write anything and we turn that error which could be something like this gopher is not a good gopher couldn't encode to binary at all so I couldn't do it but if that part worked then it will actually flush that buffer into a network and now this could fail again but it could fail because the network is down for instance so the different errors so with this actually you end up having code that is really simple and it's really easy to understand compared to what we had before way easier to understand but as I was saying now if you're calling this and you and your your gopher had 100 fields and the first method fails you're actually going to still do the 99 method calls that go after that so this means that eventually this could be slower but I think it's worth having code like this well the code before and pay the price of having of having a little bit of overhead now we're going to see another piece of code which is something that we write pretty often which is web servers this is pretty much a whole web server except for missing two lines of code and I'm going to show but basically when you write a web server you have HTTP handlers and the signature for an HTTP handler it is Doug Lee this it's a it's a function that we that we received two arguments the first one is a response writer which is an interface and you can do multiple is one of the things is to write that's why it's called writer but also you can set either headers and you can set the status code so you can say 200 or 500 or whatever it happened and you also get a point or request and the request contains all the information from the incoming request so and this is the type that it has to have so you cannot modify it so this means that it doesn't return an error so if you have errors during this function you actually have to handle them I mean that you're going to do something and if that fails you're going to handle the error in some way so in this case we're just creating an error page with the status internal server error also known as 500 and we're going to log some error and then we're going to return then we do something else and if it fails we do exactly the same thing so you're gonna you might end up having this code over and over one of the solutions could be to write this in a function but actually there's a better way which is what we call function adaptors if you come from Python very often they're called decorators but it's exactly same idea if you think about a decorator in Python it's actually a function that given a function returns a function but when you read it in Python it's really hard to understand because actually you don't have any type so it's kind of magic you go a decorator is this function that receive a function and returns handler func actually hunger funk is also a function its handler func is the function that matches exactly this signature here this is actually also known as handler func so now our function what it's going to do is it receives a function that is exactly the same thing but this one here returns an error okay so the incoming function returns an error the one that will return it doesn't so what we do is we just call that function and we handle the error that's it now our handler here you can actually return the error so this function here do this if it fails just return an error do something else if it fails it returns an error so here we like doing these that fail that's all the information that you have to add you don't have to say log it to the so log an error or create a whale flying well whatever you want to create you don't need to do that that's going to be managed by only this function here and so what we're doing is this function given a function we turn down of the function Hudler func a handler func is actually the same thing as this type here we do this very often to add middleware so you could imagine things like again if you're managing you're creating the web page and you fail while you're creating it if you have already sent any bytes to the responds it's too late because you're going to send headers so if you say 200 and then you start sending your output and there's like no no no no 500 sorry that's too late you're going to do that so very often what we do is you will actually have a buffer so you will pass to this function will pass a buffer and only when the error is nail you will actually flush the buffer otherwise you will generate an error page so you will see that pre often okay and now a little bit less about code and now how to organize code in general I've seen a lot of code and one of the common things is you start always by license if you are in open source and you know writing licenses you're not doing it correctly because you're not writing a good open source then I seen it very often especially with code that I like and I want to reuse and I cannot so write licenses also we have build tags build tags and go are actually pretty cool tool that allow you to compile a file depending on some tags so the text could be the version of the compiler so you could say actually these act these words on one two three so on one two three we added some really cool thing that you want to use you can write that code and say and if it's less than one two three I have this older version that is not as fast with whatever so you can have different code we use it also very often to say oh if you're building these for App Engine use this file that it's going to use the correct thing for App Engine but if you're running it locally build these are the one that actually defines the main package so you can have this in these things per easily then you have package documentation which is very important and then you have the important statements the import statement we sure we sort them alphabetically which you don't need to care because there is go font that will do that for you so don't fund is this really cool tool that you can call it Priya printer but it does more and more so now we don't use the new go families go imports nobody uses go fund anymore and go imports in addition to that it will actually write the whole import statements for you so what it the way we do it normally is we start with the standard library so all the packages from the standard library at first then blank line then all the packages that are import from through PI libraries and then blank line and all the packages are importing from your own code so I'm just going to do this little demo I'm going to create main dirgo ok so I'm going to just write function main hello this is not correct go code there's oh I'm gonna make it even worse okay like this this is actually there you go beautiful go code okay so this this is really bad girl code but it's not matching the format van addition to that it doesn't even compile for two reasons one every single go file starts with package I'm not saying package main here so that doesn't work and also bumped is not declared because font is a package that I'm not importing so I'm just going to save and that's it it will do it for me so and you can do cool things like if you have used gorillas before I can use gorilla to router and it will is it I know route there you go so it's able to find all the packages inside of my goal and my goal path and find the packages with the name that matches this with an identifier inside that matches the second part so anyway so that's the import five and then the rest of the code is pretty much whatever you want to do but actually I've seen a lot of people that start so I guess that if you're coming from C++ you could actually imagine that you're going if you have to declare in you know in order so you have to do pre declarations and all these things go doesn't need that so and go actually the best way to write your code is the first piece of code should be the most important one whatever that is and normally the hand all the utility functions and all the code that it's just there to help the rest of your code that's going to be at the end so when I start writing when I start reading a file I'm going to read first documentation oh these packets does this and it uses all these things and this what it does rather than actually having something like helper utility that that's something weird that I don't know when it's called so this actually so this again these are convention but I think that this is the best way to write your code except for the license license is not a convention okay so documentation is very important you should always recommend your code so the first document the first part of the commendation that we have is the package documentation which is just so I heard someone doing asking saying that go duck is like Javadoc and it's not go doc is text that's it we'll have any special symbol to represent parameters or return values or now it's just English or whatever language you want to use but basically what you say is a documentation for the package is going to be read before package without with a blank lines if you put a blank line actually will ignore it so no blank line between the end of the comments in the package line and then just code so sorry code text it's also very important so in go when you have a any identifier might be viable types functions if they identify err for that thing starts with a capital letter it's exported mean that it will appear as part of your API meaning that you should document that if it's not documented it you will have documentation that only has code and not text if it's not exported it's also good to the commanded by it's not as important so for instance in this case what fly in this case we have this type auth ER and if you check actually I think that this change it yeah it is changed but anyway not important we're going to get something else so out of the code you're going to get this pretty beautiful documentation so these are to generate it from the code directly and you can go around you have all of this is just code and at some point you get to the index you can get all the constants all the variables you can see and when you get to functions you can actually even click on the code on the name and you will see the actual code defining that that so this pretty useful this go dot org by the way and it's really really useful it allows you to find any kind of code so you can search for anything so if you're interested in doing mp3 you will find mp3 encoders and decoders on these kind of things so really useful got up now especially for people coming from Java names and go are short to the point that when we have local variables very often they will have just there will be just one letter long so it's very often very usually you're going to see a variable called I which is for an index and until we make sense and coloring it index it's not going to help in any way so I is just good enough and that's the that's what we use normally is if it's one letter is enough sure go for it when you're actually exporting something it's going to be used from outside then of course you're going to have to be slightly longer so but it doesn't mean the longest name it's not more useful it has to be as long as it needs but as it has to be readable understandable and sexist self-explanatory I mean that for instance in the JSON package we have Marshall indent and you we could have written Marshall with indentation which is better English but it doesn't really add anything and you have to write it at some point some people say oh well you then we need to write it because your editor is going to do it for you okay you have to read it we spend more time reading code than writing it so actually the length of an identifier you're going to read it a lot of times so you have a type or something like that the sugar is the easier to find also it's important to say that when you have a package in go to use any identifier from that package you have to write the package name again so the JSON encoder it's just encoder because part of the JSON package so to use it outside of the JSON package you have to write json dot encoder so calling it JSON JSON encoder doesn't help so it's important like bytes the buffer it just bytes the buffers not byte buffer bytes and then also a in go you can have as many files as you want so you can have only one package per directory okay so in in a single package in a single directory all the files that you might have belong to the same package but you could have only one you can have multiple what good you have multiple ones first reason is to avoid having 10,000 lines files so pretty bad idea especially if you're going to have to merge them it's gonna be fun also it's important to separate code and test actually in go we have a testing library it's part of the testing packages for a standard library it allows you to do tests and it actually separates what is test and what it's not by this convention of writing and the score tested go anything that it's underscore test that goal is ignored when you do go run or go install or go build it's only taken into account when you do a go test so it allows you to separate your code very well and finally it's a bit to separate the package documentation meaning that imagine that you have five files where did you put the package documentation maybe there's a very good place to put it but most of the time there's not so what we do is we create a new file called duck don't go that just contains one line at the end that says package and the name of the package and all the rest is just documentation so you will see that very often so if you check the standard library you can find it in net HTTP I think yeah an SCP is 47 files which one is the one that should have the documentation doctor go it's just easier and finally you could we should always be go gettable and if it's not yeah I know if it's not if you could still have a very successful project but but anyway it's better to do it so go get is this tool that will allow you to download all the code directly from any public repository it will compile it I will install the binaries the corresponding binaries into your go path slash bin so all of these it's it's built in a way that actually if you follow the conventions get you working with go code it's just very very simple what we do normally is you separate your code into two kind of codes one is reusable code the other one is good that you're not gonna ever use it's impossible to use what kind of what kind of code is it possible to reuse main package main package you cannot import it so you can never use it so very often what you're going to see is this actually from candy store which is a project the Brad Fitzpatrick wrote right I think it's a very good example of what go code should look like and you have two different directories one is common that contains different commands so can get can mount and instead of each one of these there's a main that go when you build that code the main that go file will compile be compiled to a binary name can get come out or can put or whatever so this is actually very easy to just install everything and these binaries will appear in the go path binary and then the part that you can reuse and the part that you can reuse you can start with package that's a very good way to do it you can rename it whatever you want but package is a very good way to do and you're going to have for instance authentication maybe that's an indication for candy store is very useful and you can use it in a different project so if you do it this way people will be able to reuse your code very easily if you have a license so it's important to just ask what you need for so if you are running code use interfaces this example right - so it's again the same go first before you can say oh right to file and you're going to create this right to file method that given a file it writes a gopher to that file and the code is going to be very simple just going to call right that that enclose probably now the problem is that what if I want to use it and I want to write it to a network now I have to change my API so actually it's like oh actually not with writer rig writer is an it is an an interface on which you can do read and write but actually you don't even need the read part so just do I owe that right which means that now just probably the code inside didn't change at all and now it what it means is that right to writer would also known as write it will allow you to write that gopher into a file into connection into a zip encoder or whatever you want to use so it's really important to have the smallest interface that you can add your input also this is something that is took me a long time to understand when I started working with go which is the fact that having implicit satisfaction if interfaces meaning that when you satisfy I mean when you implementing an interface you don't need to say it you don't need to write implements something and go you don't need to do that and it actually allows you to write really good code which is completely independent one of the other and still works so this example it's a real example but with really bad code that I wrote and what it does it's actually a web app on which you write a function method I'm sorry a mathematical function so X square whatever you want to write and there's two parts one part will parse that into something that you can execute and the second part will render as an image so you will get an image with that function whatever it is so what I wrote was this code pretty much so it returns so I call parse with a given text and that returns a function and then I call draw with a function and that returns an image and then I encode that image and then done crazy so this is actually the whole code now the important part is parse and draw those are the big things so I started writing this code okay so the complicated part is not here but basically there's this parts func method as type that has the text that I parsed and then the resulting function which is a vowel and it has so parse returns a parse funk and it has the method eval which is the only important one because when I call eval I'm going to evaluate that function so if I have x squared if I pass 0 I get 0 if I get 1 1 2 4 so on so this is actually pretty simple now I will draw and what it is like oh so my draw what it does it given a part um it writes it just creates the image ok pretty simple but now all of a sudden draw parse func it gets per thunk and it will depend some parser so my parsing depends on my na my drawing depends on my parsing and do I need that no actually I could say Oh actually I just need a function and that function has a method eval and that's an interface anything that has an eval method that given a float returns a float works for me the rest of the code didn't change so what I'm saying here is all of a sudden my draw package is complete independent of parse it just needs something that it can evaluate which means then now I can test it so I can create I can pass anything that is a function so and that function could be may test funk which is an actual function so that function could be where's this here math dots sent to calculate to go to the that operation or I could do the identity function which is just returns the same value and this allows me to write code that actually it can test really easy and say Oh even getting the identity which is passing here I expect this result I don't need if I have a bug in parse draw will keep on working anyway so this is important to have as many nice little dependencies that you can and now for concurrency so one of the most important things of go is that we have a very useful concurrency and it's very powerful which means that people use it which is good but sometimes they use it a little bit too much so one of the things is using putting concurrency in front of your API it's actually pretty bad idea so let's see why I create this function which is doesn't do concurrently that given a job which is in this case a string but it could be a function or whatever you want to do it calls that function inside of a instead of a new go routine so actually we'll execute something later on okay it doesn't wait just say okay this will be executed at some point and to do that actually you have to pass a channel of errors because that time of errors will be used to send the error so basically the do concurrently start some job and says once you're done send the air the resulting error to this channel which means that now I can create a channel of errors and start three different jobs and just calling do concurrently those three jobs will be executed concurrently so eventually in parallel and now I can wait for the errors to come back into that channel so basically you start all of them and you wait for them to go back so these pretty useful code now the thing is that how do you change it to do this sequentially actually what you have to do is you have to create the channel anyway call a function waiting the channel call the function where in the channel call a function waiting the channel little bit of a pain now let's do it the other way around and just have instead of do concurrently have do now do what it does is just what it has to do that's it and instead of putting there in the error and a channel just returns the error now if we want to do to call the same way as before so concurrently what we have to do is we create the channel and then we call the function now we're calling the function and sending that the result of the value that the result of that function we're sending into the channel so this is the only difficult part that we have to do the fact that oh this is actually calling pink call in concurrency and we're passing the result to the error the to the channel and then we wait for them so it's pretty much to do it concurrently this code and this code are actually really similar just just two lines extra but now if you want to do this control sequentially it's a for loop the day so actually when you writing go if you expose sequential AP is using them concurrently it's very easy and using sequentially it's obvious so normally avoid having channels and all these things in your API is it makes everybody's life easier and now the best practice for concurrency and there's an opportunity of winning gopher so I will ask you a question so pay attention please I'm almost done don't worry okay so one of the things is we use go routines very often and very often we have a so in this example I have this server and what I want to do is I want to start a go routine that manages the state of this server okay so what I do is this server which is a struct e I create the server when you the new server it creates a server so it puts a channel inside we'll see what the channel is for a little bit they run and it starts the run function in a different go routine okay now you can do this very easily the problem is how do you stop it when when you're done with the server what happens if you don't have any way to communicate with a goroutine you cannot stop it which means that you can end up having a lot of go routines running for nothing and that's actually memory then you're wasting so what we do is actually we use this quick channel so our run function it's doing an infinite loop so while in go it's written for and if you just write for that's any free look so there's an infinite loop and it does select select it tries to do multiple operations on channels at the same time so what we're trying to do is to read from this channel which is time that after so every second we do something so that that would be we're doing the word that we're supposed to do the server is actually responding to queries or whatever it's doing by the same time we also have quit include what I will do it will just quit don't pay too much attention to this code yet basically what it's going to do is okay so I'm going to just finish we're done so now we can actually say we stopped we can send through to quit this go team will receive that value I will finish now the problem with this is that imagine that stopping your server takes a minute when they call stop I'm done the main function finishes and everything finished and I didn't free any resource so actually when I call stop I want to wait for the server to say yes I'm good so one way of doing it is actually reusing this in channel what I'm going to say is I'm going to say stop and I'm going to wait on the same channel to visit to receive another boolean saying and done so we're going to use the same channel to communicate both ways so now this when this code gets into into action so we're going to say okay now we're stopping I'm going to wait for a second and then I'm going to be out now now I'm actually done and I'm going to send the signal to the client that is to say now I'm done you can stop so if we execute this code you will see branding task then server stopping and finishing tasks and test done all of that is the server trying to stop and server stopped is finally when stop is calling ok and now this for a gopher there's a bug so you can you cannot answer today's though okay so I'm granting this code which is send message and send message what it does I have a list of addresses and I'm going to broadcast a message which I say the message and a slice of strings which is I'm sending this message hi to localhost and then to Google and what I'm going to do is I'm going to send all of them and then I'm going to wait for a second which is a really weird thing to do but why not and actually then I'm going to check if the error was Neal if the error was Neal then we turn the air and everything went fine otherwise so this is not the point code the important code is the one on top so what I'm doing is now the important code is here yeah the important code is this so broadcast message it's here vodkas message is the one that giving a message and all just all the addresses where I want to send a message what I'm going to do is I'm going to create the channel channel of errors I'm going to start all the sending at the same time so I'm going to send I'm going to try to send a message to all the receivers at the same time and then I'm going to wait for so I'm actually expecting as many I'm gonna iterate as many times as addresses they are so I don't care about anything so I put an underscore I don't care with the index or the values I just care about the number of iterations and if something fails I'm going to return that error and otherwise everything finished correctly so then read from the bottom now wait a second wait a second now you're going to read that and whatever this just multi-rate anyway don't read the part on the bottom but can anyone say what's the problem with this without breathing the part on the bottom they made me write this because the slides are online so it makes it easy for people not here but it also makes it people for Shi V Z poor people for people here so what what's the problem no no one there's a gopher here okay yeah so actually that girl routine will be leaked so it's the same way we have memory leaks we can actually have goroutine leaks and we have a goroutine leak by so it's other consequence you also have a memory leak so that was cool but that was written so how do you solve it how do you fix it yeah that's it so yeah you got the gopher so there's two solutions one which is the ugly one which is saying if I find an error I will still iterate as many times as I need and I will just pay attention to all the errors that are coming back so I will actually read all those errors the crime is that what if you don't know how many years I might come then you might wait forever so instead what what we do is what you said we say that this channel we can write as many values into it without blocking as addresses we have so now even if we didn't read any value all the your routines are sending values and sending errors into the channel we'll be able to send that error into the channel finish and then there will be garbage collected once they are all garbage collected the channel itself will be garbage collected if you have a goroutine that it's locked it's actually keeping a reference to that channel so the channel is not garbage collected and the girl routine will will a 1-bit garbage collector either so this these are tricky thing so free go so there's also a different way which is when you don't know how many how many addresses they are in this case we know but imagine that you don't know how many values you could actually send into into the error channel what you can do is something similar to what we had before which is using a quick channel and now our quick channel is a channel and what we say is before we start we say ok we create the channel their Channel and the quick channel and we say at the end of this function whatever happens and I don't care about the way I exit this function call this closed that channel the creat Channel and now our workers they will try to do two things at the same time one is sending their error into the error Channel but also they will try to read from quit so now you have eventually hundreds of goroutines trying to send errors into this channel and you will take care of only one you will receive the first one and if that's an error you're done and you return but when you return quit is closed and when you closed quit actually when you're reading from a closed Channel you don't block when you read from a closed Channel you receive the default value of that type so all of a sudden all the go routines that are waiting here they will be able to read from quit they will all get an empty struct which is empty it has bite it has zero bite in it but it will actually be a signal so you can actually broadcast so algorithms using clothes it's a pretty cool technique and all of sudden you are sure that with this code go routines will never be linked any questions about this code this is actually the most advanced code that I'm going to show I'd probably the last code that I'm going to show which is good okay so yeah so these are the 12 best practices that I showed so avoid all the nesting by doing early return void repetition so right little types that may help avoid that repetition like the bin writer that we that we did the important code goes first but before the important code goes the license and documentation shorter is better at least four names packaged with multiple files it's a good a good idea to have them rather than have huge files you should make your code go gettable please and have your functions using interfaces as much as you can and the smaller interface that you can work with and three not four last ones so yeah break all the dependents that you have avoid concurrency in your ap is use go routines carefully so both to manage state and try to hide them as much as you can from the from the usage of your library so from outside of the library in our server that go routine didn't even exist we just had to start and stop that's everything and finally don't let go routines because leaking go routines is bad so yeah so if you want to learn more I'm pretty sure that the golang.org you've already seen that before you already have you also have the tour which is for the best way to learn go and even if you've ridden some go it's still a very good resource you end up writing pretty cool stuff you ride at the end of a concurrent web crawler that's pretty cool and then there's this my favorite go talks lexicon sconnie lexical scanning with go if you've never watched it is actually Rob bagg presenting how to write a lexical scanner using goroutines which makes a very beautiful code and how to at the end remove the go routines and still make it work it's actually it makes really beautiful code I think it's you should watch that concurrency is not parallelism which is more like about the philosophy behind what is concurrency what is parallelism they're not the same thing and if you think they are you should watch this talk and then Congrats the patterns in advanced concurrency patterns so if you want to learn more about the things that you can do with covert chains these are definitely worth it so yeah thank you
Info
Channel: Esri R&D Center
Views: 62,555
Rating: 4.884892 out of 5
Keywords: esripdx, golang
Id: 8D3Vmm1BGoY
Channel Id: undefined
Length: 49min 27sec (2967 seconds)
Published: Fri Aug 08 2014
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.