Transcript: Dev Environments - Calvin Hendryx-Parker
Hi, welcome to another episode of Django Chat, podcast on the Django Web Framework.
I'm Will Vincent, joined by Carlton Gibson.
Hi, Carlton.
Hello, Will.
And we're very, very pleased to welcome Calvin Hendricks Parker back onto the show.
Welcome, Calvin.
Hey Will.
Hey Carlton.
How's it going?
Hey, very well.
Thank you for coming back on, Calvin.
I'm excited to be here.
This has turned into an annual thing, so lots to talk about.
Um Python WebConf, Django Cons, PyCons.
Um, maybe like what's been new the last year for you, right?
There's a lot of things, but what what's top of mind when someone asks you, what have you done for the last year professionally?
What are the highlights?
Well, the highlights professionally, uh, we've done a lot recently with Airflow.
Uh so I'm I'll be giving a talk this year at PyCon on um scaling to thousands of DAGs with Airflow, which is Django under the covers, which I feel is appropriate to bring up uh on this podcast.
But it's a really, really cool product.
Um, for those of you who have not gotten into orchestrating like your ETL loads, or I mean we use it for other things too.
We've actually used it to orchestrate on um manufacturing floor processes, you know, robotics, like interesting like kind of crossovers into real-world physical things.
And then we do also use it for some traditional uh data loading ETL uh type activity as well.
Can so I've used Airflow a little bit, and the thing I think is really exciting that I could perhaps get you to um riff about is the DAGs, the the the the the way you define the task dependencies.
And can you perhaps explain that for folks?
Because I think it's really interesting.
Right.
So basically you can think of Airflow as just a a really, really glorified cron.
Or, you know, if for those of you in the Django community, I mean it's like Seller, you can do asynchronous tasks and have it run these various things in in some sequence.
That sequence though is super customizable with Python, and so you can define task A, B, C, D in some order, or those can branch.
Now, the whole thing with a DAG, it's a directed acyclical graph, which means it can't cycle back onto itself.
There's no loops in a DAG, technically.
So you're actually going to be making decisions about what paths to follow, and like there can be failure situations and recoveries, and actually run certain tasks in parallel.
So you may have a thing that starts, but it the next step may be highly parallelizable.
So you can actually take it, split it up into a hundred separate processes that can all run simultaneously, and then as they all finish, they kind of report back in, and then they can kind of come back together and run the next set of steps and things that are on there.
And there's a couple ways you can actually define DAGs.
You can use just plain straight Python, put it in the DAGs folder inside of your Airflow instance, and it'll pick them up.
It looks every you know so many seconds to refresh that folder to see if there's more DAGs that have been dropped in there.
You can also define the dynamic DAGs.
So DAGs that are like DAG factories.
So it basically can dynamically instantiate and generate you know hundreds.
Well, I'll say hundreds at this point because thousands really isn't realistic.
That's actually a limitation we ran into with the big project we were working on, and that's what I'm talking about at at uh PyCon this year is the fact that as those things scale up in dynamic DAGs, you run into timing issues that the the scheduler looks for new DAGs, the the dynamic DAG starts building a dynamic set of DAGs, but if those two times start meeting, that's when you run into real real trouble because basically the scheduler starts looking again and you're not done generating dynamic DAGs, especially if you've got in an order of thousands.
And that was the case we had, which was tens of thousands of uh DAGs in a single Airflow instance.
And I told this to some people who are in the data world and they're they were like, that can't be done in Airflow.
I go, we did it.
Uh there's an interesting workaround, and then and if you want to post a link to the blog post on our site, we actually posted how we did it.
I mean, there's no there's no trade secrets here.
We want to help the community, but it's pretty cool, and that's what I'll be talking about, and just kind of giving some insights into there's some cool workarounds with Python that actually helped in this case, where we actually have have one, we still have one DAG, but we aren't using the dynamic DAG factories.
We actually have a process that comes through and and writes out names of files that are all symlinks back to that single file.
And based on the name of the file, we basically substitute in you know new configuration, new sources of data, and actually can now scale this to still tens of thousands because the the reading in of single Python files on the file system is fast.
That that part's super, super fast.
So it's really not an issue.
It's when you get into the dynamic DAGs and trying to generate thousands of them in memory and dynamically, it slows down considerably.
That's really cool.
Can you talk about um how you like the progression to getting up to airflow?
Was this like a project where you did you start with salary and then you went to Airflow?
Like how do you reach for airflow?
I that's always my kind of question.
I guess it depends on the problem space.
In this case, the the customer was using another uh they were using a different orchestration stack called it was a PowerShell Windows, you know, orchestration tool that was kind of a glorified glorified cron, but they had bent it in in awkward ways that were very hard to maintain.
And they were also looking to basically get in line with best practices for big data, and which seems to be you know, you're either using Python or you know, there's a few other kind of common Java, a couple languages are that are in there, but they wanted to be on Python now, like it's they think it's gonna be the easiest way to onboard new data engineers, you know, people coming out of school, people who can jump in and actually be productive.
Python's an awesome choice, obviously.
So that's that was the reason they came to us was really to actually uh first review some of their Python notebooks.
They'd done some you know, Jupyter notebooks that were running in Databricks as part of the ETL process, and they wanted us to code review them, see if they were up for best practices.
And as we kind of started digging in and seeing what was actually going on inside their whole architecture, we realized really quickly like that this can be done with some open source tools.
They probably can actually minimize the reliance on some proprietary licenses.
So spend more money on their own people, getting them up to speed on Python and and notebooks and things like that, as opposed to spending money on licenses uh for big proprietary pieces of software that are that are actually hard to configure and use in an automated fashion.
Those are a lot of point-and-click, drag and drop, you know, kind of analystware type tools where they wanted to be able to check this in, have it be all automated, have a CI CD process, actually do uh continuous integration, have tests on their configuration files so that they can detect problems before they even go into the dev environment.
I think something you mentioned there was that about the hiring process, because if you use like a you know, so to there's that um paper about using boring technology, and you know, Django's always a boring technology, or Postgres is a boring but technology, you know, Django's cool, Postgres is cool, but in this sense they're boring in that they're they're they're known commodities.
Um Airflow, I think, actually has made its way into that category now.
It's it's a standard tool that's reliable, known by the community.
And if you're using that tool, A, you can have less dependencies, less sort of niche, niche bits which are custom and bespoke and need special knowledge to run.
But you can hire someone new.
You can say, hey, we're using Jangle, we're using Postgres, or we're using Airflow.
I think that's
super powerful.
No, I do too.
And I think it's worthwhile to link to that article, that blog post.
I I go back and read it every couple years just to remind myself that all the new shiny things aren't, you know, always that there can be trouble in those waters.
Uh it may look like greener pastures, but yeah, it's the boring tools get the job done well.
Now, I I believe in instead of doing bleeding edge, I do believe in like leading edge.
Like I feel like we want to stay on top of what is the best practices, and Django absolutely sits there in that leading edge still of best practices.
It's boring, but it's productive and it gets the job done and it can scale and it can do small things and it can do big things, and then people have taken it to build awesome tools like airflow.
I've made an analogy with surfing at times.
It's surfing, you you don't want to be in front of the wave because you know you're paddling and that's a lot of hard work.
And if you're behind the wave, well, you know, you sort of just stop going anyway.
You've got to be exactly on the wave, right?
Right.
Yeah, yeah, it makes sense.
Well, they I mean the also the version of that, I mean, because Silicon Valley loves that analogy is you know, you can be the best surfer in the world, but you gotta wait for you gotta be on the right wave, right?
Because it's frustrating.
You see someone else, you're like, they're they suck at surfing, and they're just like killing it.
And it's like, well, gotta find a way.
They got a Malibu longboard and they're just going.
What's with that guy?
Can I can I ask you about the psychology of the the the catnip, the the new and the because it's part of it as a programmer is like you always want the new tool.
You always want to play with the latest.
What's your thought there?
Because how do you resist that?
Well, and it's uh it doesn't affect everybody.
I mean, there are probably 90% of the developers in the world who are sitting happily doing the work they're doing day in, day out, and maybe not even looking to the sides like what's going on, but not that's not me.
And that's not a lot of people I hang out with.
So maybe you just kind of you're always you, you know, birds of a feather flock together, and maybe we're all just hanging out together, Carlton, because that's what we're attracted to is like these are the same things.
Well, you're a consultant, right?
You're a consultant too.
I feel like consulting, you're sort of interested in a lot of variety in the new thing, anyways, right?
Like it's not right, like you get airdropped into cool stuff, you're not maintaining like my iteration questions assume that you know you'd built it from scratch, whereas you you get brought in when they're like, Oh, things are broken.
Like you kind of want a consultant to be up on the shiny new thing and to have a take.
Yeah, no, that's that's true.
I mean, uh, that people do rely on us to kind of vet out those shiny things to make sure that they're not making a mistake, you know, down, you know, a couple years down the road.
Because everyone would love to be able to build a piece of software and just launch it and be like, okay, it looks cool, we're done.
Like it's awesome.
Like, but that's not true.
Like it you build software and then you have to maintain that software.
You you you're now jumping on the treadmill uh with your your product and had to you know you have to keep putting work into it to make it still work and uh day in and day out.
Now the back to the kind of shiny question, I think we do a lot of in-house like uh show-in-shares, like you know, kind of like kind of like kindergarten, like bring bring your favorite toy to school and and show it off.
So a lot of every developer kind of gets an opportunity now to show off or look at some cool stuff, and then everyone gets to see it and talk about it and discuss like what their thoughts are on it.
So we we've gone back and forth a lot on especially JavaScript technologies, because we're you know historically been more of a Python shop, and that's you know, things we've always done have been Python, but there's no ignoring the importance of JavaScript and now TypeScript in in our our work our day-to-day work.
So understanding what's our approach and like what what do we care about in these various technologies, how do we want to actually like you know code code for them, put in linters, like you know, like where are our guardrails for doing a new a new piece of technology?
Those typically come out in those kind of text show and shares.
Yeah, and I think in JavaScript, managing the the tech stack is all the more difficult, all the more like pressing.
It is tricky.
I I would I would definitely agree with that.
I think that's I mean, that's great to have to have that internally, because that is I think in any field, you know, if you're like a musician who plays rock, you know, rock and roll, you probably want to do jazz, or like if you're doing some big project in programming, it's nice to just spin up a green field thing.
Like you need to keep that beginner's mindset and that playfulness, which you can't always maintain if you're only working all the time.
And something does I mean, I remember when I was, you know, in a previous life I was a book editor, so all I did was read, but reading with an eye at prof like as for as an eye to something as opposed to reading for fun, you're like, why the hell would I want to read for fun when all I do is read?
But like you lose something.
So like ha building that into your company, I think is you know really important because otherwise you just get stale and yeah.
Well, there's a certain passion people have to have for the craft that they're doing.
Actually, that's one of the things we'd look for in a developer who would join our team is gonna be uh a profile we call craftsman.
They've actually renamed it since then, but we use a couple assessments and tools to look at the whole person that we're bringing in to hire our interview.
And one of those criteria is there's some indicators and markers from some specific assessments.
They're not the end-all be-all of whether we'll hire a person or even interview a person or not, they're just one more piece of data point that we can actually look at, and knowing that they're in that craftsman you know arena um means a lot because they've they've got just kind of certain motivators in their life about I'm excited about technology or I'm excited about the craft of it, or I want to build, you know, as opposed to the other people who have different skills and different like passions and they suit better into different spots.
Can I just ask one more question while you're talking about hiring then and teams and craftsmanship?
Um, do you do you have like um a kind of standardized tool chains and standardized processes so that people can switch between projects and that you know the tooling's the same or we
are absolutely working on that, yes.
Uh so we there's some of it depends on the client because we are consultants, and so some clients have maybe they're on Jira and we want to use you know Bitbucket or Utrack or GitLab or some other tool.
So and one of the things we're working on right now is really the developer experience at Six Feed Up, and taking that developer experience and then applying it to the client in a way that they see a lot of value in it, that they may adopt that best practice we think we feel like is a best practice in software development lifecycle.
So absolutely being able to use, well, everyone kind of picks their own IDE, but things like pre-commit hooks, you know, having those set up so that everyone's running black, everyone's running iSort, everyone's running, you know, Pritify or Prettier on JavaScript, so that those common guardrails happen before they even hit the CI pipeline.
That helps like get everyone in the same, you know, rowing in the same direction when it comes to their development tools and stacks.
They can use whatever IDE they want, but the code they're gonna submit is gonna kind of comply to some internal standards.
And then using tools like we're really uh rapidly adopting Kubernetes.
And we've had adapted, you know, containers because that actually leveled the playing field for folks to be on a Linux, Mac, Windows, and actually be just as productive in any any of those platforms.
Now the next step is actually adopting Kubernetes so that the the process of deploying and developing almost looks identical.
Uh there's just you know different versions of the container you may be using for development that has the dev tools installed or the PydevD extension so you can do remote debugging.
But when you're releasing that container into production, that whole process, the whole stack doesn't look unfamiliar.
Um, because it may look unfamiliar now.
If you're developing locally on Docker Compose, but releasing into Fargate or some kind of Kubernetes, the developers are like, I know nothing about this deployment process.
It is there's zero attachment other than the fact there's a container that runs my code.
Sounds nice, Carlton, right?
Simple deployment.
It does sound lovely.
It sounds lovely.
I mean, you know, um I think the key bit there is keeping the dev and the deploy looking similar, looking the same.
Like you would
we've always strived for like our QA or staging environments to be identical or as close as possible to production, but bringing that a step back further into the development environment without it being so onerous to run.
I think a lot of the issues before is if you wanted to run a full stack of stuff locally and you were doing a Django app, but you wanted to be able to have you know the Nginx and load balancing and the Redis cluster and the Postgres cluster and all these other kinds of pieces running.
Well, you either had to install them from like Homebrew onto your Mac, and then maybe you had a slightly different version that was within QA, or you know, there's some always these little rooms for strange edge cases to sneak in because of that.
But if you start using these Kubernetes manifests, you're using the same manifests but just defining different environments.
So there's the same versions of all the containers being run, same versions of the database, same versions of Redis, same versions of everything now.
It it seems to be a lot more reliable and and and uh repeatable to do those deployments.
Well, that's the I want I want to ask you about your um bootstrapping your local Python environment talk.
Actually because Carlton and I were talking about this before you came on, but it is true that like of my three books, the third one just uses Docker because I'm like, okay, like you know, containers, you're all set, but it that's not that doesn't work for beginners or all edge cases, even though maybe in a more professional setting, it's just like just containerize it.
And that's what I get to at the end of my talk.
So we we're
go go go ahead, Carlton.
Well, no, no, no.
Because it's it's not necessarily for me, it's not necessarily about um professional or versus amateur.
It's about sort of the kind of complexity of the team and the complexity of the stack.
Fair enough.
You know, if if it's like a small startup, you know, five five five people in a team, you may not have the ops chops to take on something like Kubernetes.
Whereas if you've got a 20-person team, you want to have that ops person there who's uh making sure that those 20 people are all doing the same thing.
And it depends.
If you're just running just running Python and you know you've got a hosted um a hosted Postgres, and you know, maybe you're running Redis.
That extra ops uh complexity doesn't necessarily pay for itself at the small scale.
But if you've got a bigger team, then sure.
It I think it does.
I don't think it precludes you from using containers in either case.
Even for small, small scripts, we still use Docker locally to run a single Python script because you can guarantee the version of Python is going to run on a guaranteed like user space inside that container.
It just narrows it it keeps everything so much more sane.
Uh so I even even now, and this is one of the things I got again, I got to at the end of my talk at PyCon last year, was that Docker was really the way forward, I think, for especially developers who are across uh a heterogeneous environment of of OS, versions of OS, versions of Python, how they got installed, where they came, you know, you don't know where that Python came from when you type Python the command line.
I can know I know how to guarantee I know where that Python comes from when you write, you know, Docker run my my image.
So so what's your answer to how do you bootstrap your Python environment?
Wait, wait, sorry.
I want to I want to I want I want him to do the talk.
I just I just want to make okay.
Whoa, whoa, back up, pull it in.
I've had this conversation a lot with readers uh you know, and so one of the one of the major things I hear from from people around Docker is you know you need a nice laptop to run it.
A lot of you know, you need a lot of RAM.
Or more, you know, so it is a barrier, someone you know, who doesn't have a lot of money, who doesn't have a nice, you know, fast laptop, Docker sometimes is a non-issue.
So um well,
I guess that's one of the reasons we moved to Kubernetes, uh, which sounds odd to say because of the left explaining that conversation.
Uh the reason we've started using tools like Kubernetes is actually if you're running Docker and Docker Compose, you can run a Docker instance remotely on some other machine and actually like, you know, from your local machine, control that through the Docker, you know, control plane, or even Compose.
Now, the issue as a developer is you want to be able to bind mount your source code into that container when it's running, so you can debug or change the code and have it auto you know, hot reload like Django or the uh React code, have it hot reload for you.
That's that's almost impossible to do on a remote machine if you're just using straight up Docker and Docker Compose because of the whole bind mount limitation.
Now, tools like Scaffold and Kubernetes changes that model.
I can actually now, actually, Scaffold's faster at syncing files into a container, running container, than Docker is at bind mounting because of the I.O.
uh.
complexities that Docker brings to the table.
Now they they fixed some of these performance issues in Docker.
It used to be terrible.
Uh I don't know if you've ever developed kind of a few years back on Docker where you were bind mounting in there and changing or had a large project that was bind mounted into a container, but the I.O.
was terribly slow.
Uh but you get around that if you start using alternate tools like uh, for example, I mentioned Scaffold, which can synchronize, it watches for file system changes, synchronizes just those changes into the container for you, and then you get the hot reload capability, and now you have the ability to actually dev locally, work on local files using your IDE and all your standard developer tools, but have those synchronized into anywhere.
Um you could have a sidecar, like small little you know, Intel tower sitting, you know, desk side, or or it could be a cheap, you know, um droplet in DigitalOcean someplace that is actually running you know micro microkates or minikube or you know, you've got some lightweight single node Kubernetes option for development, and now you can spin up for the couple hours you may need it a day to work on that specific project for pennies, uh the all
the RAM you want.
Yeah, I mean related there, I've recently become quite a fan of the uh code spaces integration into GitHub because I've just taken to that pressing um in a repo, just pressing the full stop and it convert and it just flips over to this GitHub.dev and a kind of VS Cody type thing loads up, and then you think, oh actually I need I need a an an actual um I need an actual computer here.
So you you just go, oh, load this into a code space and then it refreshes and then you're like, oh, do you know what in the browser it's a bit of a pain, I'm gonna switch to VS Code on the desktop.
It's like that's quite nice.
Um and I've been this I've I've been a skeptic for a long time because I I um I really love local development for all the convenience and me
it makes developing on an iPad a a reality.
Like the iPad Pro now, with the new especially with the new uh stage manager uh windowing, the in the in the difference between a MacBook Pro and an iPad Pro is becoming very, very slim as far as the user experience and usability.
Sorry if you can hear my dog in the background there.
Yeah, but
sorry, we like the dog, bring the dog on more often.
Yeah, he's he's quite cute.
But yeah, I love that portability.
I I want to travel with just my iPad, but I still want to be able to jump in and fix a problem if I need to, although my my leadership team would tell me I should stop that and actually rely just on my team instead of me doing those kinds of things.
But I still love to tinker.
I still want to develop and be able to do it from an iPad wherever, you know, hooking up a keyboard and I've got a mouse and now I'm in code spaces or some remote uh compute environment, there's way fast the iPad's dang fast, but it's so much nicer to have a cluster of machines in a cloud someplace that I can resume into.
So if I was at a coffee shop, pick up, go back to the room or whatever, and then set back down again, uh like nothing, nothing happened.
Like I've just I'm back in the flow again.
And it gets over that limitation of the you know the the iPad OS where you can't run you can't really run a Python interpreter, or you can't run a gross compiler, or you can't run a you know anything.
Well, no, it's all on some box somewhere in the you know ethosphere.
Yeah.
I think for developer experience, that's that's I think it's a big advancement for let's kind of roll back to those developers who are not the bright, you know, shiny, you know, lovers.
They want to just come in, do their work, go home.
I think for those developers, this is a great uh innovation for them is that the people who do like the bright and shiny can set up the most amazing development environment and now share it like a rubber stamp to everybody in the whole team.
Uh and now they can all share in those same productivity tools that the you know the one person who's super passionate about getting all the power tools into their environment, their dot files are thousands of lines long because they you know just love tricking out every aspect of it.
That might be me.
Uh, but I can now set this up for everybody and be like, check this out.
Like, here's it during a show and share.
Show them all the cool new few superpowers that are available to them on their command line or in their IDE or in their editor.
Uh and it just goes a long way.
Because some of them would be like, oh, that's cool.
I would use it if it was easy to set up.
But those things aren't always easy to set up, but they can be uh shared with others easily.
Yeah, so that dev container approach.
That's yeah.
Well, speaking of, I wanted uh maybe we've already covered some of it, but your PyCon talk about bootstrapping, I noticed your command line, you've got that nice little timer thing for commands, like a little hourglass.
I was because I mean I'm not fully tricked out, but I, you know, it's fun to do.
But I was like, ooh, I I hadn't seen that before when you were doing some commands locally.
So yeah, so
I went I used I I can't remember what phase of my computer that so I'm again, I'm a tinker hacker, I love fiddling with my my laptop all the time.
For a while I was using the bullet train go command line, but that that got went, it went uh kind of unmaintained, and I finally graduated into uh power line 10k, or I think it's what the current one I'm on.
I've been really happy with it.
It's but it's infinitely configurable.
You can spend a couple days you know running through dot files.
If folks are curious, my dot files are on my GitHub, so you can actually just go to github.com slash coblin hp slash dot files and see like the my configuration I use for the the power line 10k stuff.
And it's it's it's so nice.
I mean it's nice to have all that extra data right there available to you, especially the time, uh, which more valuable than you think, because as you are running commands and doing things throughout the day, you'd be like, oh shoot, how long did that thing take to run?
Or what you know, what time was I working on X?
Because maybe I needed to jot it down into my like timesheet or whatever.
I can definitely scroll back through my buffer or my terminal now and see, oh, that was at like 10.15 and you know I took 10 minutes to run.
And just provides all that additional context, especially the virtual environments bit too.
Like knowing what the system Python might be or what the virtual environment you have activated actually is can save you a lot of mistakes.
I don't know how people will go with a prompt that just has the dollar sign, like it mind-boggling.
Like well, that's yeah.
I mean, you need you at a minimum, you need to have the get the get stuff to let you know if something's changed.
Well, you say minimum you say minimum, but how many people have you ever seen like open up a terminal and you're like, Whoo, oh boy, we got some work to do here.
Like they're they're just they're riding pretty stock.
Oh, ever i I try really hard not to immediately judge them.
Right.
I'm saying judge.
Well, because it's no because it's because it's you know it is it's like it's like site design, right?
It's like Simon Willison's site, right?
It either like their terminal looks like that, it's like they're either Simon or they're not.
You know, that's immediately I'm like, it's an extreme here.
That's what I think.
All right, wait, wait, wait, wait.
So I mean, so your your talk though, local Python is uh a challenge.
Um I thought you actually the best job I've seen of laying it out.
I did want to ask you though, you I think you punted a little bit on like how do you recommend people install Python?
Because you mentioned there's like
I I 100% recommend PyEnv for installing a version of Python.
Uh any other Python can be is untrusted and pop possibly incomplete.
Uh that's been a huge pet peeve of mine.
The fact that you can install Ubuntu or be using an Ubuntu container and you won't have necessarily uh pip available or you won't have some some of the standard library modules will not be there because of some opinions that the OS makes.
And most likely they made those opinions to protect the OS.
They don't want you randomly pip installing something into the root global environment, which is a good thing.
Uh but it means that you really need to be installing pyEnv so you can control which specific version of Python you want.
And I recommend installing py env with the virtual env extension so you can just from right from one command line, create the virtual imms, activate them, and now when you go into those directories or out of those directories, it automatically activates and deactivates those virtual imms.
So I'm never typing activate, I'm never typing work on.
Uh I'm always just relying on you know the the.python version file that's in my you know path that just picks up what I should be doing wherever I'm at.
Because I'm moving from project to project a lot.
That may not be common for most people, but it's actually far more common than you think because you're probably developing side tools that you're using as part of your course of your work, and those should be in separate projects from like the main project you're working on, and they maybe uh have different requirements than the main project you're working on.
You may have different version requirements that you need to pin specifically for that side tool as opposed to the the more stable project that might be running on an LTS version of a library or a project.
I I like too in your in your talk, you mentioned or you recommended um PipEx for you know global global things like black and stuff that you want.
Yeah, for folks who don't know, PipEx kind of takes a lot of that headache out of the way.
And also, I think you get more recent versions of some of those pieces of software.
So you could brew install black or iSort, I think.
I think those packages may be available in homebrew, but they're not gonna be as up to date as if you pip it, pip installed them from PyPy, because those may be the latest versions.
Maybe the homebrew maintainer hasn't gotten to updating the the entry in the homebrew uh package catalog.
But PipEx gives you the best of all those worlds where I can now Pipex install Black.
It installs an it creates a virtual environment behind the scenes in a dot directory you don't see.
But then it also puts the tool into your path correctly so you don't think about it.
You just type black and it's in your path it's going to work.
It's going to you know always be pinned to the right versions that are used for that version of black.
And you can install yeah you can inject other dependencies in there.
For example if you're using um like the markdown tools and you want to install pigments into that virtual environment it's it's very possible it's absolutely possible to now inject the Pigments library into that version of the markdown virtual environment and use it with your Python markdown command but have a different version of Pigments you may use standalone from the command line.
Because they're in two separate environments.
So the the the case I have there is with Sphinx because you always need extra you know plugins and things with Sphinx.
So that that all so there's one environment that's got all the Sphinx bits in and I can just
for my dot file configuration management.
So that that tool allows me to actually have a SheaMa init uh bootstrapped command.
So basically a text file that design defines on the very first run of this dot file manager run these commands.
So it basically goes installs homebrew installs pipex installs all my standard utilities so that every command I expect to use now will be available.
And that's a big complaint a lot of people had about customizing their dot files and customizing your shell is that you log into some random shell to debug something and half your stuff doesn't work.
So your muscle memory's all broken on you know your keyboard you know memory is is is missing.
But for me I log in I literally do shame oneit CalvinHP because it comes from my GitHub it knows to look in GitHub to get the dot files to run that first bootstrap command and maybe it takes 30 seconds to a minute but everything now just works.
Yeah that's that that that not having a tool when you log into a strange box.
That's kind of why I keep my my setup quite vanilla is
that Carlton there's no reason.
Check out stream one
maybe there is I'm old that's the reason
speaking of speaking of being old Carlton can we tease your PyConitalia keynotes because it's out there
yeah yeah you can so I've um I was invited to keynote at PyCon Italia and I'm doing a a keynote called um open source for the long haul which is you know what about what it says um and but the the kind of the the the relevance of being old is it's kind of the um the the coun
terpart to the growing old grace free talk I did five years ago when I in um Heidelberg when I started fellowing and now I'm finishing fellowing and I'm doing an a kind of talk okay so and and yeah this is the the the reflections it's not explicitly a reflection on that but as I'm writing it it's a reflection on okay that's what I said five years ago what would I say now so I'm quite excited about that.
I have to go
watch that I'm quite interested I I I've followed your journey from the beginning as a fellow so curious to see what the the wrap up is the postmortem you're not dead luck yeah
no no no no no no but you the I mean part of it is you've got to be able to step away before you become you know
so um well segue to conferences Python WebConf is coming up in um a couple weeks march March right yeah
March uh 17th through the 2
3rd I think that's that
that's I'm yeah we'll have
if I don't get that right I'll be in trouble.
But uh I'm
we'll put a link but it this is um you know speaking of watching things grow over time I mean this is really yeah up and up and to the right um fifth year.
Fifth year but I mean the the speakers and the number of people and everything is really impressive.
I saw actually you did some videos um you did one with Al Sweigart but like you know even teasing out you know guests now so it's really impressive to see.
There's more of those coming uh I think tomorrow I'm actually interviewing Anthony Shaw who will be one of our speakers from Microsoft.
Uh we've got two speakers from from Australia uh who are joining us.
I mean that that's the dedication that for the people the excitement level that the speakers have about this this conference is that they're willing to come at like three in the morning their time and give their talk live to the crowd.
But it has grown a lot over the past five years.
We started this in 2019 as a virtual conference before it was hip to be virtual and it will always be a virtual conference.
So one of the things I always love to tell people about this conference is it is really meant to be accessible to those who may not be able to make it to a PyCon or a regional conference of some kind.
We want to make sure that fills that gap and the other part is I want to make sure it fills in where I feel like some other conferences may be lighter on the intermediate content.
I think there's definitely a space for like the PyCons and the regional conferences to handle a lot of those newer intro talks to get people spun up into the Python community in a nice gentle way.
We're really meant to bring some heavy hitting talks not that I would dissuade you from coming if you don't know anything about Python, but you're gonna definitely be in a a more advanced group of speakers and and guests and and people who are attending the conference.
It's really a lot of very professional folks who are doing a lot of cool things with Python.
I had a kind of intro talk with or conversation with one of our speakers yesterday they're talking about the state of fusion so those of you who are kind of following the the fusion story right now that we finally had in the last couple weeks the first time that more energy was produced by fusion that went in to than to make the fusion uh process happen we have a speaker who's gonna actually gonna come talk about where Python's playing a role in in that uh that science so I'm really excited they're they're super passionate about you know obviously this topic I know very little about fusion so I'm looking for
ward to hearing about this.
This wasn't the speed ups in Python 3.11 was it
no no no no no I I don't think they use it in that level where the performance actually matters they've got other things they're doing but when it comes to data and accessibility and getting people onboarded to be able to process all the data and actually come up with new insights into what's going on in the science Python is so hard to beat.
It's a great tool because it just provides people with so many superpowers.
I mean the battery's included and then you layer on top of that like pandas and Matplotlub and and all these great libraries that just give people superpowers without having to do much work to to kind of get to that point of having all those things at your fingertips is really a powerful story for Python.
Yes.
So that's what you'll expect come to expect to see at uh Python WebConference this year we're gonna be five days uh half days East Coast time we will have a keynote speaker kickoff every day and a keynote speaker to end every day I really love hearing inspiring speakers so even though we are a virtual conference we are having 10 keynote speakers as part of the the uh the standard uh program and that will never change because I I love having just big thinkers get up on the in in our stage and actually talk about the things that are going on in their lives and and those talks range
from technical to I've had some speakers who had barely ever used Zoom before who are non-technical give some amazingly moving talks.
So if you look last year's talks are all online uh there's a talk up there by um a Noel Musica talking about the flower and it'll bring you to tears uh but it'll move you to to action and and whatever that passion may be inside of you and that's what I want to draw to people and mine just happens to be Python in the community and that's just where I get a lot of energy.
So I want everyone to join me for Python Webconf.
Super I know Carlton you know with all your postfellow time 2024 Carlton will be everywhere.
Oh I talk to say we were just talking about this yeah actually we were you might appreciate this Calvin I was sharing uh a quote about um you know marketing right tech people famously don't like to do marketing and it was saying that you know it's seems self-involved to market but it's actually more self-involved to think just building it people will come to it because why are you so important that people care?
Like that's so true though it's so many times people think that you know if you'll build it they'll come how are they going to know about it?
Who who are you that's gonna bring them to it?
Right.
I mean I and I try to think about this in the like like movies, right?
Like Tom Cruise, right?
He spends I don't know six months making a movie he'll spend a year marketing it like Tom Cruise right like it doesn't matter how big you are because they know what's up right like if you but you know the hard thing is you think all the time is spent on the making and really it's that long tail of of uh of marketing.
So anyways I thought that was this good.
It's like yeah because it does feel a little icky to self-promote but it's like but if you don't self-promote like how how how does anyone know anything about you so
yeah I that's definitely been a problem in the open source community.
I think there's been a lot of resistance to people making money.
You know they feel like they should all be doing it for just the good of the projects but the these projects like Django wouldn't be around if there wasn't money to fund the initial seed of the project or the d the fellows to you know make sure they can kind of steward the project into better directions or the the companies who are submitting back the pull requests for bug fixes and security fixes because they needed them.
There's still money involved, and it's not a bad thing.
We shouldn't be upset about talking about that.
And we shouldn't be upset about marketing yourselves as develop as awesome developers out there.
But like Eric Mathis was um he's put putting out some more content, and he was like, he said on um Mastodon or Fostodon, whatever we call it, um I'm a bit shy about saying it.
It's like, no, Eric, we want to know.
We really like this.
Is this why we're here?
He does he does have a sub stack now.
I think it's mo mostly Python.
So right, but even even you know, even the the top Python book author um yeah feel feels that way.
So there's a lot of good people to emulate our model out there.
I mean, Simon is uh excellent.
I mean, at at sharing every idea and thought he's having in his head, and I love it.
I I want to hear more about the things he's doing, and he shares all the time.
His his talk at um that you gave at DjangoCon this year um was part of it.
It was only one small part of it, but was that the every commit needs to have like the documentation with it, and every project needs to have the blog post that goes with it.
And read
me front page, the whole entry into the project is really important.
And if and if you're not doing that bit, it's not done, right?
Was his kind of line.
And I I really like that.
It's like, yeah, okay, so I've got to write the docs here and I've got to actually tell people about it.
Well, um Jeff Bezos, Amazon's famous for his executives, like you kind of like write the press release first, and then you figure out how to do a new project.
So just that idea of like um yeah, working backwards, right?
As opposed to like, oh, let's just jump in and figure it out.
It's like, you know, of course, which is what we all kind of do, but it is helpful to be like, and how are you gonna describe it to someone?
You know, it's like, well, it's complicated, it's all it's like, and they're just like zoning out immediately, you know, versus you know, I think it is good guardrails for yourself.
Like what, you know, as we see like you know, squirrel, squirrel, squirrel of like interesting things we want to chase, like what what what's the guardrails that we impose on ourselves for a project?
It seems like there's been multiple attempts at like document-driven development.
Um, but I they just never really caught uh there's it's that's a hard leap to make to go directly from well, I'm gonna write the docs first, and then I'll end up in tests, and then that'll end up in the actual code that does it.
Yeah, doc test driven development.
Yeah.
That's pretty black belt level to be able to do that.
I've never I've never done it.
So I mean, well, so I I occasionally will um write the test first, but normally it's when I'm um I've got like a complicated algorithm or complicated process.
And I'd go, oh, if I just wrote that little bit, then that would be one step in it.
Okay, so I'll write a test for that one little bit, okay, and then I can write the bit, and then okay, I'll write a test for that bit.
And then and and in that circumstance, I'm writing test, I'm doing test-driven development, but very quite often it's the other way around.
It's like nah, blitz out some code, and now I'm gonna write some tests the other end.
Um same with docs.
Well, normally the docs are right now, I better write some docs.
Yeah, yeah.
Yeah.
Well, uh, Calvin, I wanted to ask you.
I was Carlton and I were also talking about um testing, in that I got a reader asked me a really interesting question, which was like, She's is there a canonical encyclopedic guide to Django tests?
Um, which I don't think I just I wonder like internally, do you have something like that?
Because it like, what is the point where it's like, okay, like yeah, you test your models, views, templates, URLs, but like for a beginner, it's hard to know like what's core Django, what's new, um, you know, where is that line where things become custom?
Um and I've you know, I don't I have some testing tutorials, but I don't have a great, you know, pie chart of like here's where you need to make sure you have cover you have coverage other than you know running coverage.
Um so I just curious internally, how do you think about that?
Because I'm like, yeah, I would love if that existed and we could all agree, you know, like here's here's the 8020, right?
Other than like when there's a new page, you should test, you know, test all the pieces of it.
But um
Yeah, right now that's really d driven internally by the developers' you know love of testing.
Uh it's gonna determine how good the output may be.
Um luckily on our side, we've got some great new developers who've joined the team recently that are very excited by you know test-driven development.
And so we do see more test coverage in our projects.
Um and prior to that, it was just you know, there's all new or people weren't excited about it.
But I think that it there has to be a culture.
Like you have to start bringing in folks who are who are excited, they'll give the demos, they'll you'll see the test you know coverage creep in or start happening.
And with CI pipelines, when you have a failure and you get a nice little email saying you you broke the build, uh, that that obviously is a nice peer peer pressure-driven development that encourages you to go fix and or add you know test coverage, because maybe you've got a rule that the coverage has to be X or that your commit can't go through.
Do you do you have the rule that whoever broke the build last is in responsible for running it, maintaining it?
We do.
I mean uh that but I keep seeing sometimes broken builds stay for a couple days.
I'm like, come on, what's going on here?
Let's get back in line.
Have to go have a conversation with a couple people.
I think if I was the begin thinking targeting for beginners, I'd say like have a test at least on the sort of main functionality of every bit.
Like, you know, check that your homepage loads or check that the login button actually submits or or something.
And then if you run that with CI, then if you break it, you know that you broke it and you're like, okay, I can.
And the other thing, the other, you know, 100% coverage, or that may be a bit too much to add for, but if you've got that kind of basic coverage over the core bits, it's like a smoke test that oh, actually, I broke something.
I think there's value in writing those what seem like silly, silly tests.
Like you're like, oh, this is obvious, this should always obviously work.
Well, if it should always obviously work, you might as well write the test for it so that when it obviously doesn't work, you'll know.
Yeah, yeah, yeah.
Yeah.
I I it it's hard when someone, you know, it again, this is what I spend my time with someone who's so new, like someone who was saying, okay, because I have tests in all my books, um, but like I can't write an entire book on Python while I'm writing a book on Django.
And they were like, okay, we're using setup test data.
Like, what's this class method?
It's like, okay, well, like, what are classes?
You know, and then why am I using CLS?
And it's like, oh, PEP 8, you know.
So it's it's this tension that I'm, you know, I enjoy this challenge of trying to be like, I want to explain things.
I don't want to have magic everywhere, but like, how deep do you want to go?
Like, sometimes just like just trust me on this.
This is a best practice.
And like, you know, here's some links if you want to knock yourself out.
But it is it is completely overwhelming because you're just taking it on faith.
It's like, oh, I copied these tests and it seems to work.
And I I kind of understand why, but like
you should just put a little footnote.
Go see Brian Aachen's book if you want to like dive in here, you know.
Yeah, yeah, yeah.
No, exactly.
Um, but you know, it there's a tension there between the kind of person who wants to understand everything, but also it's just turtles all the way down.
And so some I see that these people get really hung up, right?
And they had and sometimes it leads to like I'm just never gonna grasp all this.
It's like, you know, it it is fractal.
Like you do need to put limits on stuff and just be like, you know, have a list of like I'm gonna go learn those things.
Um, but you know, at the same time, like if if someone was, you know, someone could read the Python docs and like read about class methods, but there's no way they're gonna remember that until they need to use it.
So it it is kind of like you kind of need to use it to learn it, and then um, anyways, I have empathy for these things.
And even for me too, I'm kind of I'm like, oh, like, oh yeah, I'm like, I know we use that, like why do we use that?
Like PEP 8.
I was I was like, I was like, why the heck do we do this?
Do it this way?
It's like, oh yeah, it's a pep somewhere.
We have that same tension even internally on our team.
It's like we're a team of senior developers who are continually wanting to learn new things, but there's no point in going and learning some new technology piece of technology if you're not going to go apply it right away.
Yeah.
Because you you'll just have to if six months when that project does come around where that technology is actually warranted, you're gonna have to go brush up on it again anyway.
Um so uh a lot of our learning is really on the job hands-on when a project comes about.
Um, you kind of we we track in like a kind of a skills matrix or inventory of what people obviously what they're good at, but what they want to learn so that we can actually match them up with some projects where they would want to actually expand on the new skill set.
That's really wise because I've seen so many times a developer in a job who's a little bit bored start going it in experimenting with some new tech because they're a little bit bored.
And the way around that, of course, is to preempt it and know that they want to use that and assign them to the task.
So that's I think that's that's obviously a battle one learning.
Yeah, it's a free tip for the day.
Yeah, yeah, yeah.
Well, I think also um bugs like this is maybe less as a consultant, but more when you're in internally working on something, you just have this big long list of known bugs and figuring out how do you how do you deal with that?
Because you know, you can't just fix bugs all day and have perfect code because you're never gonna ship new features.
But on the other hand, if you never fix any bugs, developers are all gonna eventually leave and get frustrated.
So um I I've said this before, but I think one really nice way is to have like bug squashing days, you know, every month, every whatever, so that it puts the onus on the developer.
So it's like, okay, there's a hundred bugs, like you take ownership for deciding what are the 10 you're gonna handle.
And it's a way to kind of off um, you know, it's like a uh escape valve for like, yes, we are we are fixing these things, but not right now because we're doing something else, but it's not, you know, an indefinite like code is all crap.
If you if you look on our site over the years, we've done uh an activity internally called FedEx Day, it's now called Ship A Day, and actually it's kind of more recently morphed into what we're calling tech tech debt relief week, uh, where like one at least like the first week of January, everyone's kind of coming back from the new year and they've been off for like a week or two.
And we'll be like, we're not gonna do any customer work this week.
We're just gonna focus on tech debt relief or new process enhancement.
And so it it just kind of came about that that was a great way to give people that outlet to clean up the little messes that have been made.
You know, and sometimes we do it more than once a year, but usually once a year we spend a few days not on billable work, but actually fixing up and scratching those itches and coming up with new innovations and ways we you know can improve our workflow.
It feels so good as a developer.
I mean, it's hard to describe to someone who doesn't do this kind of thing, but it's it's like a cleanliness thing.
It's right like
but it's nothing worse.
I mean, uh for me, picking up an old code base, and and we thought we were doing best practices at the time, and this was maybe a couple years back, and looking at it and going, oh my gosh, I got so much to clean up here first before I can even be productive.
Like my it's like having a clean desk before kind of getting started on some creative work.
Uh it's hard when you like you just you just see little like issues here and there and there and there, it distracts you from solving the actual problem.
Yeah.
At least it's for me.
I assume most folks were like that.
One one analogy I've seen for this kind of environment, you know, this kind of discussion about tech debt versus shipping features is that you know, okay, if you just ship work on shipping features that in the short run you'll ship more features, but sort of velocity falls over time.
And you know, in the medium to long term, you're actually going slower because you didn't prioritize.
Would would you agree with that?
I would agree with that.
It's like the drag, the friction coefficient.
Yeah, or yeah.
Well, obviously, in the beginning of a pro a new product, there's a lot more new features to build too, right?
Because there's nothing if nothing exists.
I mean, we're we're experiencing that with the loud swarm platform that we host uh Python Web Conference on.
Is uh we actually pick it up in a couple times a year.
If folks are not busy on another project, they will get assigned to do some cool new stuff on Loudswarm, which is actually really fun.
Uh, that's been a great platform for us to experiment with new technologies, like a lot of the WebSockets work we've been doing, a lot of the Kubernetes you know advancements in our developer developer experience have all come out directly out of us innovating on the Loud Swarm platform.
That's cool.
I love Loudswarm because that you've hosted the Django cons for you know the whole of the COVID period and since as well.
But um I remember last time you came on, you were talking about Fargate and containers on Fargate, and now you're talking about Kubernetes.
So I see that.
We still use you can still use Fargate with Kubernetes.
If you're using EKS on Amazon and you don't feel like you don't know what your capacity is going to be or you want to scale closer to zero, it's possible actually to spin up compute in Fargate.
Uh Fargate works on ECS and EKS uh just as equally as well.
So you can actually define your pods and your your resources to pull from Fargate ad hoc serverless resources.
Sorry, a little plug there for Amazon Fargate.
But I I do find Fargate to be a great option when you just aren't sure how much resources you need, or you don't want to be maintaining the EC2 instances that would be hosting those resources.
Yeah, no, perfect.
Um to have a playground to work on it in is helps
a lot.
Uh and it brings people up to speed on like CIC pipelines and Terraform and configuring CloudFront and all the like caching pipeline, and you know, how do you split off WebSockets into the separate like pods of like resources that are servicing just those kinds of requests?
Like there was a a point came up last week or a couple weeks ago where people are asking, how did the front end get deployed?
Like the CI pipeline would run and it would deploy new Fargate containers for the back end, and there would magically be a new S3 bucket synchronized with the latest front-end changes, and people were like, we don't know where how those get there.
And so we had to go track it down, and it's actually kind of clever is that we actually had Fargate tasks that when the Fargate release would happen, obviously new task definitions would be generated.
Fargate picks those up and then replaces the old containers for Django, but at the same time it runs the Django migrations, it does the collect static, and then it synchronizes as a task that's then runs and stops all the front end of the front end of the S3 bucket.
So it means anytime you release a new release, you're sure the front end always matches the back end because they were tagged at the same time.
Yeah, lovely.
That's nice.
Lovely.
Um coming up on time, um, our previous guest was um Marius Felicia, and we were talking about Django 4.2 and 5.0.
Um so my question to you is are there new features you're looking forward to?
And like what's your current Django wish list if you just you know make it so?
What could Django add that would improve uh things?
I mean I think the the async story uh is is ever improving, and I think that's really important to Django being a viable player out there still.
I think a lot of people may see start to see Django as getting along in the tooth and being a uh still a synchronous web framework.
And obviously it's hard to kind of bolt that on, and we've had a we've taken a very measured approach to getting async capabilities into Django, and I think that's a that's a high priority.
I think that the the to make sure that Django and Python as a framework, Python as a language for people who are doing work in the web, it has to be async.
So 4.2 brings in um async support for streaming response, which is um if you if you pass it in async iterator and you're running under ASCII, you can you know do long polling or you know um service end events just recall Django.
Um I think that's kind of quite exciting.
Yeah, that's quite exciting.
And then with the Psycho PG3, um I was talking to Marish about this today.
I want he's like, I'm like, you've got to put this example together for me, Marish, where we use Psycho PG3's async client to listen to a notification that came either from a trigger or you know, uh a save event or whatever, and then tell a listening client from a streaming response that it needs to fetch the lady.
So that kind of real-time updates, all in native Django.
And then so that giving streaming responses, um making streaming responses async compatible, that's kind of like the outer limit, I think, in terms of features that will be in Django Core.
But now through 5.0, it's like, okay, can we flesh out the decorator support for async?
Can we, you know, just get async signals?
Can we, you know, flesh out some more stuff inside the ORM?
Can we, you know, these these richness of the async support now.
So over the next, over the 5.x cycle, it should mature, you know, continue to mature, and all those, all those gnarly bits will start to smooth out and give you that Django experience that you want, right?
Um for
people to pick up and actually be productive, they need that Django batteries included, you know, Pythonic way of of working.
Yeah, I think I can't remember who we were talking, it might have been Michael Kennedy, who was saying that um uh you know Python is a full stack language, and uh you know it's important for it to have async because you don't need you don't want to have to just jump to Rust or Go or whatever just because you need high throughput.
It's the same with Django, is that there'll always be specialist async frameworks that are you know more advanced, but you don't want to have to change your web framework just because you need a streaming view or just because you know you need that.
So it's coming on nicely, I think.
Well, and that's that's some of your post fellow um open source work is around async as well.
Yeah, so yeah, so I will I'm not leaving Django by any stretch of the imagination.
Um it's giving me a career, and I've given back to it for this period, but now I'm gonna step back to the back benches.
Um, but uh to continue, I'll continue maintaining the channels projects and have a bit more time for them in actual fact.
Um and I want to um continue working on the async stuff in in Django itself, and then you know there's things around the request um object in terms of modernizing that and bringing in JSON request passing that I want to add.
And then the really sort of next one is is to improve, is to refresh Django serialization story.
So this is something that I want to work on.
And um, well, Andrew Godwin just released his little um little API framework that's very fast API inspired that was in his um oh what's it called?
Uh the the Mastodon client that's called something the name escapes me.
But he's released this Hatchway project as a yeah um proof of concept there, and it's it's quite exciting because it takes Pydantic schemas and pulls them stra pulls the request straight into the request the request handler and then it will serialize back out for using Pydantic again.
That's that's where the future's got to be.
That's where it's like, okay, whether it's Pydantic or whether it's Atters or whether it's you know something else, that giving Django a better story or any fresh story there is something that I'm really excited about over the 5.
Speaking of Airflow, we should ask Andrew to uh come on because he he works he he works on airflow.
Um yeah, we'll have to get it back on.
You should, I agree.
Well, any is there anything um we we didn't cover Calvin?
I know No,
I think make sure you come to uh Python Web Conference.
You guys have there's a um a discount code that you all can share in the the the show notes for everybody.
Brilliant.
And I'll get you like a super 15% off.
Yeah.
Come come hang out with me for a week.
It's a lot of fun.
Yeah.
Oh we uh yeah.
But you don't have to watch all the videos live, right?
You can you can catch, you can buffer them.
Oh, so
they're they're available immediately after the talks, uh, which is a beautiful part of like the loud swarm platform is that you can watch any video that's happened already, uh like within 10 minutes of the talk.
You can also pause and go get a drink and come back and pause or come in late.
Or re-rewind and be like, what's that?
Well you can totally do that.
Uh that's that's one of the things I love.
I'm I didn't want to create this platform that just matched reality.
I wanted to you know emphasize the features of being a fully virtual platform.
And one of those is definitely like I missed the first five minutes of talk.
I'll just slide the slider back and watch the talk live from five minutes ago.
Yeah, perfect.
I just yesterday actually, I was doing something trying to explain async to someone, which is like rough because I don't fully understand async.
And I was looking at Carlton's talk again from DjangoCon, which I've seen twice, and I was like, oh God, like you know, so I was definitely rewinding and sliding.
So it's it's it's very necessary to have that.
Yeah, struggle is very real.
Um well, Calvin, thank you so much for coming on.
We'll have links to everything.
Um, Python WebConf, we'll have the discount codes.
Uh really, you know, I like this.
Every, you know, we we see you, you know, at DjangoCons in between, but to catch up on what's happened last year is really interesting.
So it's been always a great conversation.
Thanks for having me.
Thanks for coming on again, Calvin.
So DjangoChat.com, we are on uh Fostadon, and we'll see everyone next time.
Bye bye.
Bye bye.