Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save coolaj86/968cb98bbdb3f3a7d10a2c6bcbf4d8ab to your computer and use it in GitHub Desktop.
Save coolaj86/968cb98bbdb3f3a7d10a2c6bcbf4d8ab to your computer and use it in GitHub Desktop.
Transcript of Creeds of Craftsmanship Part 1 - The Zen of Python - https://www.youtube.com/watch?v=zpKZ1bqmlHI

Transcripition of https://www.youtube.com/watch?v=zpKZ1bqmlHI

So there's no Python, I would call this in a programming, because these are succinct stances that apply to all programming languages really. And there's nothing here that is specific about Python. And because it's a very high level, I don't think that there's anything here that that can't be understood by all programmers. Because the go the go proverbs three, as you'll see there, the language is more towards a systems programmer. But whether you're a web developer or a systems programmer, I think you can get this. So beautiful is better than ugly. I think that this is its objective, but it's also something, the old quote, I know it when I see it, you can look at code, and you can say this has sort of that aesthetic style to it. And that style is generally Dave cheney gives a really good example where he draws a line through the center, well, not the center through the margin of the code. But basically, if you notice that most of your code aligns with a single bar, and there's a couple of Jedi arrows, that's probably beautiful code. If you notice that your code is jutting like this, as you go down the page, it's it's it's deep into from the left side to the right side, it's going deep to the right side, and it's zigzagging. That's ugly code, it's not going to look very pretty. When you just look at it as a shape, it's jarring. But also it indicates that you have a high cyclomatic complexity because you have lots of nested statements, you might be nested ifs might be nested tries might be nested switches. If the code never reaches the whitespace point back towards the margin inside of a single screen, then you have a candidate for code that probably needs to be pulled out into multiple functions. Because you should be able to see this dome shape of the code over and over again, as you scroll the file, you shouldn't be seeing the jagged jetty thing. So I think I think that that's what beautiful is better than ugly means is just that the code should have a certain flow to it that the aesthetic is recognizable to most people's eyes. Explicit is better than implicit. This goes to what I was talking about the ES modules where and go follows this perfectly. If there's a package name, and the package name is appropriately named. And then I have a dot and I have a function or a constructor or whatever off of that package name, then it is clear to the reader where the package came from, what the package intention is, and what context applies specifically to the function that comes from that package. And so, and in general, it really stinks when you have to go hunt through documentation or source code to figure out how something works. It's nice when things are explicit, because then in the examples that will show and I, I get some of the argument for certainly reasonable defaults. But I also really appreciate it when an example. All of the options that can be specified are there in the example. And they're just set to their default values in the example. So if I copy and paste the code, it would be the same as passing an empty config object. But at least everything is explicit. And I know exactly what options are available to me and I know what the defaults are intended to be. And there's lots of other cases like that were less global scope, more package scope, less, there are cases where we need one letter variable names, because of its common convention, it makes things easier to read, for example, I as a counter, this makes sense. But in general, we shouldn't be trying to stomp out all the vowels. We want things to be explicit, to be readable, and we'll get to that mark. Simple is better than complex. So obviously, if you can look at it, and you can understand it at a glance, you don't have to sit there and think and be like, Okay, let me break this down, you know that you're violating these first three rules, which I dub p one through fy 19, is what I dubbed these when I am doing, I'm starting to do code reviews where I use g one through JUnit, g 19, and P one through p 19. To say, this is why I think this is good, or this is why I think this needs improvement because then it's not just, you know, me being an old fart with, it's like lots of old farts have said this, I feel a little bit better. But if you have to restructure code in order to understand what it does, it's probably not beautiful. It may not be explicit, you might have really short variable names that aren't clear. TMP is sometimes better than t. o. That's letting us know that we don't have much time left before the building shuts down for the night and the lights will go off and we won't be able to turn them back on. But yeah, and it's not simple. Now complex is better than complicated as one that is a little bit difficult to understand, but I would I would phrase it like this. We need complexity sometimes because an algorithm may be complex. But we don't need complicated and I think everybody maybe not you too because you're you Yes, young, maybe not quite into your program and cruise. But everybody's had a situation where you go to refactor some code, you try to follow the don't repeat yourself principle. And you end up with a function that's a little bit wonky, it has maybe too many options in it, or the options that it has don't quite make sense. And you kind of get lost. So you got all the abstraction quote, correct. But then the abstraction makes the code complicated in terms of understanding it. That is a good indication, as we'll talk about later, that you probably need two functions that are maybe three functions. And the functions might have five lines of the same code. But it's complicated if you try to make the abstraction work for all three things when they're similar things, but they're just different. The way that you calculate the area of a circle is not the way that you calculate the area of a triangle, or a polygon. And so if you have functions for calculating the area of something, you could try to smash everything into calculate the area function. But that would become complicated. Even though many of the principles would be the same, it would make more sense to have different functions for shapes that have different rules as a, you know, off the top of my head example, flat is better than nested This one is really simple. The more that you have to go into an object, we've in the Java world, you've experienced this, where you have a something dot config dot, get instance of inner private object dot config dot get instance of other enterprises object dot Git config. This is this is complex, if you have nested state, it particularly you'll notice this when you go to test your program, if you have to set up a 11 million things in order to test the functionality of an object or a class or a package, you have probably nested things too much, you have too much state too deep. And there is an elegance to it as you start to do it. But you will probably find that if you d nested and put things at the same level, and just have them use each other rather than be nested inside of each other. And I wish I could bring up code example of that author, or give an illustrative example off the top my head. But is there any ambiguity about what I'm talking about there? Do you have a case in mind of your head of Yeah, I know where where I run into this before? I'm getting head nods. Okay. So sparse is better than dense. There's there's unlimited whitespace. Dave cheney said, just like it code should read like a paper, you have paragraphs in between each paragraph, you put a break. So between your functions, you have breaks, obviously, but within your functions, you have a grouping of code that does the calculation of the area, then that's one thing, you do the that you've got a couple of lines of code that have the calculation of the change in position. That's one thing. So you have paragraphs within your code that are a couple of lines long, maybe three, four, maybe just two, probably more than one. But yeah, it we don't want to optimize for what's really hip in JavaScript right now is doing all these arrow functions where you do 10 things in a row. This is bad. This is objective. Well, according to just about every software engineer in existence, it is subjectively bad to put it is because it's not readable. It just if you ask somebody might say oh no, I prefer it this way. It's easier. No, if you actually ask them to read it, you will see that they take more time to read, it is easier to read from top to bottom than it is to read from left to right and certainly not from right to top. And right to top is the case when you use async await incorrectly in JavaScript, you have all these try catches, and then they're nested. And then you have to be reading right to top to figure out what's going on so that you can go back down. So and that leads us to number seven, which is readability counts, it's all about readability. And almost every software engineer that I hear speak at conferences has a strong focus on readability. You don't want to optimize for keystrokes. You don't want to optimize for fitting things in a single line by the way, I didn't finish that but map filter reduce the map you know the people do that in JavaScript, you see that work and I use a little arrow function so it's just an arrow and then and then a value and then a dot and then another don't do that. readability counts. special cases aren't special enough to break the rules. So again, will somebody go hit that thing by the TV over here? So if you hit that that should give us a little bit more time. Okay. Or wait, oh, it came back on. Especially he's there in special enough to break the rules. This is Crawford says this really well although he's really abrasive as as am I. But if something is useful, something being useful is not a good enough reason. To use it if there's two ways of doing something, and one of them is useful, but the other one is guaranteed to work, use the one that is guaranteed to work every time. Because you can always find a use for thing. He said it extremely well in his JavaScript, the better part stocks, we're humans. Our our separation from the animal kingdom is how wonderful we are at finding uses for things, even useless things. And he gave some sort of example of, of basically, Rube Goldberg machine type example we will find uses to take something that was not intended for a purpose, and we find a purpose for it. So anything can be useful, and this is dangerous. Although practicality beats purity, so not Dave cheney. I don't remember his name. Well, it's not that I don't remember his name I Well, I don't read his name off top my head. I think I do anyway, he gave a talk also that was on go. It's called the things in go I never used that is also in the link of the Creed's of craftsmanship that are down in the doobly doo. As well as in all of the chats for this thing. At least it should be my go make sure that it made it into the other chats for this thing. Oh, whoops, this is going way too What? Let me Oh, yeah, it's in all the chats for this thing, because I posted it in Discord. And then that posted everywhere else by virtue of restraint. So what was I saying, although practicality, beats purity, oh, so he says there. One thing he never uses is else, which by the way, I would challenge you this if you use else. And you don't think that there's anything wrong with outs, then you need to go a week without using Alex because you are writing really nasty code. You are you eltz is something that should only be used in exceptional cases. And that would be a case where practical practicality beats purity else is a tool to be used with extreme prejudice. There are cases where it doesn't make sense for a single line that needs to be there to not break the flow of the code to then go put in an extra function or to break everything else that would come after the else into its own function and then call two functions. There are cases where with extreme prejudice, it is acceptable to use an outs but generally speaking, if you're using an alto, you're not thinking like a programmer, because here's what your your your if statement looks like, it looks like if normal case, that's going to happen 99% of the time, these 20 lines of code else, do nothing. And now you've indented all of your code and started one of those jackal tools that you didn't need to start. So but you do need it occasionally, errors should never pass silently. This is one of the reasons for you strict in JavaScript, this is just good practice. This is very strong in the NGO community. As I said, Go is the spiritual successor to Python, it follows all of these rules, all of the go. The core Go team, the people that speak at the conferences that are the big go heads, they all say these things either in their own words, or even quote them occasionally. But errors should never pass silently. If there's an error, we want to know about it. If nothing else, we need to log it out as a warning, but there probably should be some sort of Event Stream say that you have something where you can do a callback and and collect those errors. Somehow you don't want errors, there are certain errors, your database returns 404, you want to check the error. Okay, this is the next part unless explicitly science silenced. So a lot of database libraries. If nothing is found, they throw an exception. If there's a SQL error, they throw an exception. So what you want to do is you want to catch that error you want to check to see is error type not found. If the error types not found returned on your find it because your program knows to handle you are looking for a query of Is there anything in the set zero is an acceptable number of items to have in a set. If you know that's the case, return the empty array or return the null value and then go create the user or go create the bookmark, right, but you check that error and you make sure that it's the not found error and that it's not the connected database error or the invalid database or invalid SQL syntax error because you go change your SQL here doc string and you forget a comma and your error swallow you hate yourself when you finally find it four hours later. In the face of ambiguity refuse the temptation to guess p 12 is probably the most important line, maybe in coding history in the blog towards go to which is also linked in the creative, creative craftsmanship link. They talk about a case where they knew that there was a problem with the way that time work because there's monotonic time meaning how many seconds passed, and then there's wallclock time which has to deal with things such as daylight savings time. So in daylight savings time hits, monotonic time continues to increment. If it's been an hour and a half. You don't say Oh, actually it's only been 30 minutes. You need to continue to count monotonic time. It has been an hour and a half now it's been two and a half hours, walk off time wall clock goes backwards or forwards. it skips time or it goes back previously right They had an error with this, or they had a potential problem, no one had had the problem. I don't remember exactly what the problem was, but it had to do with a leap second, and they decided that they weren't going to handle the leap second, because it only happens once every year or two years or something like that. So they decided they weren't going to handle it, because they knew there was a possibility of error, but they didn't experience it. And Google, the Google servers do a special clock skew, so that on a leap leap, second day, the NTP server actually just adjusts the seconds off by a few milliseconds every second so that leap day, seconds are just off by an order of a fraction of a millisecond every second, that's how they handle the problem in Google. So they didn't deal with the problem. And then there was this big kerfuffle with CloudFlare. And then when the problem happened to CloudFlare, the way that it happened and the way that CloudFlare had to solve it, and the communication that happened between the teams, led them to an elegant solution. So that time could keep wallclock time monotonic time and deal with leap seconds, all in the appropriate expected way, without adding too much extra craft or having bad behavior. And but they waited, they waited years to solve that potential bug, they waited until the bug actually happened. And until they had enough information to solve it, and they do that a lot, you'll hear people talking about go architecture, they'll wait six months to release something until it because once it goes in the standard library, it's gospel, they don't change that they probably will never break go syntax other than adding new things that are available in new version. So and you'll find this when you're having those discussions. Oh, well, in six months, we're going to add this feature, we know that this is coming down the pipeline from Salesforce. But if you don't know if it hasn't come down the pipeline from sales, if you don't, if the other person responsible for the other microservice hasn't finished their API, don't guess just don't include the feature. You'll never regret it. I i've regretted times when I've tried to plan ahead for something I didn't know I've not regretted delaying. Because when something's running late, everybody's running late. I work as a contractor people call me up they say, Hey, we need this done yesterday, we we promised this last month we needed done yesterday, can you do it yesterday without my time machine and I go fix it yesterday, and I present it to them. And I don't hear from them again for two months. Right? So deadlines and stuff are arbitrary. People don't need the things they think they need. You can wait and and see how things go. So there should be one and preferably only one obvious way to do it. Again, this is my beef with import, there's there's too many ways to do there are distinct, separate distinct there, there's about a dozen, maybe more, you can look at MDN distinct ways to do imports and exports, you anybody that has actually memorized every way to do an import and export, I would I would love to know if that person exists. Right? This is senseless. We don't our art is not in the letters that we type our art is in the functionality that we produce the capabilities we bring to the world. So there should be an obvious way to do the thing. We shouldn't have 10 ways to do things. We want to optimize for less mental load. Although that way may not be obvious at first, unless you're Dutch. Well, this, of course means that there are there are team constraints. When we work on a team, we develop team values. When we work in a language we develop language values. So although we say we want it to be obvious, obviously a person who has never picked up coding, it's not going to be obvious to them. So there are some constraints on what we mean by its must be eyes. And this is the one reference that is specifically Python reference because the Python core team, a lot of them are Dutch. Because Guido, I think is Dutch now is better than never, if we need to make a decision, we can we can add an API version to we but we need the functionality now. And we know what the functionality is. So we're not stuck in that previous one of in the face of ambiguity repeats the temptation to guess we know that we need it, we know what's needed, we have the requirement. So let's go ahead and implement it. Don't Don't, don't hold off for the perfect solution, follow the greater distribution. Once you get to that 80% move forward. If you don't know the other 20% don't include it. You can add it later, especially with things like JSON and JavaScript, where they are dynamic in their nature, you can add new properties later. Although never is often better than right now. And this anybody who has had to ship something on a given day, and the whole team is staying overnight to ship that thing. People are there until 12. Is anybody in that situation where you're? Yeah. Okay. How many times has it ever worked out that it was better to ship it that night than it was to wait two days. I had one case and that was because there was a legal deadline and it was better to ship a broken product than to not ship the product. But aside from that one case again, never all deadlines are arbitrary. And you If something feels so urgent, and especially this, this applies the rest of life, especially to dating, if something feels so urgent, so pressing that it can't wait, then something else is wrong, you know, the company upstairs May, they would address it a number of different ways, because they would still go forward, the product managers kind of lead the company and, and so they would still go forward with the everybody up all night. Let's get this done for tomorrow because the customer needs that thing. And then we deal with the for the next several months, all the the issues that come from that. But I thought it was interesting that one of the ways he would address it was they had an actual rule that if you were there all night, you had to go home and sleep the next day, only because they understand that there's only so much you can do with clarity of focus in mind when you're that night. They don't understand how Mountain Dew works. No, I agree. Free food. So you can have as much as you want. And Mountain Dew was on the list. So yeah. Yeah. So if the implementation is hard to explain, it's a bad idea. And this is inevitably true, because even if the implementation is correct, go back to that conversation we had earlier about marketing things, if it's difficult to explain, it's not going to catch on, it's not going to develop a culture around it, it's, you're not going to be able to have shared understanding, and somebody else is going to implement it maybe in a much worse way. So if you have the perfect implementation, but it's hard to explain it's a bad idea, you would be better off following the Pareto distribution, find a solution that meets the 80% and get buy in, then to deal with having a perfect solution that no one will believe you about. The other problem with perfect solutions is often you may be the only person that has enough experience to understand the value of the solution. And when you're a roomful of 10. People, it doesn't matter how senior you are, when nine people who are junior to you don't understand the implementation, you lose that vote. So if the implementation is hard to explain, it's better. If the implement implementation is easy to explain, this is a seductive one, it may be a good idea. And this goes to the marketing again, there are lots of sweet things out there that sound flowery and good, that are absolutely horridly bad ideas, Objection, objective, really bad ideas. But they're easy to explain. So if it's easy to explain, it may be a good idea that we should not let ourselves be fooled, because it falls into the comfort of our our minds interpretation that therefore it's good. And finally, and this is already kind of come before namespaces are one Hawking great idea. Let's do more of those. I do have another word on this. But namespaces meaning packages. So this comes from an era when C was much more dominant. C has no scope at all? Well, I think it has it has function scope, that's the only scope it has every packages in the global scope. So that's where this comes from. But it's it's very relevant still. Group things together under a name that makes sense. Now, this is my caution for the JavaScript community. We have things like lodash lodash, says nothing. And that is a good indicator that it's something that you shouldn't use. Utility libraries are the devil's playground. They're like the ternary operator. They're just, they, they're seductive, but don't use them. Very, very rarely will a utility library that has a generic name that does not communicate what is now I understand. Sometimes we have weird names for branding purposes. And there's an authentication library called polar I think, doesn't say anything. But polar refers to this methodology of doing the authentication actually is I think the libraries Oh, so I don't know what that means. And the, their configuration is called polar anyway. So there are cases where you know, for branding purposes, the names are meaningless. But when you come across something that cannot be described. And this is not you know, that's I'm going above and beyond what this is reading in the text here. But this is the inverse of that. Because for every measure, there must be a countermeasure that should be on here as well. We want to group things together, we want to put them up in their own place, but if you find that it's being called stuff, lib, utils things. config, something like that. There's a really strong indicator that you have not followed this principle namespaces should describe a unit of work that gets done. So if I have slash lib slash off, probably I should probably have slash slash off end and slash off z to distinguish between my login logic and my permission enroll logic authz being permission roll logic off and being login logic. Think of it like driver's license. Says who you are, well, actually, that's a bad one because it does both. It also gives you permission to a hall pass doesn't say who you are says you're allowed to be in the hall. state ID doesn't say what you're allowed to do, says who you are. That's distinction we often see, but that's different. Anyway, the point I was trying to make is that we give things names, and we put them in a namespace. And if you can't come up with a name, that is descriptive, then you probably haven't followed namespace principle. So with that, I will take constant questions, but I won't go on to the others. We'll leave that as a part two. Or arguments. You want to fight me, I'll take you. Class. If you don't stand for something, you'll fall for anything. So I think it's important as if you want to grow into the role of a software engineer to learn from other software engineers not I don't think there's anything argue about this in Python. It is just so plain. There are other Creed's that have some points that I think are a little more arguable perhaps some people would argue against explicit is better than implicit, but find defensible reasons for the reason you code the way you code and remember the heart is defined by the constraint of the medium it is not what you include, but is what you exclude the defines your discipline. And perfection is achieved not when there's nothing left to add but when there's nothing left to take away. So Hallelujah, Amen. I'll see if there's any questions in the in the chat box here. Nope. Okay, well that I'm gonna go ahead and peace out and we can chat a little bit I would appreciate your help cleaning up. And again, if you're watching on the YouTubes or whatever twitches doobly doo for the links to the cross links to the node channel and the meetup and blah blah blah. Thumbs up if you got them thumbs down if you don't, because every time helps and peace thanks

Transcribed by https://otter.ai

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment