
Pybites Podcast
The Pybites Podcast is a podcast about Python Development, Career and Mindset skills.
Hosted by the Co-Founders, Bob Belderbos and Julian Sequeira, this podcast is for anyone interested in Python and looking for tips, tricks and concepts related to Career + Mindset.
For more information on Pybites, visit us at https://pybit.es and connect with us on LinkedIn:
Julian: https://www.linkedin.com/in/juliansequeira/
Bob: https://www.linkedin.com/in/bbelderbos/
Pybites Podcast
#041 - Letting the tire hit the road ... how much software planning do you really need?
This week we talk with Thomas Gaigher about software planning ...
We discuss many things ranging from the Zen of Python, being pragmatic as a software developer, his pypyr open source project (a lightweight task runner implemented in pure Python), how to start a software project without getting stuck in analysis paralysis (both in a company or on your own), premature optimization, adaptability and much more ...
There are a lot of nuggets in this episode so make a coffee (or grab your favorite beverage), sit back and give it a listen.
To the person who asked about software planning on our Slack:
Thanks! We hope this helps you moving your project(s) forward.
Links mentioned:
- The Law of Leaky Abstractions
- Falsehoods Programmers Believe About Names
- Agile Manifesto
Thomas' pypyr open-source taskrunner (not Piper lol!)
You can contact Thomas on our Slack (yaythomas).
Hope you enjoy this episode, and feel free to reach out to us on Slack or email us with any feedback or ideas for upcoming episodes.
Writing code and letting the tire hit the road is one of the best ways of discovering whether you're thinking about something in the right way. As soon as you write your unit test, you might discover that there's a problem with your API or there's a problem with your function signature just because you suddenly realize it's hard to test. Hello, and welcome to the Pibytes podcast, where we talk about Python career and mindset. We're your hosts. I'm Julian Sequeira. And I am Bob Baldebos. If you're looking to improve your python, your career, and learn the mindset for success, this is the podcast for you. Let's get started. Welcome back, everybody, to a new episode of the Pyewites podcast. And today it's me, not Julian. I gave him a rest week. But we have a very special guest. With me today is Thomas Geiger. I hope I pronounced that well. You pronounced it perfectly. Thank you, Bob. Nice to have you here. And yeah, maybe you can introduce yourself to our audience, what you do in day to day, and how did you get into coding and Python? Okay, my name is Thomas. I've been for my sins in it for about 20 years. I code in various languages, from Python to Golang C hash VB back in the day in terms of job title, if that even means anything in it, that's generally enterprise architecture, technical architecture, tech lead nowadays, product design or product direction, something like that. A large chunk of my experience has generally been around workflow systems and enterprise application integration automation. Again, maybe without starting any fhirs. But enterprise work can be frustrating, shall we say, especially as your role gets more senior, you disconnect more from the day to day coding aspects, and specifically on Python. To your question, Python actually reinvigorated my love for programming, probably about four, maybe five years ago, maybe six, I can't remember. But funnily enough, it's because Python is so widely used as an automation language. It became another tool on my tool belt as you're coding on other projects effectively. And when I saw the Zen of Python for the first time, it suddenly gelled, or gelled with me in a way that programming hadn't, in a sense, because design of python is suddenly talking about a lot of ideas that I hold dear about the art of simplicity and not overly complicating things. And I find so frequently in coding, and especially enterprise coding, we tend to argue a lot about patterns and practices and what's best practices and what's the purest or the best way of doing a thing and you end up in big arguments over what at the end of the day are details. And I find that quite frustrating and not very productive. And to see something like design of Python that just as a. The feel of the whole language, if you will, I'm not even talking about the technical underpinnings of it, but for sure, once I discovered the simplicity of Python syntax and how powerfully expressive it is, you know how you can do a generator and those nifty one liner pythonic. Sorry for our listeners, I was doing air quotes when we're talking about pythonic code and just how nifty it looks. So it scratches that techie itch to do something that's cool and clever and at the same time there's that mindset associated with it, which is keep it simple, don't try and be too clever, don't over design, don't overthink things. And that there's multiple ways of doing a thing. There's multiple roads that lead to Rome, whereas very frequently when you're in enterprise architecture, there's this mentality that there's a highway and the other way, there's only one approved way of doing a thing and Python says no, actually, there's many ways of achieving the same thing. And yeah, since then I've been doing a lot of python. That's nice. That's a great journey. And love how you found that beauty and simplicity in the python. With the Zen of Python, we recommend all our people to read it often to frame it on the wall, because a lot of what makes Python beautiful and elegant is wrapped in those 1920, I think, 19 statements. And it's even that fact that it's called the Zen of python, right? Because a lot of it, it's so dissimilar to when you read other software guides. If you think back to the old big IBM prescriptive enterprise patterns and practices, right from the early nineties, say, Microsoft went through a phase of that. Also. Java, of course, went through a big phase of, you know, patterns and practices and approved ways of doing things. And then you get the Zen of Python, which is like, what, 20, I think 20 little principles that are almost phrased like a Zen cohen, like a foolish consistency, is a hobgoblin of tiny minds. And it's what a great response to everyone that's arguing over camel casing versus Pascal casing versus whatever the currently fashionable casing methodology is, right? Or if the implementation is hard to explain, it's a bad idea. That seems so obvious, but it's actually pretty deep. Right. A lot of these statements really resonate. The other one I really like is, let me see if I can remember. Pragmatism beats purity. Pragmatic, lutely, yes. And in our conversations, a lot of that came back over and over again, where there are always trade offs to be made. What's the saying? Like, fast, cheap, and another thing, and you cannot have them all three. You always have to make choices. Yeah. So being pragmatic is super important as a developer, and sometimes very against the typical nature of a software developer, that can be fall victim to perfectionism. Right. And that's definitely something you have to go against. But we'll get back to that in a little bit when we talk about software planning. First, I wanted to move a bit into the open source, because you're big in that space, and you have a project, Piper, not to be confused with PI I Latina, as you say in Spanish, of the series. Now, this actually with y. So PI y PI r. And yeah, it's a very cool project, but I leave it to you to please introduce us to that project, what it does and why you build it. I'll just say, first of all, as much as I love the Silicon Valley series and their product, Piper, the Piper that we're talking about now actually came before that, so I didn't borrow the name. If anything, they borrowed the name from me, although I tried to be very explicit there. Explicit is better than implicit, right? Exactly. Redesign of Python, people. If you take nothing else away from this podcast, Piper is a lightweight task runner, which is useful whenever you want to sequence some steps in a process. And those steps could be literally anything. It could be a bit of python, a bit of bash, some CLI apps, wrangling some config files, or interacting with the environment to do something useful. Think typically of something like a Ci CD process, where you're compiling or building, depending on your language. You're testing, you're linting, you're doing CD functions like deployment, where you're maybe spinning up servers or docker containers, or deploying to a Kubernetes cluster, or less technically, if you're preparing media for a release, where you're doing video encoding, transcription, clipping, encoding to mobile formats, or if you're in the business intelligence space, where you're doing data ingestion, cleaning, transformation of data loading, all of those good things. So what we're talking about here is a linear workflow, and you typically call this sort of thing a pipeline. And Piper helps you do this, and it comes with a bunch of pre built tasks to help you not have to code repetitive and annoying things. For example, reading and writing files, or automatically resuming or retrying on an error, or retrying ten times, and then going to a failure handler that does a compensator reaction producing output files, very common thing. Also error handling, I've mentioned already looping constructs. Now there are various task runners out there, and to your question, which is what does it do? Or why did I start writing it? It was to address my own personal itch, which, as Linus Torvald says, is the way project should start, and that it was that a lot of task runners are either too focused on the DSL, which, sorry for the acronym domain specific language, so they'll have some sort of abstraction language that you have to learn before you can use the product. But then learning that language in itself becomes a bit of a job. And that's fine, you have to learn new things for every new tool. But that DSL tends to be limited. So if you use tools, you very frequently find yourself uplimited by what that tools DSL allows you to do. So maybe. And then you find yourself wishing when you're halfway through your automation that oh, I wish I was in python, because then I can do a clever nested, nested for loop, which I can't, for example, do in the DSLR. But then on the other side of too much DSL, you've got too much code where there are task runners. That basically just means you end up having to write a lot of code yourself. And I found myself on project to project having to solve this problem where I'm sure most of us have this, but you probably have some bits of code and script that you keep in a folder that migrates between projects and your copy. Yeah, it's funny you mentioned that. We just started a repo called pybytes tools to try to centralize some of those common things we always do. Yeah, exactly right. And specifically when it comes to scripting and automation tasks that you might have, which is something that Piper helps you with, that can get annoying pretty quickly. So think of the typical scenario when you're starting a new project and you think, this one we're going to do, right. So you start off right from the beginning with a little one two liner bash script to automate your build process, say. But as your project progresses, that Bash file gets bigger. And at some point, normally when you suddenly have to put a loop in there, or if, and you're trying to remember how Bash's if statements work? And then you remember, actually, Bash is not so nice. When you're having to encode more complex conditional logic or looping constructs. You start wishing, oh, I wish I was in Python. But even if you started in Python, you find yourself interacting a lot with the CLI, and then you have to invoke the subprocess to co opted a CLI. You have to pass values in and out of the CLI, and then you wish that you were in bash, because that would have been easier. In Bash, what I tried to do with Piper, or the problem I was trying to solve for myself, was to do this more seamlessly, to understand that when we're automating processes, we're, we're in effect, wanting to jump between the full expressive power of Python, or calling CLI apps, or even calling a ruby script, or a bash script, or whatever the odd bits and pieces of tools you have in your chain. And you want to combine all of those and pass values in between them seamlessly so that you don't have to worry about it. And on top of that, specifically things like retries. For example, if you need to make a call to a rest API, but it fails the first time, you maybe want to retry five times. Now, I know there's a certain style of developer who will say, why would you use a task runner? I can just code that myself. And it's, yes, you can. But if you have to do even something simple, like retry that rest call ten times before doing a failure handler, that's actually quite annoying to do with Bash, because it doesn't really have the linguistic constructs to do so. So Piper literally started off life as me solving this problem for myself, and I open sourced it in the beginning. And I mean, back then, actually, before I open sourced it, it actually literally was a single file. And I can't remember what that file was called, but it might have been ci py, because I'm lazy and I don't like typing. And at some point, when I uploaded it to pypy, in case, I'm sure our listeners noticed, but Python has a sense of humor about it. So names tend to be either Monty Python or have a py in front of them. So I was looking for something with a py in front of it. And because Piper fundamentally runs pipelines, I thought, or pipes, because, again, I'm lazy with typing. Who plays a pipe? Well, it would be a piper. And then we ended up with Piper. That's a great story. Before the series. Nice, nice. And you can do everything in Python then? Absolutely. This was critical for me because I don't want to fall into that trap where you have to learn a DSL. And this is very typical with workflow languages where there's some sort of DSL and maybe it's a Gui or maybe it's a yaml, or I mean, even JSon if you want to be wild. But the problem is they lack expressive power. At some point you need that full grunt of Python, but you don't want to invalidate your workflow engine because it's helpful in other ways. So with Piper, you can use the pre built baked in steps to say, read your files, get some config values from a JSON, get some other config values from a web service, call somewhere, combine them, generate some sort of new config file, and then fall into some python to do something complex. And you can do all of that seamlessly and enter and pass values in between them between these different steps in the process, without needing to code that plumbing yourself. Yeah, that's nice. I love those abstraction libraries. I see something similar in the JavaScript well under HTML space. So now we have HT Max, and it allows you to make Ajax calls in your HTML basically with some new syntax, HX dash, whatever. Yeah. And you can now do javascripty things without writing a single line of JavaScript. And it just, I mean, I'm not against JavaScript, but I know a lot of Python developers have trouble with it. Like it's yet another thing to learn, and we have already so much on our plates and it's a super nice abstraction. So it's, yeah, I see a parallel there and it's, yeah, very friendly for the developer. Well, I mean, let's say instead there's the famous comment from Joel Spolsky from Joel on software about leaky abstractions. And what that comes down to is that the more you abstract your code, the more problems can seep in because of what you're abstracting away or what you're abstracting imperfectly. And the point is, if your abstraction is starting to limit you, but then also doesn't give you a way of breaking out of the abstraction, that becomes a difficult thing to deal with, because typically you discover this a couple of months into the project, at which point it's too late to change your framework. You can see the side effects of this. If you look at some older projects, you might find this really gnarly Bash file that's 300 lines long and no one really knows how it works, but also everyone's too scared to touch it because it's accreted over time. There's a lot of complex functionality in there. Worst case scenario, it's using some of those clever bash shortcuts that don't read so easy to the human eye, and you stop knowing what it's actually doing under the hood. And also you could have replaced, say, ten lines of clumsy batch with one line of clever python. And that's exactly what I wanted to achieve with Piper. If there is a simple one line of code that you can do in Python, you should be able to do that one line of code without needing to engage with the DSL or be stuck with the limitations of the DSL. Very similarly, I would argue for specifically the type of automation that we're talking about here, that a simple code beats GUI every time. Because this style of abstraction that I'm talking about, especially with GUI orientated workflow engines, is very prevalent, where the GUI only allows you to do a very limited set of things, and maybe the GUI gets 80% there, but then you have the problem that you just literally can't do the remaining 20%. And it would be handy if you could have a simple and easy line of code that you can use to achieve the thing that you want. Command line for the win. Yes, absolutely. I want to go back to what you said about it all started with one file, Ci Py. And then we get a bit into software planning, but do you see as two or three common problems or pitfalls when we try to plan a software project? And maybe I can actually quote a question that was asked in the slack community that actually kicked off a great discussion we had a few weeks ago. And the question was, I was wondering if anyone has any good material research on how to plan design larger software project from scratch on my own, like going from idea, how should I code this? And I think this resonates with a lot of people that are newer to python and software development, that they overcomplicate it. They tend to overcomplicate it and really think they have to design the whole cathedral before writing one line of code. So I would love to hear your take on that. Yeah, let's say first of all, and you specifically invoke how intimidating it can be for neophytes. And part of the reason is because architects tend to make a big show about what they do for a job, so there's a degree of hierophantic mysticism attached to it. Oh, we've got special outfits, and we've got special documents and special names for things that seem very impenetrable and don't be too intimidated by that. That's the lingo of a certain job function. That's not necessarily what's helpful towards building your own project. So you asked about what goes wrong. I think a lot of this is very contextually dependent, which is to say how you go about your own open source project or your own private little project. The world's your oyster. You can really do what you want. The reality is, no man is an island. We exist in a community of people. As a developer, you probably exist in an organization, or maybe you run your own business, but then you're responsible towards your customers. So a lot of the best practices that you'll see referenced on the web and that people really get upset about on Twitter, and every time someone's got a new book they're trying to sell, there's a new best practice that they're trying to sell as part of that book. And people become very doctrinaire over the one true way of doing things. But the point is, your organization might not be orientated in a way to be able to adopt those practices. And that's not to say that your organization is necessarily at fault. For example, if you work in regulated industries, anything involving security or money, basically a lot of the agile programming style things or scrum style implementation practices can't work quite simply because the industry won't let it. Now maybe that's a good thing or a bad thing. I'm not getting into that argument. I'm merely saying that how you plan is contextually dependent on where you are and what industry you're in and what type of project it is. So the typical projects we see, especially the topical problems we see, especially in the corporate or the enterprise world, are these overly planned, waterfall style projects where you have top down plans, and the problem is they lose all relevance on first contact with reality. So I'm sure we've all seen these design plans that are basically boxes, and one box says authentication service and there's an arrow and another box that says business layer and another box that says data access and another, you know that picture of the brick wall with the fireball through it? That means firewall. A lot of those dotted around, maybe another arrow pointing at a laptop computer and a mobile phone. Now, okay, maybe. But that's not actually selling a project. Well, that's not actually planning a project. In fact, as soon as you start implementing, you discover that your authentication functions actually can't all live in one authentication service, so it doesn't survive contact with reality very long. But it might have been an important part of your corporate software planning and design process. The other famous thing that goes wrong a lot is changing requirements, and the changing requirements is not a problem. To be clear, the problem is our inability to deal with them. And I think changing requirements roughly come in two flavors, which is either the customer doesn't understand what they ask for, and that typically means change requests down the road when they suddenly discover that the software they they spec'd out and agree to is not quite doing what they expected, or it's not quite solving the problem they thought they were solving. But let's not pin this all on the customer though, because as developers we often don't fully understand what we're doing, and as developers, we don't fully think through what's going to be important on a project. So the typical examples would be at biggest level, something like Instagram, which started off as a location check in service, and it ended up that the photo sharing functionality was the bit the users liked more, or YouTube was a dating website, believe it or not. Wow. Facebook was a rate my looks thing, which is a little bit yikesy for Harvard. Back in the day, WhatsApp was just a simple status update mechanism before they figured out people are enjoying the messaging aspect of it. In the case of Piper, I started it off as a CLI, and I thought about it as a CLi until my user started coming to me and contributors started, and it turns out they were using it as an API, which is a very different way of thinking about a project. As a developer, we don't always understand even the code we ourselves are writing, where it's headed and where it might be useful. And the other big problem I see with planning and design is that hidden complexity on things that you take for granted can very easily trip you up. So I'm going to run through some top of head things that annoy me on almost every project. I hit them address validation, which when you're in your design session, sounds like a simple thing. Yeah, we'll have a field for the postcode and a field for the first line, second line of the address, and then we're done. Right, just save it in database. But if you've ever dealt with address validation, you'll know it's actually quite annoying. And because there are so many non standard ways of encoding an address and saving an address, it doesn't lend itself to those rigid structures very easily. The other typical example are names where in the english speaking world we very lazily think that a first name, middle name, last name equals full name. And we frequently design our data structures and our objects to look like that. But there's a great blog, by the way, that I, or a great article that I really recommend, called falsehoods. Programmers believe about names. It was written many years ago, but it's quite concise and in bullets, kind of like design of python. And it just discusses some of those things. For example, ASCII encoding. You can't assume all names are an ASCII. Names change, names change for no reason. Sometimes names can change multiple times in someone's life. Names have prefixes and suffixes. People don't only have one and only one name. Some languages don't have a canonical roman Alphabet spelling for a name. There can be numbers in a name. So suddenly those simple text boxes that you didn't think about during your planning session actually become more tricky than you thought they would be. The other area where this off hidden complexity is whenever you're talking about scalability and concurrency. On the one hand, we've got these best practices about how you would make your system scale, and we designed for that. But on the other hand, a system at scale always behaves in very surprising ways, and you can't really predict where that's going to be unless you understand the problem domain very well. In short, you require real implementation data before you will actually know how your system and your data, with the lengths of your data, how long those strings typically are, how that system will actually behave under scale. Almost the granddaddy or the umbrella for all of these problems I just mentioned, I think is premature optimization, which as we all know, is a bad thing. But let's take the simplest example where this becomes a problem in planning, which is obsessing over scalability, specifically when you don't even have one user yet. I've personally been around projects where not one line of code has been written, not one functional requirement of the user has been serviced, but for various reasons. There's a lot of developer brain and architecture brain that is being burnt on an abstract question over what if we need to scale to 2 million users, and it's maybe worry about ten users or even one user before you worry about 10 million, right? Yeah, this is great. Yeah, just get it out there first and have it hit reality, and then worry about how to scale it. Well, and just to be clear there, Bob, I don't mean to suggest that it's a free for all. And you can just really shoddy code or code that you know will never scale. I mean, be sensible, you know, and bring your experience to bear about what works or what doesn't work. What I am trying to say though is don't kid yourself that a six month planning session is going to fix all the problems for you. It won't, because as soon as you collide with reality, problems that you don't expect will rear their head and then you have to deal with those anyway and they will impact your timelines. So things you didn't foresee, like the trainer of Mike Tyson. Right? Everybody has a plan till they get hit in the face. Exactly right. Something that I also want to add regarding the planning I referenced earlier, that you're probably working for an employer and that employer will have certain ways of doing things. And this could be anything from design by PowerPoint, which I've seen spec by email, which I've also seen your spec effectively starts being 100 different email chains. Typical waterfall or wrap style projects where you end up normally having long Excel spreadsheets or MS project plans scrum or planning poker. If your organization is a bit more modern, faux agile. And by faux agile, I mean there's organizations that pretend they're doing agile, but actually it's waterfall, but they sort of chop it up into sprints and then they call it agile. And as mockingly as I'm talking about all of these, this is the reality that a lot of us have to live in. Right? So what I'm trying to say is it doesn't really matter what the stack overflow argument or the Twitter argument says about what's the best way to plan. What matters is what does your organization do and how do you work within your organization to deal with those plans. So what I try and say, rather than be completely rebellious and saying burn it all down, I'm saying just distinguish between what works for you personally to conceptualize what you're trying to do and to understand what you're trying to do versus what your organization needs you to do. And sometimes your organization needs you to do something for stupid reasons. Other times there are good commercial reasons for it. The point is just that the act of coding and planning your code and architecting, okay, does not exist in a vacuum. You're not an island. So talking in the abstract about how you as a developer want to run a project and plan a project, unless you have no commercial pressure. So if it's just a passion project you're doing in your own time, you can do what you want. You read my mind. I was going there like if you're not constrained by any company or employer and it's your open source project, because I think the person that asked the question asked it more from a I want to build my own thing. So yeah, if you're not constrained by those criteria, what advice would you give our community, people that want to start their open source project? You can probably tell from the way I've been talking so far about big waterfall methodologies that are all about agile. This is going back about 20 years now, but the Agile manifesto, which I forget the website, but I think it's something like agilemanifesto.org dot read it. It's great. In a nutshell, what the original agile manifesto said before it got scrumified and turned into any number of money making ways of encapsulating project management methodology is that working software at all times is better than comprehensive documentation. So in other words, write some code and write some code that works, that is better than a long document talking about the code you're going to write, or planning the code you're going to write. And agile, another core tenant of it, is to respond to change rather than following a plan. So like we just hinted at how to convince your boss or your stakeholders or your customers of this is a different question, which we'll leave to the side. If you're just coding for yourself, then I think following that agile process can work very well, which is to say, start small, start with something useful. The very first iteration of your code can just be one file, it could be one function even, but it can do, and it should do something useful. And what useful is, is going to depend on you and over time build out on that. Now, what I would say is important is some method or some technique as to how you build it out. Rather than worry too much about in advanced planning or planning any abstract, think more about the process of keeping your code tidy as you go. And I'm saying tidy very much on purpose here because I'm trying to avoid the concept of clean code because I feel like clean implies a value judgment. Let's just say instead to think about more of a practical principle of how you do the thing than a planning document per se. So when I say as you expand your code, what you should be practically thinking about at every step is how can I keep this tidy? And tidy for me is just think of it as a semantic structure or a taxonomy that makes it a bit more predictable to navigate your code base as you grow better at what you do. And as you learn your problem domain a bit better, you'll start intuitively recognizing where those opportunities are and code for them in a better way. And again, writing code and letting the tire hit the road is one of the best ways of discovering whether you're thinking about something in the right way or whether you're thinking about something in an extensible way. I mean, funnily enough, it can be as soon as you write a unit test, which, by the way, you should be doing. As soon as you've written your code, you might discover that there's a problem with your API or there's a problem with your function signature, just because you suddenly realize it's hard to test, right? Or that, and then you might refactor it. So again, now it's a bit easier to test, which normally sometimes means that it might be more extensible or more malleable for use in other places. Writing test can be an eye opener that can really show you how you design is going to work or not. Yeah, you need that regression suite as your software grows. Exactly. And what I'd also add regarding your question on as your project grows, when you see a big finished project, it's very intimidating. And you think, how did they conceptualize all of this? And the reality is they didn't. You started off with a file or two files or free files, and that built up over time. And the key is your method for imposing tidiness as you grow with time. And what I want to be clear on here is that a lot of people get into very pedantic arguments over what's the best way and the purest way of organizing a project, and what folders or directories you should have. And what I'm trying to say is that doesn't really matter. Pick some sort of categorization schema, one that makes sense for you and for your project, one that you can navigate. If it becomes too clumsy, then reshuffle it a bit. There's no offense in that. Think about it like you would organize your books or your CDs, right? You can do it by title, you can do it by author, you can do it by artist, you can do it by genre. You can get into big arguments over how you argue, how you should optimally organize your CDs or your books on your bookshelf. But ultimately, it doesn't really matter, right? All of these things are just taxonomies or categorization mechanisms to make it easier for us to find things and easier for us to interact with. This thing in the future. And rather than get too stuck on what's supposedly the best project structure to use in advance, that will reveal itself to you over time, as long as you keep up with the tidiness, which is to say, don't let technical debt build up. It's like dishes in your sink. Once they reach a certain level, it's annoying because then it becomes harder to clean. If you clean as you go, then yeah, all of life. It's very easy to have that stand in the way to get something working, which is requirement number one. First get something working and then make it pretty. And the whole file structuring is the pretty part. It's important, especially if your software grows. It needs to be organized well and it has a lot of good reasons to put it into multiple modules. But it's often not the first concern not to get something off the ground, right? Yeah, awesome. Well, I think this is valuable for the person that asked this and to many of our listeners. So we're coming to the end. So yeah. Any closing thoughts or recommendations for our audience? Things you want to share on top of all the good stuff you have given us already? That's a broad question. I feel almost a sense of responsibility about answering it. Well, closing thoughts or recommendations, let's say. I think a big thing that was implicit in everything we said so far is adaptability, or differently put, responding to change or how you respond to change. And that's absolutely especially in software, the waters we swim in. But I think even as a more general statement, as being a human being and living in this world, it's that adaptability is a good thing. The world will not bend itself to your will. It's up to you to find a way of working with the way that the world is. And maybe that means understanding what changes you can reasonably implement, understanding that thing about practicality, beating purity, and spending less time arguing online about what's the best way of doing things and instead getting on with doing things in interesting and problem solving ways and doing your best. And that part of it is important because I think also it can be easy to overlook that when we're talking about these ideas of do more sooner or hit the ground sooner or code more. That's not to say code lazily or code sloppily. That is to say you should be challenging yourself to do the very best that you can do at every step of the way. You should be researching at every step of the way what's the best way of doing a thing. You what we're what I'm trying to say is just, you shouldn't only be doing research, you should be, you know, try to do a little bit every day. And I think by bite is actually great with that in encouraging people to do a bit of code every day. Because over time, that's the way you learn, right. There's an accumulated knowledge and accumulated experience that you get, and that spaced repetition also helps those good patterns and practices bed themselves into your mind until some point you reach that Zen mastery where you don't have to think about it too much anymore. Yeah, there's definitely a muscle memory thing going on. The more you practice and you repeat certain code idioms, they become automatic. And yeah, we, our aim is to get people out of tutorial paralysis and get the right code with us every day, because that's the best way to become a software developer, to become very practical and to write code every day, not be held back by perfectionism or what people might think about your code or best practices. I mean, these are important best practices, but not to get something working, you have to get out there, basically. So I hope that's one of the takeaways. And there were many in this episode. So thanks for sharing your experience and knowledge. Very interesting. And yeah, we probably should have you back at some time. It's a pleasure talking to you, Bob. Yeah, and yeah, everybody go check out pyper, basically. But I spell it again. P y p y R. Open source project on GitHub. You can also hit up Thomas on our slack. He's Jay Thomas. Thank you, Thomas, for being on our show. And yeah, you have a great week. Same for you, Bob. Thanks. We hope you enjoyed this episode. To hear more from us, go to Pybite, France, that is pibit es friends, and receive a free gift just for being a friend of the show. And to join our thriving slack community of Python programmers, go to Pibytes community. That's pybit es forward slash community. We hope to see you there and catch you in the next episode.