7 common mistakes in Go and when to avoid them by Steve Francia (Docker)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
all right first thanks for staying and for those that aren't staying thanks for staying that long it's fine I'm not offended I'd ask we've been here a long time can I just stand up and stretch because I feel a lot of people here yawning and getting tired and we all kind of need a little just don't leave like stretch enjoy yourself okay that felt good didn't it that's good all right all right now so I'm going to talk to you about it which honestly probably my most personal talk I've ever given it's seven comma stakes and go and when to avoid them fantastic introduce me or get darker also written a number of libraries and tools and go and the reason I highlight them is because I'm actually in talk about these aren't common mistakes these are my common mistakes that I've made in go and I've seen it other things and maybe you're making them too all right so how do you feel when you see that does anyone else experience a bit of pain we've been conditioned in this country and maybe a lot of countries from one we're very young that failure is a bad thing and that we shouldn't fail and it experiences pain and anguish whenever we see something like this and it's because it's so deeply ingrained in who we are the failure is something that should be avoided at all costs this is a quote it might as well be from Yoda it's not but it says do you all know the difference between a master and a beginner the Masters failed more times in the beginners trot and edie Catmull founder of Pixar said we need to think about failure differently most people think mistakes are necessary evil mistakes aren't a necessary evil they aren't evil at all they are inevitable consequence of doing something new and as such should be seen as valuable all right go is a new language relatively speaking I think a lot of us are trying to do new things with it just consequently we're going to make mistakes I personally make lots of mistakes and there's a human tendency to want to cover up our mistakes and not to broadcast them and I'm completely fighting that human tendency as I share my mistakes with YouTube and all of you in this room and anyone who watches this video later so do we know who this is it's also someone else his name's Michael Michael Bluth from a TV show Arrested Development and if you watch this show you you generally relate to this character because he doesn't want to make mistakes there's another character who makes huge mistakes who we laugh at and don't find is relatable and hopefully by the you'll see kind of a contrast here so the first mistake and a lot of these are related to the first every one of these mistakes are ghosts specific they're not general programming mistakes they're part of the language most of them have to do with what I think are the two biggest new features one is concurrency and the other one is interfaces which guess some exist in other languages but the way govern go does is unique so the first one is not accepting interfaces now I think it's important and this is another storm is pretty go savvy it's one recognize that in there's state and behavior these are two fundamental principles of computer program types can go can express both state and behavior state is equal to the data structure and behavior equals the methods interfaces are one of those most powerful features they permit extensibility they're defined by methods meaning that go interfaces are behavioral only the adherence is satisfied only by behavior not at all by the data structure not at all by the state so I want to use an example from hugo if you haven't heard of hugo it's the fastest static site generator there is just a little little story about this we got a bug report I don't know six months ago someone's trying to build something with like 15,000 posts and they said they tried every static site generator that there was most didn't ever finish hours later had never finished most crashed one finished in an hour and a half Hugo finished in ten seconds so it's fast now most people do also don't have 15,000 posts but if it can do that and ten seconds it can compile your blog a lot faster than that and so this is this is all code examples from code that mostly ira so first one is don't do this so what are we trying to do here first just setting up the stage in this slide we've defined a new byte buffer and we're writing to it there's nothing wrong with that specific part but the next thing what are we doing we're grabbing the bytes and we're passing them into another function and the signature of that function here that only accepts a byte slice and what does that do well it creates a new reader all right so we've gone from something that satisfied a reader to extracting the bytes to to creating another reader from write and you look at that and it seems pretty obvious but if you look around go code you'll see things like this all it's not just in my code it's in a lot of other people's code too so instead right what's the solution is pretty obvious here all we do is convert it instead of taking a byte array we're going to convert it to take an i/o reader and in doing that it were taking interface instead of specific data type and it's a lot more efficient so mistake number two is piggybacking on that it's used not using i/o reader and i/o writer and it's a you know if you look around different libraries it's amazing how often this is not being happening so what our i/o reader and our writer they're simple and flexible interfaces for many operations around input and output they provide access to a huge wealth of functionality and I really want to underscore how much you can do with with these two things and they keep operations very extensible and they're really simple I mean you can't define simpler interfaces than these and you know light of time you can read it but the reader has a read method that's the behavior it expects and the writer has a write method that's the behavior it expects so here's an example from Cobra CLI commander which powers kubernetes and Hugo and so this this line is actually one of the most powerful lines in the entire program what this does is it lets you for each command like a command is like git clone and clone would be the command it lets you define a specific output for that because we've enabled it to be IO writer it accepts a whole slew of different outputs logging systems Network layers there's a whole lot of different things you can do in this case would default to OS standard standard error which it again adheres to that same interface VIPRE is another tool it's another it's kind of a companion to Cobra unless you do configuration management so it automatically reads JSON and Tamil and the mo files and environment variables and remote key value stores and you know this is right from that go there's actually from a pull request I didn't write this one but it was a great learning experience so someone contributed this read buffer config and they passed in buff bytes buffer right there's nothing wrong with this code this code runs fine it works really well but it's very prescriptive about what's going to happen right much better is to define it as an IO reader which by its buffer adheres to it adheres to that interface when we do this enables our code to be much more extensible now now people can pass a whole lot of different things into this whereas before we're very prescriptive by the way for me if you have a question just shout it out well not a raise your hand or something but like I don't want to wait till the end and then you forgot it so so I'm assuming no ones have questions it you know I think a lot of this I think it's obvious when you look at the slides hopefully you also think it's obvious when you're writing the code maybe it's not as obvious so so third one is sorry requiring broad interfaces so interfaces are composable should only accept interfaces that require the methods that they need functions should not accept a broad interface when a narrow one would work you can compose broad interfaces made up from narrower ones so you use a couple examples this is a Faro fs it's a library that I wrote specifically to make it so I could do testing better because with Hugo we do lots of creating sites and then destroying throughout the test I don't want to write to the file system but I don't want to rewrite my code so luckily because the OS standard in different OS package defines all these interfaces really well I was able to write a really thin library that lets you do neat things specifically it gives you cross-platform memory back filesystem that's completely interchangeable with the OS package and so what do we do inside this we have I've defined a file interface and has a whole lot of different interfaces that it's composed of and it's tempting when you're defining a function throughout there RL is to say hey I'm going to include that broad interface I'm gonna include file everywhere right and if you've used other languages a lot about language it's kind of actually a pattern you look for in go we don't want to do this why don't we want to do this why don't we say well what if I don't want to implement the entire file because I have good reasons not to write but now I can't use this anymore so much better we're only using the read function so you should only use the reader interface we shouldn't use that broad interface all right mistake for methods versus functions I know this one trips up a lot of a lot of people and it did me a lot when I first started so how if you look come from an object orange background really what are the rest of you come from like I know Robert doesn't but I don't some of you just don't raise your hands I guess right and we've learned that we've been ingrained with that a lot of us that was the first program environment that we really learned and so we've been engrained in how to use it and part of that is owes a lot really method heavy and there's a natural draw for object our programmers to define everything via structs and methods but what is the function so let's kind of define it a function is operations performed on n number of inputs result on n number of outputs the same inputs will always result in the same outputs so functions don't depend on state that's how they can adhere to that what is a method method defines the behavior of a type this is very specific alright so remember it goes back to the whole interface being behaviors it defines the behavior of a type a function that it's a function that operates against the specific value and it should use state the whole point of is is to use state it needs to be logically connected with that state and functions can be used with with interfaces so method by definition or bound to a specific type of functions can accept interfaces as input so example from hugo and this is an example of one that I think is really you know pages a major data structure within Hugo because it creates website so it creates lots of pages and there's tons of methods on it and there's a big draw to put everything down is a method and initially when I wrote this function short codes are kind of like template macros and there's a there's a draw to make this a method as well and when I started was a method I looked at you know why is this a method it's not actually doing anything with that it's using it but it's using it as input the same input the same page every time will always result in the same output it's not manipulating that page and does that make sense am i explaining that reasonably well a lot of people are nodding wow that means you're even listening and paying attention this is going pretty well for none at all right so if you look here we're really not manipulating it at all we're just using it as if it was input shouldn't you be thinking about what's exported enough yes you're right you're totally right your point is valid that's it that's a very valid point so to repeat the question is why would you not consider it something about the state with the page it certainly is part of that right and you could make an argument to do this to make it a method in fact is it's not changing that state at all right it's using a state it's also using the string as input so it's using multiple things as input here the fact is it by definition of the function because the inputs and outputs given the same inputs in the same outputs it's always the same methods don't do that methods take inputs they've changed often will change the state and result in an outfit maybe it's the same output but that state change is going to be the difference now you can include it right there's not a hard set rule not to include it and sometimes logically make sense to group things together around something and often you know and going nice thing is you can actually have an empty struct or even nil and you can create methods on those things right but typically those are for logical groupings rather than treating them as methods so really they're acting more as functions of that result so mistake 5 is pointers risk values so I've heard a lot of people when I was learning ago I heard a lot of people say always use pointers there's so much faster or always used values because maybe that's where they came from right if they came from I think it's like Java they want to always use values because they want to copy everything it's not generally question of performance but it's one of shared access if you want to share the value with a function or method then use a point if you don't want to share it then use a value right so generally performance isn't the thing you should worry about it should be about access and what how you want to use it so pointers versus value receivers is another question I get all a lot I see a lot of people people don't know what to do a lot of the default answers always use the top one that's what generally people say because it's usually right but again pointer receivers are good when you want to share values and often with methods you do and because methods are manipulating things so that's a very common thing remember these are not safe freaking current access right because they're also using shared then you got value receivers if you want the value copied then you use these values if the type is an empty struck right so there's no value to it again you should use values and these are safe for concurrent access so another example from a pharaoh in this case right we're calling closed on a file right why would we want that shared right where were you sending a pointer why it seemed because we modified state that's exactly what and we want that universally modified another example this is from the time package right in the time package it does use it uses methods but it uses them on values not on point why would it want to do that anyone because time is ticking yeah that's really this one should be obvious what thank you for being the brave person to shadow an answer okay yeah yeah time was ticking all right so mistake six thinking of errors is strength so when I started learning ago all I heard about was all these complaints about errors and how go handled errors I think with all these conversations people completely missed the point of what go errors are and how powerful they can be yes you don't throw but you know you can do a lot of things with them so first a lot of people when they learn go are surprised to find it error is not a tuck what is there it's an interface it's a very simple interface it's an interface that has only one behavior to find on it it has an error method that returns string all right so you can do a lot with that so first the standard errors are often sufficient right so you can call Perrineau and provide a string and it will create a value of type error of interface that adheres the interface there you can also export error variables that can easily check so from Hugo this was some coding Hugo we created error new and we gave you know pretty standard error there all right this is fine it works but how do you compare that usually people result in string comparison and that's generally not the best way to do things so better is to export it with the variable and now we can check values right checking values there's a lot better than checking strings I see this in code all over the place there people are always checking strings or sub strings to do it this is another example of actually just the check so it's the second part outside now you can create your own custom error types and these can there's three different reasons to do this one is you can provide context to guarantee consistent feedback all right I see a lot of people creating errors they have lots of complex formatting in them don't do that I'll show a better example you can provide a type which can be different from the error value right so the error doesn't there value and its own type can be two different things and it's important and you can do lots of powerful things with that last is you can provide dynamic values based on internal error State so this is an example from docker does everyone know docker is raise your hand if you don't know dr. well I got John that one did that you're excited it's good alright so this is from docker and this is a pull request we got recently so docker is a complex program and we're trying to expand our errors and get better errors and we're trying to prepare for internationalization in the future at least somewhere to set the pull request is and so what we've done here is they've created this custom air type which has error code and a message write the message if you look at error right what is this is this is how it adheres to the function what is it doing it's it's going to has the both the error code and the string representation of the message the nice thing is you can check just code you don't have to look at the string message when you're using this that allows you to internationalization or various translations that the the message value can be different from the code itself from the ghost standard library some really good examples so this is one these are just standard errors at the top to line and cite them because it's important for the next side in this case this from the OS package there's path error that's a very explicit type and if you look at the signature here or the definition of it what does it have it has operation it's got a path has got an error and then look at how it creates it it does the formatting for you in the error function alright so when you create this error you're going to create a giving it three explicit things and it's going to automatically format it for T now this is a function from inside the OS packages to the right at one and it returns an error right and remember errors in interface so the first thing it does is returns a standard error right if F is now return a standard error invalid which is Saturday but if it's longer than that it actually and in certain conditions happen you're going to want to return a path there right path there's this explicit error type that we've defined earlier what we're doing here is we're we're giving it the three parameters that we need to we're not worrying about string formatting beyond that you can do some pretty powerful things so in this case this is a fake function that doesn't exist but what we're conceiving up here is you might be writing something and say you know what if there's a path there I actually don't care I want to continue I want to do something right I don't care what the path there is there might be four different type values for path there I don't care which one is I just want to see any path there I'm going to handle it one way otherwise I'm going to fail and I'm going to you know call of fatal another example here is this is a similar thing we're checking the type if if the types of certain thing we're going to be fine with it in this case we're actually checking for the specific value there too right so you can do a lot of things by checking with the types to remember the type can be independent of the error value itself and that gives you a lot of power with errors so there are a lot more than just strings all right mistake seven is to be safe or not to be first you can't make everyone happy you aren't a jar of Nutella all right so consider concurrency if you provide a library someone will use it concurrently here is going to happen all right data structures and go or generally not safe for concurrent access and values aren't safe you need to create safe behavior around them all right so how do you make things safe we just went through a lot of that with Aaron's talk so I won't dwell on that so with the Pharoah we were trying to model map exactly the the file system in OS so this is how it looked at initially when I coded it and it worked really well until somebody put it in a go routine and when they ran a bunch of things concurrently it blew up why to blow up because it was trying to access the same thing at the same time so what's a solution it's a simple solution it's to use mutexes and add some locks around right and for this all right that's pretty clear there now why do you want to keep things unsafe right when I so this I gave a presentation earlier and this this section I got a ton of feedback on it was mostly constructive I hadn't made a mistake so this is me trying to on that reality is there's lots of reasons to keep things unsafe safety comes at it cost it also imposes behaviors on a consumer right so if we look you know if we have to find a proper API it allows the consumers to add safety as they need and it lets consumers choose how they want to do it they can use channels or they can use mutexes whatever fits their situation so this is back to the same slide why do we do it this way why do we put our lock in here because that's what the OS package does work concurrently because it delays things to the operating system which lets things run concurrently so we wanted to model that behavior right so we didn't let it define above it because in this case it made a lot of sense to implement here because it's consistent with the OS package however maps which are part of the go are unsafe by design all right often safety as unnecessary believe that's the argument for why they're still that way it enables consumers to implement safety as needed right so I just showed an example we're using a map how do we implement it we use the lock surrounded with new Texas and the consumer of that can choose how they want to implement the safety I also don't have which I'm not going to go through because of time and because we just have a bunch of stuff on channels but you could also use channels to this alright so the biggest mistake is is not making mistakes alright so again from Edie Catmull failure is a manifestation of learning and exploring if you aren't experiencing failure then you are making a far worse mistake you are being driven by the desire to avoid and takes me back to now who do I want to be more like I want to be more like job a little less like Michael who makes a huge mistake and that's my time thank you so again we have time for like one two lessons yeah yeah when we go back to a club okay so one was the overly broad interfaces or concrete types instead in fixes Seavers you see that you know certainly go vet and other tools like that could help with a lot of these things in fact I think covet does help with some of these things reality is the reason I think a lot of these that I want to highlight them is a they're not obvious I don't think they're always obvious me a lot of them it's not obvious when to do it right sometimes there's a good reason to do one and sometimes a good reason to do it the other way and there's a lot of context involved with that that the code tooling couldn't help wit because it's not going to know enough about the context of how you're using it kind of the architecture you have behind it and again these are things that I saw myself do wrong and it you know I use a lot of libraries out there and I see it you know it's being confused in a lot of places I think the reasons confused it is it can be confusing because there's not always a clear answer so I think yes it can help with some things on the other side I think education and experience of using the tools more you know I think how much I've learned in the couple years I've been writing going and as I look through the standard libraries which I use as inspiration I think I see differences over the ones that are created later right I think even the go team is still learning a little bit about how this language works and how best to utilize it and at least Andrews nodding his head so it's those wrong and so it's Rob so I think you know this is their creation but you know just because your creation doesn't mean you you know everything about it I think all of us are starting to explore kind of different ways to do things in in it and a nice thing with the language that's so flexible in the way that it is it lets you express yourself in different ways you know we're all still learning so all right okay so if there's no more questions and just watch you all the speakers
Info
Channel: Data Council
Views: 215,169
Rating: 4.9322853 out of 5
Keywords: Go (Programming Language), Programming Language (Software Genre), Docker, Steve Francia, Golang, Go Lang
Id: 29LLRKIL_TI
Channel Id: undefined
Length: 27min 57sec (1677 seconds)
Published: Wed Jun 10 2015
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.