Ashley McNamara + Brian Ketelsen. Go best practices.

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

The slides are pretty clear if you're just looking for a quick perusal: https://talks.bjk.fyi/bketelsen/gcru18-best#/

👍︎︎ 4 👤︎︎ u/frebb 📅︎︎ Apr 06 2018 🗫︎ replies

Interesting talk, was only a little bit distracted by the wig :P

👍︎︎ 2 👤︎︎ u/forfunc 📅︎︎ Apr 06 2018 🗫︎ replies

Very very nice, and funny! If you like this talk and want to hear him talk more and make jokes you should try gotime.fm.

👍︎︎ 1 👤︎︎ u/cloudrkt 📅︎︎ Apr 06 2018 🗫︎ replies

I love how he is helping all these serious kids while acting like a woman. Goes to show it doesn't matter who or what you are doing, if you have the answers.

👍︎︎ 1 👤︎︎ u/govision 📅︎︎ Apr 08 2018 🗫︎ replies
Captions
[Music] hello my name is Ashley McNamara and today I'm going to teach you how to code like you belong on the go team but first a little bit about me Ashley McNamara I work in Microsoft Azure as a cloud developer advocate I work with amazing people like Brian Kedleston on Twitter I'm at Ashley McNamara on github Ashley McNamara and my most popular repository is Ashley McNamara slash Gophers where you can find copies of all of the Gophers that I draw by hand for the NGO community so please enjoy yourself and go to Ashley McNamara on github slash Gophers and you can print your own stickers and posters they're all liberally licensed this talk is available at CD AMS slash little jay big p i want to take a moment though and talk about a person that's very important to me a person that's been an inspiration to me a person that I love very much Brian kettle s'en is an amazing person I don't think I could be Ashley McNamara without Brian kettle s'en he's handsome he's smart [Applause] amazing so thank you Brian thank you so to write code like the go team we're going to talk about several points we're gonna talk about how to organize your Go code into packages and what those packages should contain many times that's a problem for new code developers what code goes in which package how do we know we're going to talk about code patterns and conventions that are prevalent in the ghost standard library we'll talk about how to make your code more clear and understandable and we'll talk about unwritten go conventions that go beyond go format and make you look like a veteran contributor to go so our outline we're going to talk about packages naming conventions and source code conventions let's start with packages there are two key carry two key areas of code organization in go that will make a huge impact on your usability the testability and the functionality of your code those two pieces are the package naming and package organization if you've ever seen a large go pack a go project that has a hundred files in one package that's not usable conversely when new developers come from Java sometimes we have a thousand packages each with one source file that's also not good where's the middle so we can't talk about code organization and naming separately it's one problem we talk about them together because that's what makes sense how's my hair did I do it right it gets in my eyes so a package should contain code that has one purpose when you look at the standard library this is a list of some of the packages in standard library archive crypto errors index math one purpose when you look at the archive package do you think that you can find the constant for pie in there 3.14159 seven to six whatever do you think pi is an archive no I think zip tools are in archive I think you can open a tar file with archive and it's very clear by looking at the package name what that means sometimes you have a group of packages that do the same thing in standard library a perfect example of this is the encoding library we have to encode JSON XML asn.1 base64 base 32 hex and so many more so it makes sense to have a parent package called encoding and in that parent package encoding there's an interface that all of the children packages implement so we've done two things we've defined a clear interface for all things that have to encode and we've made a very clear convention that all of the children packages under encoding are part of that package so using the standard library as an example the encoding package shows us how to take common functionality and group it together in a set of packages so some of the commonalities of well-organized packages the package names always describe their purpose does a package named utility describe its purpose no is it it's very easy to see what your package does by looking at the name of the package the names of the package in standard library are always short you don't see 50 character names in standard library they're usually six or seven characters one small word that describes what the package does archive we could have called it zip and tar things but archive is smaller and more clear when necessary we use a descriptive parent package and several children implementing the interface in that functionality like the encoding package so the packages that we've seen so far are all libraries they're intended to be imported by someone else's code you build libraries so that you can share them and use them in your commands but when you're writing an executable program a command or a service how do you organize those packages let's look at that next so when you have an application the package organizing organization for that application is just a little bit different the difference is that the command the executable that you're building ties all of those dependent packages together so what we want to do is create an organization structure that makes sense for something that has a lot of dependencies so application packages have a huge impact the way you organize them has a huge impact on the testability and the functionality of your system oftentimes when people ask me questions about I'm sorry oftentimes when people ask Brian questions about how to test code if they're if they have a problem with testing their code many times Brian will tell them that it's because their packages are incorrectly organized if you're having a problem creating a test it might be because your packages don't make sense and that's usually the first sign to Brian that there's a problem with your code organization because it's harder to write tests he's such a smart guy that Brian when writing an application your goal should be the right code that's easy to understand that's probably my number one favorite feature of go I can look at go code and understand what it's doing when I wrote Brian wrote c-sharp for 10 years and today when I look at c-sharp code I don't understand it very well at all because go has spoiled me so much you can read go code and understand what's going on your packages should do the same service for your users it should be easy to understand what your application is doing by looking at the packages so most libraries focus on a single function the archive package focuses on making and reading archives that one function is important to the package but when you have an application a command a micro service it uses lots of libraries so it ties all of those smaller libraries together and that means that the scope of the packages in your system are much larger when you build an application so when you build an application you should organize the packages in that application into two categories domain types and services domain types are the types that model your business functionality so if I worked at Google for example a domain type might be a search we might have a type that that represents a search that a user entered that's a domain type if I worked at a telephone company a domain type might be a call record or if I work in an HR department hiring and firing people that'd be fun then maybe one of my domain types might be an employee domaine types are the things that model your business functionality services are the packages that operate on or with your domain types there's a fantastic article written by Ben Johnson on medium.com about laying out package definitions for applications strongly recommend you read this remember you can get the URL CD AMS /j big P and it's much easier than trying to take a screenshot of this slide I saw you over there so domain type is the substance of your application if you have an inventory application your domain types could be product or supplier HR administration system you've got employees departments business units the package that contains your domain types should also very clearly define the interfaces between those domain types and the rest of the world so I have an employee what are the things that I need to do with an employee so maybe we have a domain type called employee and an interface called employee saver and it tells us that we expect to be able to save this employee to some database those should be together and they should be in the root of your application a root folder because when you open that package on github or in your code editor you want it to be clear what this application does and you can do that by opening the employee go file seeing an employee type and then an employee interface employee saver I already know what the app does it's right here it's written right in the root of the package so domain types should be in the root package of your repository that makes it clear to anyone who opens your codebase for the first time what domain objects we have and what things we want to perform with them the domain type package or the root package should not have any external dependencies I'll say that again the domain type or route package should not have any external dependencies it's a roadmap for your application it tells you what and how that's it it only exists for the purpose of describing your types and their behaviors the implementations of your domain interfaces should be in subdirectories separate package and they should be organized by their dependency for example I said that we had an employee domain type and an employee saver so we could create a sub package or a package underneath our route called Postgres and under Postgres we have an implementation of the employee saver for the Postgres database what we've done is declared in the root level what we're going to do and then in the post grass package how we're going to do it and we already know which database we're using because the package name is post grass so with all of your external dependencies if you create a single package representing that external dependency whether it's Postgres or memcached or MongoDB if you want to throw your data wherever you have choices and putting all of those dependencies together by by interface type will make your life simple when you're creating tests so what are dependencies dependencies are external data sources maybe you're making an HTTP call out to another system to get data maybe you're making a call out to another micro service in your company they could be more complex things like transportation logic in our route in our domain types we we determine the domain type and the services that they provide but there was no explicit declaration that we were going to provide that service over HTTP maybe you want to use HTTP and rest services today but tomorrow you want to use G RPC so don't declare the type of service or the transport of that service in your interface save that for an implementation and there should be one package per dependency so why one package per dependency it makes testing so much easier when you have an interface that defines how to save an employee and then you have a package called Postgres that actually saves the employee when we want to test that all we have to do is create another version of that interface that saves it to disk instead of saving it to the database or saves it to memory instead of saving to the database often people call that a mock but more importantly you're using a form of dependency injection because you determine at runtime or compile time how you're going to satisfy the domain interfaces that you've created with one package per dependency you can very easily switch dependencies to something different if today Postgres works for you but tomorrow Postgres isn't enough you can move off to Azure cosmos DB or my sequel the most important part of one package per dependency though is the last point no circular dependencies if you have a package that depends on another package and that package depends on the first package the compiler doesn't know what to do that's a circular dependency and you can get into circular dependency trouble when you start mixing domain logic with interfaces for your services so if you use one package per dependency you almost never end up with circular dependencies and for me that's the best reason to do all of this so let's talk about some coding conventions my favorite quote there are two hard things in computer science cache and validation naming things and off-by-one errors naming things is very hard it really is but if you put some thought into how you're going to name your types and your functions and your packages those package names and type names and function names will make your code more readable more understandable remember you spend maybe 20% of your time actually coding the other 80% of it is reading the code that you've already written or code that someone else is already written go is so helpful because it's optimized to be read easily we could make go look like Scala if we wanted to but nobody's that mean instead we want go to be readable so if you choose package names and function names and type names that are easy to read and very descriptive then you've helped your future self and your coworkers so a package name should have the following characteristics it should be short that's pretty simple prefer transport over transport mechanisms small word descriptive word your package name should be clear you should name it for clarity based on its functionality the bytes package in standard library perfect example we know what we're doing in the bytes package we're manipulating bytes you should also name it to describe the implementation of an external dependency so if we have code that works with Postgres I think Postgres is a really good package name for that code because it's an implementation of a domain type we already know about the domain types what we care about in this package is how that domain type talks to Postgres so Postgres is a perfect package name packages should provide functionality for one and only one purpose avoid catch-all package names like util helpers how many people have a you till in their go code right now all right now Brian this morning said there were a lot of liars in the room I need to see more hands because I've seen a lot of utilities out there and that is a code smell a util package tells you that you might be missing an interface somewhere think about it if you've got util convert to thing doesn't that maybe mean that you should have an interface called thing converter and then you can get rid of the you tillage often these utilities and catch-all packages are the first place that you run into problems with circular dependencies if the domain type depends on the you tillage because we need to know how to convert it and then the Postgres package depends on the you tillage because we need to know how to convert it now you have a circular dependency what's the answer to that is it to make one more package or delete one package delete I want you all to go home and delete your utopic adjust tonight so variable naming if you look at the standard library and go there are some very clear patterns for variable naming go code uses camel case not snake case go code very often almost always uses a single letter to represent indexes usually that single letter is I for the first one J for the second one and K for the third one you use short and descriptive names for other variables like count and cussed it's very clear what account is it's not so clear what C is C the letter C for customer is too short customer is pretty long cust is a good medium point just remember that there are no bonus points for making your code hard to read I've seen developers use one letter variables for everything in a thousand line package can you read that code I don't want to read that code use a variable name that's long enough to understand and not so long that you don't want to type it it's a good needle middle-ground and if you use the scope of the variable as your guide then you can determine how long it needs to be in your code if you declare a variable on line one and you use it on line three you can use a really short variable name because those two lines of code are this far apart but if you declare it on line one and use it on line 200 you better use a long variable name because I don't want to have to scroll all the way back up to the top of the package to determine what that variable is so the farther away your code use is from the Declaration the longer the name should be this is something that surprised me looking at the standard library and go many times when there's a collection or a slice of something they use two letters to represent that collection or slice so if we have a collection of things a slice of things they'll use TT as the variable name for that slice and then when iterating over that collection in a loop they'll use a single letter T so TT is many T is one inside the loop it makes it more clear what you're dealing with when you see two variable names that are the same together TT this has to be a slice or a map or something we know it's a lot of them though and a single one inside the loop we know we're looking at one instance a void package level function names that repeat the name of the package an example good example is log dot info the packages log we already know our intention because the packages log we know we're logging so if we have log dot log info we're just repeating ourselves get rid of the extra log dot info package name already declares the purpose of the method so there's no need to repeat that who came from java.net c-sharp Java there is no getters or no there are no getters and setters and go no if you write my package dot get customer my package dot set customer I might laugh at you and more importantly your code won't look like it was written by a veteran go developer so get rid of anything that says get or set this one's tricky so if you have an interface and it only declares one function add er to the end of the interface name to make the name of your interface add er to the end of the function name so in this case we've got one method called string so the interface name is stringer and that's an English idiom that that makes it look like this interface does something stringer this is a thing that makes strings I don't know if that translates well to Russian somebody can tell me later now here's where I disagree with that if you have a larger interface that declares more than one method it doesn't make good sense in English to add er to everything and the go team may disagree with me on this but I'm standing strong because I'm Ashley McNamara and dammit I know what I'm doing so the customer storage interface we could have called it customer saver customer database er but that doesn't make sense it's a customer storage interface it's okay not to use that er everywhere let your own logic and more importantly the readability of the code guide your choice I just made this point there are purists out there go team that think all interfaces should end in ER it's okay to break this rule so inside your package separate your code into logical concerns this is pretty obvious for most code developers now if you have a type called an order then you put the orders type and the orders interfaces in orders go so everything related to this domain type in one file it gets frustrating if you have a type called orders in orders go but the interfaces for orders are in orders interfaces and then later somewhere else you've got a orders interfaces imple dot go no.11 file in the package that defines your domain objects define the types and interfaces for each object in the same source file so orders dot go contains both the type and the interface here's a smaller tip that makes a huge difference and it's something that I didn't really realize until much later after I started go in your comments make your comments full sentences that end in a period it's a silly tiny thing that makes a huge difference in the readability of your code when you have full sentences that form full paragraphs your code comments look like document a which is funny because that's what your code comments are and go there documentation so take care and use concern when you write comments and go make full sentences make it readable make the next person who reads this understand what's going on go imports I think I know who wrote go imports it was that Brad Brad wrote go imports use go imports please it's a great tool and the most important thing that go imports does it orders your dependencies in the same order every time it puts standard library at the top in alphabetical order and then all of your other external dependencies below it in alphabetical order there is nothing more frustrating than having your editor report that you have a variation in a file when you're trying to make a commit and the only difference is the order of your imports if you use go imports you'll never have that this one's big avoid the else clause you can almost always not always but almost always skip having an else clause if you write your if statement correctly and this makes code so much more readable so we have if error is not equal to nil handle the error and return the else is implied there is no else because we're returning in the bad case and we're just continuing in the good case so most if statements can be written so that you don't need an else and that makes your code much more readable so if you follow these conventions it will make your source code easier to read easier to maintain and easier for someone else to understand and I think those three things are the things that we strive for most as developers who worry about the future if you don't care about the future if you don't like your coworker ignore the speech or if you hate yourself I don't know if you have any questions feel free to ask Ashley McNamara thank you very much so well Ashley are we going to have some questions session right now sure I'll answer anything okay as we have one gopher for the best questions okay Brian my question will be party tools but they are so damn useful for example there is common occurrence in our cutter base is generate you ad package you ad string and it's merely a wrapper function which just prevents the panic from occurring and this seems extremely it's painful to a create another package called you ad to place you deep car and to place generate string inside that file so and there's a lot of this examples and the code bases so let me answer your question with a question you hire a brand new developer right out of college and they need to fix the UUID function where are they gonna look first are they going to look in a package called utilities and other crap or are they going to look in the package called UUID it's all about readability so we are spending what's worse adversity and expect an expense for we are getting ready bility an expense for verbosity so we are creating perhaps you're creating more packages but my argument is that that gives you better readability even if it means creating one bucket for one function yes thank you you bet actually thanks was great my question about large interfaces you said about interface that has three methods save delete and so on so I have a controller that have any actions any way they think is it was it good have large interface that may I think I understand what you're asking that the NGO convention is to have very small interfaces this is great yes I I say that if you're writing the standard library and go then you should have one or two methods in your interface but we generally don't write the standard library and go we're writing business applications to solve problems and I have written interfaces that have sixty or a hundred methods because it's one type and one dependency problem with this and I should implement a mock for this large interface so it's never easy to test something with lots of functions but if that if that dependency that you're using say it's a database if all of those methods are in one interface it's because it's one dependency so use something like go imple geo impl that generates your mocks for you because that makes makes your life a little bit easier thank you sure Oh actually my ask so first question how do you handle your you to package if it has a lot of functions like maybe so if you have a package called util that has 50 functions in it yes I would say that you writing code that's hard to test and you should look at those functions and determine whether they can be moved into interfaces for the domain types so what what is the relationship between those 50 functions what do they share they probably don't share anything do they yeah you just what they share is that you didn't know where to put them and that's not a good reason to name it util to try to find the commonalities and take some of them and put them together into their own packages by business function by functionality and the second question by the way you do have a boyfriend iLook do have a boyfriend do right now I I cannot answer that question publicly I might have more than one boyfriend and I don't want them to know thank you very much and that's the best question so thanks karateka biliary bacterial telephone I thought he was asking questions what last question okay one last query that's not fair he can't know whether he do two questions okay two questions okay okay small questions about getters common problem you have struct with thin field and now you have another implementation with pink field and you're going to expose ability to get things through interface how I should name method you should just name it thing I have already make link field so I can't so if you have a method already called thing and it doesn't return a thing I can feel that or you have a you have a thing field and your struct but you want to return a thing as well why does it have to guess why can't why can't you just return the field unless you're using G RPC that's correct they can't be named the same way but my question is if you want to return thing because it's the thing you're asking for then return the field just get the field and if you need a different method so that you can change thing before you return it then name your method changed thing for example uppercase thing lowercase thing or rounded down thing because if if you have to have a method for a field then you're making a change to that field I need to have a method for a field because I want you to instruct as interface I can't get field so you want to use your struck to implement an interface yes I don't I don't have an answer for you I think ask them to change their interface okay and the last question here thank you for your speech my name is Max and my question may sound provocative but I hope for the fire answer the question is what do you think about international identifiers in go what do I think I think that international identifiers like using UTF characters to name the things in the european go code like types and variables because like I think I've never seen Russian you go but I definitely seen Chinese and Japanese yes so I think that if if most of your developers use those those languages then that's perfectly fine but the problem is that gos exported naming requires a Latin character for the first letter so I've seen Chinese code bases for example where they'll make capital X and then a Chinese variable name or lowercase X and a variable name if that works for you and that's readable then that's fine it's not Latin what is it utf-8 unicode uppercase thank you good yep thank you SD [Applause]
Info
Channel: GopherCon Russia
Views: 34,540
Rating: undefined out of 5
Keywords: Go, Golang, GopherCon
Id: MzTcsI6tn-0
Channel Id: undefined
Length: 39min 53sec (2393 seconds)
Published: Thu Apr 05 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.