Golang UK Conference 2016 - Mat Ryer - Idiomatic Go Tricks

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
you know it's a great honor to be asked to come back I spoke last year and it's great to see it growing and you know it's all very exciting so this is this is going to be fun so a quick I don't really like these slides generally but a quick bits about me I I've been doing go for a long time I wanted to build something on Google App Engine and I had the choice of either Python or Java or this weird little language go which was just beaten and it was experimental and stuff which and that appeals to me so that's the one I picked and since then I've kind of stuck with it now I work at grey matter and we're our back end is 100% go and kind of micro services and all that exciting stuff I've got a few other little tiny little projects but we're running on App Engine which you can go and check out and if anyone wants to see the code for that I'm happy to share it the only reason I don't is someone will find what's wrong with it or find a way to to get in there you know almost certainly I also did bit bar no I thought you're going to cheer that's fine bit bar is an app that lets you put a tutu late lets you put the lets you put the output standard out script in the menu bar on a Mac which is kind of fun and the get bit bored comm site that goes with it is also go and also App Engine so cool idiomatic go tricks then idiomatic is basically things that are phrases that are you know natural to a native speaker and I think it's possible to become a native speaker and go and that's what I'm going to do I'm going to share some of my favorite bits and pieces some you might like some you might not I'm interested to hear either way so first of all go code this is basically what go code ends up looking like you have a few things that are distinct to go and and a few style things that aren't really part of this but they've kind of started to emerge and they've they probably change over time but they become they become standard and they kind of become idiomatic and that's what I mean really when I talk about being a native go speaker so some examples we don't have lots of lines space gaps between the the code it's all kind of sits together neatly that's one of the features we also have obviously multiple return arguments which some some languages have some don't the last return arguments usually an error there's usually two and the last ones an error and you can see here on the second line that gets something call is is actually using those two arguments and the error argument is called eerr err you know again doesn't have to be but that's become a kind of standard thing and a bit like what Dave Jani was talking about in his solid go talk you know defer defer is used because it's it expresses very clearly what you're doing and you expect something to close regardless in this case some people think well that is there's a performance hit to that and they'd rather have it they'd rather just put it out explicitly and you know which is fine but this makes it very clear what your intent is and it makes that clear to new people that are going to come and and use the code and also to yourself in the future your future self I don't mean they're going to travel from the future and come and work and do that pair programming or anything like that although be interesting I mean you are going to forget this when you look at it you sort of not going to necessarily remember in detail and you're communicating to you to yourself as well as others yeah so this is this is what go code ends up looking like so there's one other feature that I like and and I try to find the name for this and it didn't find one there might already be one so I'm calling it line of sight and essentially we have a a line down the left edge of code that tells you what code is doing and it's kind of the happy path sits down one edge which is kind of stranger if you see in this first picture you can just by looking down the edge of the function you can see what it's doing it's going to get some things going to defer the closing if something's not okay deal with it something else lock/unlock defer you know you can read it down that edge and then indent it if you look in the second picture you have all the error handling and what this does is it allows you to quickly scan the function to see what it's doing and it lets you it gives you yeah so the definition of line of sight is a straight line along which an observer has unobstructed vision and that's really what that is if you think about it looking at function you just have there's no obstructions it's not complicated you can you can just see it if we look an example of code that has a bad line of sight this is exactly the same does the same thing as the previous example but this time it's kind of difficult to see what's going on we have if something's okay then we're going to do this and we sort of the nest in words and we're then carrying on the return of this the happy return the thing that we're getting out of this is kind of lost in there whereas before it was at the bottom and so it has a difficult luck it's not a very clear line of sight to see what's happening so some tips make the happy return the last statement if possible so when you look at a function if you look at the bottom of the function you kind of want to see what's being returned and sometimes it's nice to go backwards from there to see to kind of investigate and learn about what that code is and next time you write else consider flipping the logic it's very natural to think if something's okay then we're going to do this that's how we think about it but then you end up with nesting deep and gets quite complicated so if you think about if you ever use else see if you can flip it and get rid of the else altogether if something's not okay we're going to deal with it because dealing with it usually is short and sweet you're going to get out of the function or something and you can protect that the rest of that line-of-sight single method interfaces I'm also a fan of the reader interface because of its its power and its simplicity and and and you can do this too and should I think so a single method interface is an interface consisting of only one method and you know they're they're simple they're really easy to use and as as Dave Cheney said you they can be they can come from anywhere you know you can you can find them throughout the standard library and and and using it as it you know it's really specific about what that function wants and that's kind of the key the key thing my other favorite is the handler interface which is another great example and this is has a serve HTTP takes in a response writer and a request and that's all you need to do in order to build something that's going to handle web requests HTTP requests so you won't so you know they become very easy to implement these interfaces if there were ten methods to implement in the H in the HTTP handler interface you're probably not going to do it very often if there's one sure it's easy and you only need to build a struct with one method it's awesome but you can even go in a bit further than that and this is another kind of classic go thing which is feels a bit weird initially but once you get your head around it turns out to be extremely useful handler func is a function type that has a method that implements the handler interface so it's a function that has its own method on it and when you call that method it just calls itself it just calls the function but what that means is you now no longer need the struct at all you can just do a function and you can use this pattern yourself if you find if you discover a single method interfaces consider whether there's a use for just have Phunk kind of alternative funky alternative that's not going to catch on okay another one this one's silly but I use it every day sometimes I'm looking at logs that look like this and it's just long and and I have to kind of find my way through it and it's hard to see how the function I'm working on so I'm working on this function I want to log something and see it but I've got all this other noise so you can pop this at the top log print line some dashes defer printing the dashes and that will just nicely bookend the output of a function for you and you and then you can see it just clearly you know shows you the nice thing about deferring the the slashes for the end is wherever your function exits you're going to get those lines so it's really nice and there at the top of the function so you can comment them out delete them easily enough so that's a little OneNote which you can keep okay teardown functions this is very cool I think and we've used this quite a few times essentially you have some function that does some work and and it's a great example is in testing where you have some setup code and this might change a little bit with go 1/7 but this principle applies I say that only because the testing we now have sub tests that you can make that really easy which is cool so here we have a setup function it's going to create a sample file for us to use and really that file needs to be cleaned up after we need to close it close our connection to it and also delete it so what I'm doing here is I'm returning three arguments return the file itself I'm returning a func function and or optionally in an error and then in the in the body I set that function up to do the teardown and so what I can do when I call it I immediately just defer the teardown and know that whatever's been set up inside this setup function is going to be cleaned up for me and what's nice is if that setup does different things that's okay I don't as a user of it I don't need to worry about it because the cleanup is kind of part of it and this is kind of about cohesion a little bit where these two things belong together they're both kind of that the best friends really so it makes sense that they're next to each other cool another way to use kind of returning functions is in timing and we use this this exact pattern so we have a start timer function and it creates it captures the current time it then returns a function to the calling code and when that returned function is called it takes the duration and prints out how long that function took to run so you can see that you just you just call start timer you keep the stop function defer the stop function immediately and that's then going to time how long that function took so there's another little pattern of being able to to use return functions it's worth thinking about because you know you the calling code doesn't have to know about the time or doesn't have to worry about the state it's all kind of captured in that closure so you know we don't have to trouble ourselves with it and it makes things easier for your users and by users I mean users of your code which sometimes is you so this goes a little bit to what the other talk was talking about which I should stop referring to of course because it's going to be at some point this is going to be on on YouTube whichever I shouldn't have said that either so we have a sizer we have a sizer interface here and this is the idea is we want to get the size of something and so fine we have a single method interface which is nice and I have a couple of functions of where we could use that so there's a Fitz one where we pass in a capacity and the object and say does this fit in this capacity and we have also is email Abul so this is you know can I email this item and it's going to make that decision based on its size and then there's a sample implementation there on this file type that has a size which gets it from the info so you can see that it's quite easy to implement this interface so then you can do something quite clever which is you can create a new type which is a slice of that interface and make that type implement the same interface so now you can treat many items as one and you can use them in the same places you use the size so he goes into the fits method no problem so we could have ten files and pass that in and the fits method doesn't have to know that's what you're doing the implementation here just iterates over the the objects call size and totals it up you know so we just get the sum of all the size there so that's quite cool other ways to implement the interface include of course the size func so we could have now a function that ad hoc calculates the size of something and we can pass that in to anything that's using this size interface and similarly you can just do it the type itself so here I have the type size as an INT 64 that then implements the size interface which just returns itself so now I can just I can just wherever I need to pass a size I don't need to create an object I can just pass in I can just cast it and say size this size and the reason it's easy to do all these different things of this interface is because it's so small a single method so see if you can find single method interfaces when you when you're thinking about building your bits and pieces okay optional features this one turns out to be really quite powerful you hear is they have this decode function at the bottom and the idea is I'm going to pass in a reader probably you know a something from the HTTP request and it's going to decode the jason for me but optionally it's also going to call valid call this this valid method actually the methods called okay it's going to call that on the object if it has it and the way we do that here is we just have we we do a type assertion so we say if if this object implements the valid interface which is another single method interface by the way then then call it and if that okay method returns an error then we know that the object isn't okay so this is a great way to do validation on objects and also keep the keep the validation of an object with the object rather than repeating it or or you know having it some other place or some of the system so that's a nice one and you can do that for many different things so whenever you think you know we have this we have this kind of thing and sometimes it has it doesn't it's not quite always like this sometimes it also has these extra bits and pieces so then consider maybe there's maybe there's two interfaces or maybe it's you know worth abstracting a little bit I've no idea how much time I have but I'm going to just plough on thumbs up cool simple mocks okay so here we have a interface called mail sender and it has two methods and Freud and it has send and send from and so this is this is a nice little trick of creating something that you can use in testing so you just make a struct that has fields for each method so because you know functions just a type really you can you have a send func and they send from func so these two fields can then be set at you know when you write your test and then all we do is implement the interface that just calls those functions so you don't have to you don't have to build complicated mark objects what we can do in test code is just create the this mock version and pass it into our code that we're testing and we can control in the test what that function is going to do so that could involve capturing the capturing what was called and making assertions about it it's often quite useful and you can also control what's returned you know and in this case and ascend from I'm returning an error another nice thing is you don't have to implement every field you can only you can just focus on the one that you want to test if other fields are called you're going to get some kind of nil panic probably but you know that means then that something's happening that you haven't expected in your test code so you have to then address it anyway so it's sort of kind of sorts itself out mocking other people's structs okay so sometimes there's some package has this struct and you wish it was an interface does that ever happen to anyone def I heard someone over there say yes Matt definitely yes well it has happened to me and what happens is you immediately feel like this is I wish they'd done an interface and you thinking maybe I'll do a pull request to that and abstract this and things or you might think I just want to take a sword and slowly pass it through myself because that's how it feels it's like that's this is terrible but don't despair because you can make your own interface you already know what the methods are that you're going to be working with so you can just make your own and since there's no explicit implementing interfaces in go it's a sort of duck typing it's called structural typing and you don't they don't even have to know that you've done this so in this in their package they're messenger we create our own messenger interface here that implements the same method and we can then use that now they're struct already implements this so our code is going to work as before but now we can create our own mock one or do whatever we want since it's now an interface so that's another cool one that's worth remembering retrying this is nice essentially you know sometimes you want to call a function a couple of times you don't want to have to Bill you don't want third-party frameworks and things to do to solve this for you so you you can do something like this this is the Tri code it's a try function and essentially it's just going to call it and then it expects a bull and the or an error and if the ball is true it'll continue if it's false it stops and you know and if there's an error it returns that this that's it in its entirety you can get the full code at github comm slash Matt Ryan slash try but don't import that package copy the function because it's tiny and there's no need to build in a dependency to that but how you can use it is you just you just you call try you pass in a function the function gives you the attempt number which starts at zero or one I can't remember and then you can just return where attempt is less than five so that's going to be true up until is five at which point it stops and that you know it's going to stop retrying so it's quite nice it's quite easy to read I think it's obvious if I showed you this and said what's this what does this do I think you'd be obvious you'd know and that's kind of a kind of key and then so if you want to do a delay between the retries which you might want to do one option you have is to add a function to the try package or whatever that is you could add a function say try delay and you pass in a delay duration so yeah you could do that but if there's a way to not change anything and still solve that problem in userspace then that's got to be preferable because it keeps your it keeps that try interface dead simple so that's as a principle I think worth always seeking and in this case it's quite easy we just check if the error is not nil just sleep so it does it in the body that also means it's in the place where it's actually happening and that's where you that's where you see it so I think that's a nice another nice little pattern another one empty struct implementations sometimes you have an interface like codec and you want to implement that codec we can do it like this with an empty struct that essentially is just a collection of these the methods that implement that interface since there's no state in here there's no need for it to be anything more complicated and you can see that the receiver the json codec here the receiver actually doesn't we don't capture it it just says the type and that's also makes it clear that we're not going to use that we're not going to store any state so it's another nice thing to do and then at the bottom we have there we just have this this VAR here called JSON which is of type codec by the way and it's just an implementation of that empty stripped so what's nice about this is if this was a package or we've all we have to expose is the codec interface and there Jason variable so it's it's dead clear that what's going on we don't have to have Jason codec exposed as well that's why it starts with the lowercase J keeping it private and the other nice thing is you know wherever you need to if you if you want to just use the JSON stuff directly you can offense was in a package it might be you know encoding dot jason the variable dot encode and you can actually access directly those methods semaphores we want to have we've got this process going we want to limit the number of go routines that are running at once okay well this is a really nice simple way of doing that essentially the idea is you create a buffered channel and the size of the channel is how many concurrent go routines you want and what you do before you do the work you send in something into that channel and the you know while this room in that channel that's going to go through no problem as soon as that channels full it caught it'll block it can't put any more in and then you spin up another girl routine here where you defer the function of reading from that that semaphore channel and that then clears one of the slots which then would unblock one of the others and I can I can show you this running you can actually see that it set the limit to five and you can see that these things are running in blocks of five there are only five go routines running at a time so it's a nice way to kind of control things and and you know make sure things don't go crazy debug logs were built with a build tag I like this I'm sure someone will tell me on one of the websites or not this is perhaps not a good idea always always love love that I actually do because the learning is awesome so the idea is we we set a variable called verbose to false and then we use that variable whenever we're going to debug something and of course it's just false all the time so it's silent but then in a different file you put a build tag of debug in and just in the init just set that verbose value to true and that then turns on the verbose logging so you can do that in a build tag so then you could run tests with this flag and use the build the tags and it will turn on you can also do it in production if you want for building and stuff you know I think on bigger systems you're going to have slightly more sophisticated logging and stuff like that but for small programs this is it's really great so definitely be obvious not clever one example from before the the start timer example this is another way to write it where you defer start time a call the function you know that returns the stop function if you remember which you then call but it's deferred so what'll happen is the start timer thing will be called now and then the stop what is confusing so even though this is this takes two lines to say it's way clearer and I think you know that that's worth going for it's not it's not all about trying to be really clever and and smart it's smarter to be simple so how to become a native speaker and go if you want to well read the standard library there are lots of great examples of things to learn in there and there's lots of lots of cool stuff and it's all open source you can just go and read it right obvious code not clever code don't surprise you you know don't surprise your users don't do something don't do extra checks just to be clever just to be really you know to make sure it's bulletproof just make it really obvious and and and simple seek simplicity and and definitely participate in open-source projects because I've learned most a lot of these I have we've kind of worked with the team and come up with together but a lot of them also I've found in open source projects when I've seen and working with people ask for reviews and accept criticisms and if you spot something in someone else's code by all means you know point it out and be kind when you do that because people are very personal about their code so be gentle but share ideas and and if you've got any questions about any of this stuff please tweet me at Matt Riya I'm nearing a thousand followers and that'd be awesome if we could get a thousand followers my dad my dad said you'll never get a thousand followers on Twitter and I said dad get out get out thank you very much
Info
Channel: GopherCon UK
Views: 51,192
Rating: undefined out of 5
Keywords: golang, go
Id: yeetIgNeIkc
Channel Id: undefined
Length: 27min 57sec (1677 seconds)
Published: Fri Sep 09 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.