Are you considering getting into web programming?
Choosing a web framework like Pyramid Flask or Django can be daunting.
It would be great to see them all build out the same application and compare the results side by side.
That's why when I heard what Nicholas Hunt Walker was up to, I had to have him on the podcast.
He and I chatted about four web frameworks compared.
He built a data-driven web app with Flask, Tornado, Pyramid, and Django,
and then put it all together in a presentation.
We're going to dive into that right now.
This is Talk Python to Me, episode 149, recorded January 30th, 2018.
Welcome to Talk Python to Me, a weekly podcast on Python, the language, the libraries, the ecosystem, and the personalities.
This is your host, Michael Kennedy.
Follow me on Twitter, where I'm @mkennedy.
Keep up with the show and listen to past episodes at talkpython.fm, and follow the show on Twitter via at Talk Python.
Talk Python to Me is partially supported by our training courses.
How does your team keep their Python skills sharp?
How do you make sure new hires get started fast and learn the Pythonic way?
If the answer is a series of boring videos that don't inspire or a subscription service you pay way too much for and use way too little, listen up.
At Talk Python Training, we have enterprise tiers for all of our courses.
Get just the one course you need for your team with full reporting and monitoring.
Or ditch that unused subscription for our course bundles, which include all the courses, and you pay about the same price as a subscription once.
For details, visit training. talkpython.fm/business or just email sales at talkpython.fm.
Nick, welcome to Talk Python.
Hey, thanks for having me.
Yeah, it's great to be here.
It was really nice to meet you last week at PyCascades.
That was a fun conference.
Oh, man, that was awesome.
That was my second Python conference ever, and it was on par for me with PyCon.
Yeah, it was definitely a different vibe.
It wasn't like a huge expo hall or things like that, but I felt it made up for it in the richness of conversations.
You could sit and talk with three or four people, and those people were amazing.
Right, and the one thing that's been different is I've done a lot of academic conferences.
I used to do astronomy, so I've been to a few national conferences, and I've always missed out on talks.
And this is the first conference that I've gone to where I had the actual opportunity to sit and hear every talk.
I didn't feel like I missed out on anything.
Yeah, and the talks were really good.
So congrats to everyone.
That's a new conference, and you missed it this year, but it's coming to Seattle next year and then Portland the year after.
And it's supposed to kind of go up and down the Cascades and the West Coast of the U.S., the mountain range.
So it should be a lot of fun.
I'm looking forward to going next year already.
But that's not what we're here to talk about exactly, although we are going to cover a talk that you gave there, which sort of surveys a bunch of the popular web frameworks.
And we'll get into that.
So let's start with your story.
How did you get into programming in Python?
Sure.
I actually didn't think I'd ever be programming, ever.
I started doing astronomy back in about 2007.
I just got really interested in how stars lived and died.
And so I started doing astronomy.
I started doing science.
It seems like one of the most amazing parts of all science is astronomy these days.
Yeah.
I mean, there's a lot going on in astronomy.
A lot of my former colleagues are doing some amazing work finding planets, learning about black holes that we didn't know existed, all kinds of great things.
When I started doing astronomy, I naively thought that I would just be looking through telescopes and taking down notes and thinking through equations and that kind of thing.
I didn't think I'd be writing any programs at all.
And so when I got into grad school, even before I got into grad school, I had to learn how to program a little bit.
And I used Fortran 77.
And that was, I hated it.
I hated it.
I did, too.
I had to take it.
I was in engineering at first.
And they told me, I said, can I please take C++?
They said, no, you have to take Fortran.
It's the most important language you'll ever learn.
I'm like, no.
Well, it's one of those things where, like, when you're in academia and you're an undergrad or you're in grad school, you learn the language that your advisor knows.
And my advisor knew Fortran, so I learned Fortran.
And then when I went, that was at Columbia.
I was in the Bridge to the PhD program there.
It's a great program for the scientists.
And when I transferred into a graduate program at the University of Washington, then my advisor was using a language called IDL.
I forget what it even stands for, but it's a proprietary language.
So you have to have a license on your computer to use it.
And if you wanted to be able to, like, do work at home, you have to have a license on your home computer to use it.
And so it's a whole lot of stuff with that.
You have to be connected to the internet so they can verify your license.
Oh, it's that intense?
It has, like, almost like a dongle type thing?
No, it's not a dongle.
It's more like if you're not connected to the internet, then you can't use the IDL editor.
Wow, that's intense.
And you can't run your IDL program.
That's kind of the opposite of it.
Which sucks.
Yeah, it's terrible.
Exactly, exactly.
And so I actually learned Python partially to get away from IDL.
It was kind of my way out.
I was like, I had been introduced to this language, and I was like, oh, this is a free thing.
I don't have to have a separate license to do this.
I can install it on any machine.
It looks like English.
Like, this is...
Yeah, yeah.
Why not?
Yeah, absolutely.
So I used Python for my research.
I used Python for my homework.
And then one of my colleagues at the time, like, and this is kind of where it really took off for me.
He had been doing blog posts about science.
And I was like, oh, that sounds cool.
I should do that too.
And I used Python to help me learn more about the science that I was doing.
And I was using the science to help me learn more about the Python that I was writing.
And so I kind of got a lot of that practice, you know, after hours, just using Python to answer interesting questions.
Yeah, that sounds really cool.
It's a very organic story of just like, I kind of just found my way into it.
And I just, you know, I sort of grew as you played with it.
That's awesome.
So like I said, I'm a big fan of astronomy.
Are you still doing that today?
You're not, right?
You're sort of...
I'm not.
You took the path that I did.
Like, let me work on a PhD and actually do nothing and just go programming with it later.
Now I just feel bad.
But yeah.
No, I know I do too.
I kind of looked at my advisors and stuff when I left.
I'm like, yeah, I'm sorry, but I'm going.
It was tough, actually.
But I think it's totally the right choice for me.
I don't know about you.
Yeah, it was time.
I wouldn't make a second choice in a second.
You know, I met some great people there, but I'm much happier doing what I'm doing now.
Yeah.
I feel like the PC experience in all of grad school kind of taught me how to do what I do now.
But I feel like I'm applying it in a place that makes a bigger difference for more people.
Right.
I'm still doing as much reading as I was doing during my PhD program.
I'm still doing as much thinking, but it's toward...
So one of the problems that I had with the work that I was doing in my PhD program was
it was not very easy to explain to other people why it was interesting or important.
I knew why it was interesting or important.
I love like aged stars and seeing how like what was happening as they were dying.
But in order to explain that, I've got to explain, okay, look, this is how stars evolve.
This is what all this stuff means.
I've got to apply all this background.
Whereas, you know, what I'm doing right now, I'm teaching at Code Fellows.
And I can just say, you know, I'm teaching people how to program, you know, teaching people how to make websites.
So, you know, the kind of stuff you see like a Google.com or anything.com, I'm teaching people to do that, at least at the basic level so they can go out into the real world and get a job and do that stuff for real.
Yeah.
And it's a great experience to help people sort of change careers or advance their career down some other path they weren't doing before.
So what is a typical day?
So Code Fellows is a boot camp for those who don't know, right?
And what's a typical day there look like?
Yeah.
Code Fellows is one of the coding schools in Seattle.
I'm a little biased.
I think it's one of the best ones.
But I also work here and I know some really good people.
But a typical day when I'm teaching looks like three hours of lecture.
Let's say I'm teaching one of my Python lectures.
It's like, okay, we do about an hour of code review.
And then we talk about some topics.
We do some data structures.
We do some algorithms practice.
I'll teach you about a web framework or some aspects of a web framework, like what a model is or what a view is or how to do routing or security, that kind of thing.
And then we go to lunch.
And afterward, they come back and they work with each other on lab assignments.
And we build the lab assignments to complement the lectures.
And so I teach a thing.
And then they use that concept in their application.
And after that point in time, they're kind of on their own.
They're still on location.
But they're on their own building the projects.
And myself and the TAs are here to grade their assignments and to be resources when they need help.
Yeah, that sounds like a really fun job.
And how long does the boot camp run for?
The full sequence.
So there's three levels to it.
201, 301, and 401.
201 is four weeks.
And that's the basics of HTML, CSS, and JavaScript.
And then the 301 is also four weeks.
Because you have to do that.
There's no way to avoid JavaScript.
Right.
Like there's no way to avoid it.
That is the language of the web.
Let's be honest here.
Yep.
It is.
So 301 is also four weeks.
That's more intermediate.
HTML, CSS, and JavaScript.
We talk about jQuery.
We talk about more libraries.
We kind of get people kind of more interested in the wider scope of being a web developer.
We start dipping into the back end a little bit with Express, but not too much.
And then in the 401, that's 10 weeks.
We have several 401s.
We have Python.
We have JavaScript.
We have Java.
We have C#.net.
And that's 10 weeks.
For the Python class, that's basics of Python, a preliminary web framework like Pyramid,
and then a more advanced web framework like Django.
This is actually where my talk came from because I've been teaching this course or at least
being a part of the teaching process in some way, shape, or form for the last almost two
years and having all this exposure to it.
And I was like, huh, I wonder what these other frameworks look like because I'd only ever
taught.
I'd never actually learned Python for web development in my graduate work.
I was doing astronomy.
I was doing data analysis.
I only learned how to do this stuff on the job.
They don't have web frameworks for machine learning across.
You don't build web apps, right?
You do build other stuff.
Yeah, it's all custom software.
Yeah, exactly.
I'd never actually used Python for web development.
So I only learned this stuff when I was on the job.
And so I'd only been exposed to Pyramid and Django.
I did a little bit of Flask just kind of as a one-off thing, but I didn't really understand
what I was doing.
So I didn't really take the time to get to dig into these web frameworks.
I was like, okay, I wonder what these other ones are like.
I should try to talk about that because I'm sure I'm not the only one who thinks this.
No, I think it's a super interesting idea because a lot of times what I find is people,
they kind of do a quick survey.
They're like, all right, what's out there?
Django.
Okay, there's a lot of building blocks already built.
They're kind of big.
And I like, okay, well, there's a micro frameworks and they're really small.
I put pieces together.
This one or that one is mine.
That's my style.
I'm going to do it.
And then they kind of just stop, right?
You learn what you need to know to do the job you try to do.
Yeah.
And most people aren't doing, unless you're a contractor, you're not doing a new project
every three months.
In a different framework.
Right.
In a different framework or a different language entirely.
You have your job.
You might jump around from company to company, but you still like, most places are hiring for
Django, so you learn Django.
Or they're hiring for Flask, so you learn Flask.
Or you're just building tools for the backend.
But yeah, in my 10-week class, it's all that plus data structures and algorithms and a little
smattering of machine learning.
So it's like end to end with the week breaking between each class, it's about 20 weeks total.
Wow.
It sounds really fun.
It's something like I could actually kind of enjoy hanging out there and just being part
of that.
That sounds fun.
It's great.
It's super intense.
And honestly, now that I've taught it, I really wish that I had learned to program this way.
It's really directed.
When you go through undergrad and you get your degree, you've got to do a lot of ancillary
stuff, which is great for building a well-rounded person.
But if you're focused on just wanting to do one thing, it tends to get distracting.
Whereas with this, the goal is clear.
We want you to get a job.
So we're going to train you to be able to do the things that jobs are asking you to do.
And that's it.
There's no humanities requirements.
There's no other paths here.
It's just like you're here for a specific reason.
If your cause doesn't fit that reason, then you want to go somewhere else.
But it's directed.
It's focused.
And it's cheaper than an undergraduate degree by far.
Yeah.
By quite a bit.
Yeah.
And time and money.
That's cool.
I mean, I'm a huge fan of the liberal arts education.
I feel like it's good to be a well-rounded person.
But I'm not entirely sure how much college should drive career training.
You know, more like be a good person in society and be well-informed.
Now go learn the thing, right?
Yeah.
And I mean, it's also good for networking.
It's good for, you know, expanding your interests beyond whatever you learned in high school.
But, you know, most of the people that we get are people who are changing jobs, not people fresh out of high school.
I've had a few people who are fresh out of high school, but most folks have gone through, you know, they might have an undergraduate degree.
I've even had a few people with CS degrees, but they've had a job before.
They want to do a different job.
They don't need all the ancillary stuff.
They just want to know how to do a new job, which is fine.
And we teach them how to do that.
Yeah.
That's cool.
That's excellent.
Yeah.
So let's talk about your, the four frameworks that you chose and maybe even start with just because with the app, because your idea was, I'm going to build the same app in four different frameworks.
Right.
So what's that?
Yeah.
So the app itself, I tried to keep it as simple as possible while still displaying, you know, the aspects of what a web.
A framework should handle.
And so I chose a to do list, which is, you know, everyone knows a to do list.
So there's not much that needs to be explained in that way.
So when I get to talk, it's like, Hey, you know what a to do list is.
This app does that.
You know, with this, with this application, you can, you can add new users through registration.
You can log in, log out.
You can add new tasks, edit existing ones or complete existing ones.
You can even delete them if you want to.
And so that's just kind of the backdrop for investigating how these four frameworks work.
Yeah.
That sounds pretty simple, but actually it touches on a lot of stuff.
You've got a data access layer.
You've got a database.
You've got forms because you've got to post back information to register.
You've got like secure user management.
There's a lot of stuff actually going on there.
Oh, absolutely.
And I didn't, I didn't get to go into all of it in my talk.
I didn't even get to finish writing all the code just because time got away from me, but
it's not just, I'm going to send some data somewhere and it gets handled.
It's okay.
How exactly is it being handled?
What exactly am I handling?
And how is every web framework supposed to be doing it?
And so when I originally wrote this talk, it was looking at each aspect of a web framework
across all four.
And then I revised it to look at each web framework one at a time, doing all the things that's,
that the app requires.
So I started with Flask and the setup and installation and then getting things up and running
configuration and then how to make a view.
So like a view is just a function that handles a request.
So an incoming HTTP request and sends back a properly formatted response.
And the benefit of web frameworks, and this is definitely something that my students learn
because I have them build a web server from scratch as part of the course, is that you
don't have to worry about a lot of the stuff that goes into building a response or parsing
an existing request.
There's so many different ways that an incoming request can go wrong.
And you don't have to think through all that logic.
You want to think more about how your app is supposed to work.
Right.
You could open a socket and just go to town on that thing.
Right.
But right.
You know, splitting strings and using regex to find different parts of the request headers
and all that stuff.
But who wants, no one wants to do all that.
No, no, no.
Something that's already pre-built.
And you know, people smarter than myself have done it.
So why should I do it myself?
Exactly.
And there's people actively working on it.
So the four frameworks you chose, you chose Flask.
And then Tornado, I thought, was an interesting option.
Yeah.
I had heard about Tornado.
And I didn't have any idea what it looked like, what it would do.
But I heard the word async.
And I was like, that should be useful.
That sounds fun.
Yeah.
That sounds really fun.
That's cool.
So yeah, I'll dig into it.
Yeah.
And you've got Pyramid and Django.
So those are the four.
And let's, I guess, start with Flask.
It's on the smallish side, right?
It doesn't bring a lot to the table.
It's one of these micro frameworks.
But for your example, you still use Flask, Flask SQLAlchemy, and Flask HTTP Auth, right?
Right.
And I have to have those external packages because Flask really is the barest bones.
Where a framework, it's just, you know, you can make a function that handles requests
and returns a response.
And that's all that Flask does on its own.
Yeah, pretty much.
And so if you want to talk to a database, or if you want to do any sort of authentication,
you've got to use something else or write your own.
Yeah.
So like Flask, and there's benefits and drawbacks to each of those.
So like if you want to use a database like a MongoDB database, you download the package
that someone has written to use Flask MongoDB.
Or you can even just write, you know, straight up queries on your own without using a go-between.
And then that'll work.
Right.
Just write a couple lines of code and like sort of piece it together yourself.
Right.
And that's something you can do, especially if you only need a very small application.
Flask is the way to go.
Once you want to start doing more of the classical CRUD application, CRUD being create, read, update,
and delete functions, you're going to start wanting to move away from Flask.
Just because it can still do those things, but it becomes harder.
Yeah, you do more of the legwork yourself.
Yeah.
So maybe let's go through, like, we'll kind of go through the same section for each framework.
For Flask, let's talk about like, how do you like connect to the database and sort of incorporate that?
Sure.
So I'm a fan of the 12-factor application.
Give us the quick summary on what 12-factor app is, if you can.
Sure.
And the way that I'm trying to connect to it here is that one of the parts that's important is having your code not change between development production.
Instead, be dependent on your environment and the variables that are set in your environment.
So my application should have the same code running, whether it's on my own machine or on Heroku or on AWS.
All that I'm changing are some flags, like, you know, am I in debug or not?
Is my database a local database or is it a remote database?
And so one of the ways that I do that is I use an environment variable.
I call it database URL just because I use that everywhere.
That's used in several places.
One of the places it's used is Heroku, so it makes it very easy for that.
So I use an environment variable called database URL to point to my database's URL.
And then I use an environment variable called Flask Gap to point to the directory of my Flask Gap.
And then I put all my working code in the location of my Flask Gap, that app.py file.
Right.
Yes, you just have the app.py.
And basically, you could just use Flask.sqlalchemy.
And what is that like?
Is that integrated?
It creates a sort of a base model, right?
If you do SQLAlchemy on its own, you've got to create the declarative base and do all of that stuff.
And so the Flask SQLAlchemy kind of does a little bit of that work for you, right?
Yeah, Flask SQLAlchemy takes care of a lot of that work for you.
It just gives you this model object that you use.
That includes the declarative base and all the SQLAlchemy machinery.
But just lets you focus on building the actual objects that you want to insert into your database.
And it also does a nice thing for you where it includes a method.
No, I guess it's not a method.
It's an attribute on the model object that you create that will talk to the database for you.
So you can query for one object by just saying, you know, object name.query.all.
And that gives you all the instances of that object in your database.
Oh, yeah.
That's really cool.
Because otherwise, you have to, like, create a session and then use the session to create the query.
Right.
Yeah, so it's kind of like a convenience wrapper around the SQLAlchemy stuff.
But for the models and everything, you just define them the same, more or less.
Right.
You set up columns by declaring columns.
Yeah, it's really easy.
You set up columns by declaring columns.
If you want a primary key field, you say, this column is going to have a primary key.
And it's going to be true.
Like, the primary key flag is true.
If you want to set up an explicit table name, you have a table name attribute that you set in your class.
Any other behavior you want to have.
You know, it's still a class in Python.
So you can still add whatever methods you want to do special things.
Right, right.
I find I don't do that often, but a little bit.
There's sometimes there's just, like, a few things you want to compute in Python related to that entity.
And you're just like, oh, it just needs, like, a property or something here.
And it'll be perfect.
Exactly.
And one of the things that I use that for was, so in my models, I have two models.
I have a task model, which is the actual, like, to-do list task.
And then I have a profile model, which is the user who has the tasks.
And one of the things I wanted to do was when you register a user, automatically give them, like, they joined.
And then also automatically give them, like, a secret token that you can use to log in and log out with.
And that's not handled by SQLAlchemy.
And so in the init method, I just say, you know, do whatever you were going to do in your init method, but also set these properties on the class.
Yeah, I really like that.
This portion of Talk Python to me is brought to you by Linode.
Are you looking for bulletproof hosting that's fast, simple, and incredibly affordable?
Look past that bookstore and check out Linode at talkpython.fm/Linode.
That's L-I-N-O-D-E.
Plans start at just $5 a month for a dedicated server with a gig of RAM.
They have 10 data centers across the globe.
So no matter where you are, there's a data center near you.
Whether you want to run your Python web app, host a private Git server, or file server, you'll get native SSDs on all the machines,
a newly upgraded 200 gigabit network, 24-7 friendly support, even on holidays, and a seven-day money-back guarantee.
Do you need a little help with your infrastructure?
They even offer professional services to help you get started with architecture, migrations, and more.
Get a dedicated server for free for the next four months.
Just visit talkpython.fm/Linode.
So then also the Flask SQLAlchemy comes with sort of a create all function that would be the, you go get the metadata and then do that on the base, right?
There's like a little bit of a nice utility method there.
Then when you talk, you talk about views.
So in Flask, views are basically functions with a decorator.
And they're super simple, right?
Yeah, and that decorator, yeah, absolutely.
That decorator is the app.route.
So like your Flask app is the app object.
And everything goes through there, including the routing.
And you decorate every function that you want to be a view with app.route.
And you pass as an argument to that decorator the actual route that's going to connect to this view.
So let's say I want to have a home route.
I say slash home is that route.
For my decorator, I say, you know, the app symbol, app.route, and then slash home for my route.
And then directly underneath that, the function is going to be whatever handles that route.
So when the home route is accessed, that function will run kind of like a callback in JavaScript.
Yeah, the other thing that's interesting about Flask, I think, is this global request object that's kind of always there, right?
That was one of the weirder aspects of Flask.
I'd never encountered that before using Flask.
Because typically, like with other web frameworks, the request object is populated.
It's a parameter.
Just as a local variable.
Yeah.
It's a parameter in a function or a method in a class.
But it's just populated for that one instance.
And it's only usable by that one function unless you pass it somewhere else.
With Flask, the request object is a global variable.
It is the incoming request.
And it's usable not just by your view function, but any function or anything that you have in that file, that script file.
You can use it to do whatever you want to.
So you can set up, you know, background tasks if you want to use that request object without any actual reference to your view.
Yeah, and that's kind of funky.
But it also makes it pretty easy.
I had the guys that did Quart.
The guy who did Quart on, and Quart is an asyncified version of Flask.
And this type of stuff was one of the things that made making it async really challenging.
Because how do you control when the request thing points at the right one?
And then you release the thread, another one runs.
It's like, it gets a little tricky.
Yeah, I have no idea how that would work, honestly.
It took some crazy monkey patching, as from what I understand.
Good God.
I mean, it's certainly possible, and I'm sure there's use cases for it.
But I can't imagine the mess that must be under the hood when you're trying to do that.
Yeah, it gets interesting.
Yeah.
All right, speaking of interesting, the one that is the most out there of the four that you chose, I think, is Tornado.
And I'll just read the quick summary for Tornado that they put on their website, like the paragraph.
So Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed, which is like some interesting early social media, for a non-blocking network I.O., right?
So it scales to tens of thousands of open connections and makes it ideal for long polling, WebSockets, and so on.
So if what you're doing is waiting on stuff, I'm calling web services, I'm calling database things, and I want to not block up my web tier when that happens, like Tornado is pretty cool.
There's other options that are more modern, but this is like a really popular one.
Yeah, definitely.
Yeah, Tornado is useful for if you want to have a long-lived connection or if you want to do anything that requires some long-running input-output.
This particular use case, this to-do list, is not the best place for Tornado to be used.
It's still like you don't need to do async stuff with Tornado.
You can use it just like a Flask or like a Django.
It'll work the exact same way.
It just handles requests and sends back responses.
But if you do have a long-running task like a database query that's going to take a while to aggregate some data or maybe you need to send a request to somewhere else,
you can set up your views as coroutines that'll run in their own time and still free up the web service to handle other requests or do other operations.
And it's really cool that way, and it's actually fairly simplified, where all you really need to do is know exactly which part of your code you want to, or which will be long-running.
You set that up as being what's called a future object, something that's going to be running in the future, and set up the method as being a coroutine.
Tornado will handle all the rest.
You don't have to worry about the event loop.
You don't have to worry about any of, well, most of the other asynchronous issues.
It's just, it's done for you.
Yeah.
And so you're using SQLAlchemy here as well.
And what gets interesting is SQLAlchemy itself is not async-enabled, coroutine-enabled, or things like that, right?
So you have tornado-SQLAlchemy, which lets you do that, right?
Mm-hmm.
And the way that it does it is by setting up a context object where, so in that context, you have access to this session.
And then whatever you would do with that session gets handed off as a task to your async event loop.
And so you hand it off to the event loop.
Your event loop continues to run.
And you're not necessarily waiting for that process to finish before you handle your next request.
It's just that when that process does finish, and the event loop is aware of that, then that response to that specific user is sent back as it needs to be sent back.
The thing that it's not doing for you is, like, if you have some long-running computation, that's not going to be handled by a tornado.
It's really just for input-output from some external service or from, like, clients.
Right, exactly.
You've got to have one of those things to make a future and wait upon it, right?
And if that's just compute, it's just going to block up the same thread anyway, so.
That's an interesting thing.
Like, I was never actually trained in understanding async.
And so...
It's pretty mind-bending the more you dig into it.
Yeah, it really is.
It really is.
It was interesting.
And this goes back to PyCascades, where, like, I had kind of, like, dipped my toes into it with Tornado, but I was like, oh, I don't really know that much.
I know I can decorate this method with a coroutine.
It'll make it a coroutine.
And then I got the privilege of being able to sit next to Guido during the speaker's dinner after the first night.
And he talked to me for a while about, like, how async works.
And I still didn't quite fully grasp it.
But it was really interesting in how Python is still being a single-threaded process, but it's handing off tasks to be working in the background.
And then I tweeted about, like, okay, I'm really going to be serious about learning about this async stuff.
And he tweeted back at me, and he was like, hey, you want to check out this book?
And it's been great thus far.
I've been reading.
I've read through it about this.
This is one chapter in this book about twice now.
I'd say my understanding is at about 25% level.
That's awesome.
What was the book you recommended?
It was...
Let's see if I can put...
I don't have it on this machine.
Do I?
Let's see.
I'm going to look for it.
And if I find it, I'll send it to you.
Yeah, we'll put it in the show notes or something like that.
Yeah, sure.
Absolutely.
But it's an open source book about...
It's very sharp.
It's about the architecture of software.
Oh, is it the one where they build all these different things and 500 lines of code or less?
Yes, that's what it was.
Is it the article of Jesse Davis and Guido's article, maybe?
Yes, that is the exact one.
Yeah, that's a good one.
That is a really good one.
A web crawler with asyncio coroutines.
And it actually builds up what a coroutine is from ground level.
It starts with your blocking sockets.
And then it's still sockets, but non-blocking sockets.
And then it goes to an actual web crawler using coroutines.
And it's pretty awesome.
Yeah, that's a really cool one.
And I love the 500 lines or less aspect of it.
That's pretty cool.
Yeah, and for being 500 lines or less for such a complex topic, they do a really good job of explaining what async is and how it's supposed to work in the context of Python.
Yeah, yeah, that's really cool.
All right, so we've got these async coroutine view methods.
Are they methods or are they classes in Tornado?
I can't remember.
So the views themselves are classes.
And you connect the views to routes in Tornado's central application object.
You can have multiple applications running at the same time, which goes back to that event loop thing.
You can have in your one Tornado project four or five applications running at the same time, doing and handling different things if you want to.
But the actual method that gets run depends on what kind of requests you come in.
So you know that you have several types of HTTP requests.
You can get, post, put, delete.
Those are the main ones.
There's other like hen, option, whatever, but normally you should use those.
And then there are corresponding methods for those.
So when an incoming get request comes in, whatever code that I've written for the get method will get run for that request.
And the response is built from that request, from that method, and sent back to the client.
Yeah, that sounds really cool.
So the sort of fundamental building block in Flask is you have a decorated function.
The fundamental building block here is I have a class.
One URL points at it, but it can have different methods for the various HTTP verbs.
So it's a little restful in that sense.
It's a little restful in that sense.
It works really well for a restful API.
And the benefit of having it be a class is that you can set some instance attributes to only run for that one class, for that one type of request.
You can think of them as, you know, semi-global things that only apply to that class.
And you can have other methods in that class that work just for that class and whatever you want to do with those methods for those specific kinds of requests.
For those methods, in this particular case, the to-do list, I add some methods to some base request handler for constructing responses, for setting default headers, for converting incoming data from post requests into Unicode, because they come in as byte code instead.
Sorry, byte strains instead.
That's really simple.
It's just a method of the class.
Yeah, that's cool.
I find that that's a really nice design pattern, because there's probably like five or ten things like every web method wants access to.
And if you put that in a base class and bundle it up, that's sweet.
And that was very simple to do.
Yeah, cool.
And then for the SQLAlchemy, even though it's the Tornado SQLAlchemy, you still basically define it exactly the same, right?
The declarative base and all that?
It is almost the exact same thing as Flask.
In fact, when I first written this project, I wrote it in Pyramid.
And then when I was going through Tornado, I was like, oh, I can just copy and paste everything I wrote for Pyramid into Tornado and copy and paste everything I wrote for Pyramid into Flask, because it's all SQLAlchemy under the hood.
And that's one of the things I like.
If you have an ORM or like I use Mongo a lot, so an ODM that you really like, they kind of are portable, right?
You learn the data part.
It's almost like the 12-factor app idea that you were talking about.
Like, you understand this part of your architecture independent of the framework, right?
Like the pieces, you put them together.
They're not like locked.
And they're not like the one in the same, unlike, say, Django, which we'll get to in a second, right?
Right, right.
Yeah, that's the benefit of using things like Pyramid or Flask or Tornado.
And they're similar in the way that there is some basic framework, but all the rest is just building.
It's just Legos.
Yeah.
It's all the same stuff.
Nice.
So let's move on to Pyramid.
I think Pyramid lives somewhere in between Flask and Django, maybe a little closer to the Flask world.
But I really like their philosophy.
They're the start small, finish big, stay finished framework.
And they say their philosophy is it should be very quick and easy for you to learn to start with a web framework.
But the stuff that you need as it grows more complex is just there.
And so that's kind of a nice philosophy, I think.
One of the things that was nice about Pyramid is that I use the cookie cutter template for building a Pyramid application where cookie cutter is a separate Python package that you download and then you point out a repository to copy over some files for you to build your application.
There are cookie cutter templates for Flask, Tornado, and even Django.
I didn't know how to use those as well as I knew for Pyramid.
So I just used the one for Pyramid.
Yeah.
It's the official way to get started with Pyramid where the others you theoretically could use cookie cutter, but it's like there's some other sort of official starting point.
Yeah.
Actually.
So it's interesting that you say that because when I first started teaching Pyramid almost two years ago, cookie cutter was not the way to do it.
It was.
I was using Pyramid 1.8.
Yeah.
It was pcreate.
Like when you install Pyramid, it installs for you a command.
It's actually still there in the current version of Pyramid.
Yeah.
If you still want to use it.
I think it delegates to cookie.
It just is a wrapper around the cookie cutter now, I think.
Oh, is it?
I haven't actually looked at it.
I think so.
I'm not entirely sure either.
That makes sense.
Okay, cool.
But yeah, like the pcreate command would say, okay, you want to create a pyramid application.
You want to do certain things.
There are various templates you can use.
The basic pyramid template says, okay, you have some main function, which is your main configuration.
Maybe you want to hook up some views.
Maybe you want to hook up some routes.
Whatever.
We got you.
With the SQLAlchemy cookie cutter template, it says, oh, you want a database?
Well, instead of having you write your own, because we know you don't know what you're doing,
we're going to give you a script for initializing your database.
Here it is.
It's called initializeDB.
It does exactly what you think it's supposed to do.
Without you worrying about the actual implementation details.
One of the things that I wish they had was an Alembic template.
Maybe they have one now.
I haven't checked in a few months.
But that'd be cool, too, because one of the things that's hard to teach what I'm doing
pyramid is, you know, you can actually, if you know how to use Alembic, you can set up
these things called migrations, which are snapshots of your model as you change it over time.
And that's a lot easier and better for production than just destroying it all and rebuilding it
from scratch every single time you want to make a change.
Yeah.
The migrations are where that get tricky.
And so the fact that if that were built in, that would be sweet, right?
Yeah.
And I'm sure that at this point in time, someone's done it.
I just haven't looked.
Maybe.
I mean, one of the things that you could do for your courses is you could take one of
these cookie cutter templates and make one that's like a little more focused on what
you guys are trying to end up with the end goal.
Like I have my Python for entrepreneurs course, which has just a crazy amount of different
things brought into it, like bootstrap set up in a certain way and all sorts of templates.
And so I actually created a cookie cutter template that is the, like, if you wanted to take what
we built through the 20 hour course and start a new project from it, you would just run that
new cookie cutter template and like you would start basically the end of the course.
Yeah.
That's awesome.
Yeah.
It's really fun.
So that's a great idea.
Yeah.
It's really like you teaching the same thing.
It's similar things you could like, you could help yourself by like,
tweaking one of these and forking it.
Yeah.
That might be a thing that I'd do in the future.
I have been trying, like, as I've modified the course.
So it's worth noting that I didn't, I wasn't the one who created the course.
The course was created by this awesome guy, Chris Ewing, great developer, great friend,
extremely smart.
And he created the course with Pyramid in there.
He had done Flask before, but he decided to go with Pyramid instead as just kind of a more
basic framework that could do a lot.
And his idea was to not have the things that they learned be too heavily tied to just the
course that we teach.
Because when they get out in the real world, they need to be able to understand what's happening
and not just fall back only onto what we taught, but be able to build up from scratch whatever
they need to build up for whatever job they have.
The benefit of using someone else's cookie cutter template is that someone else has done
it.
It's more likely to be used widely if someone's building a project and they can kind of just
get direct, they can feed directly into that pipeline.
But I think now that you mentioned it, I'm going to, I'm going to see if there's an Alumbic
template out there for Pyramid.
And if there isn't one, I might actually try to write one.
Yeah, it'd be really cool.
It would be useful.
Yeah.
I don't mean to derail you, but I do find this, these cookie cutters are really interesting
to roll with.
So this is how you get started in Pyramid.
And let's say the terms of views, the default fundamental building block is very much like
Flask, right?
Oh yeah.
It's just a function with a decorator.
The difference between Pyramid and Flask is that your decorator, so your routes in Pyramid
are separate from your views.
They are just a listing of routes in, you can put them in a separate file, you can put them
in your main configuration directly, and they have a name.
So like, again, the home route, it would be called home, and then the actual pattern that's
supposed to be matched to go to that route.
And then your view has this view config decorator where you say, okay, here's the name of the
route that I want you to connect to.
Here's also the way in which I want you to render the response of this view.
You can have, there's several options.
One of those is JSON, so I can take my response, like if I pass a dictionary to my return value,
then my response will just be a dictionary, and that's JSON serializable.
Or I can make it, I can use a template like a Jinja template or a Chameleon template or any
other template system that I want to, and just pass my response to that template, and Pyramid
will build a response for me and send it back to the client.
You can also go with the Tornado style and create these like handler classes that get
one URL.
You can, or they're called view classes, I think.
You create handler classes.
There's like a whole bunch of different ways.
And I think that's one of the challenges of Pyramid.
It's the framework I like most.
My web apps are built in it.
But I do feel like there's all these different ways to do the same thing.
So I'm never like, am I doing it the best way?
Or I'm just doing it the way that I know?
You know what I mean?
There's always a better way.
It's more a matter of, my students often come to me with the question of like, is this best
practice?
Is what I'm doing best practice?
And my response is always, well, best practice is oftentimes just defined by the person who's
paying you.
What do they want?
It's a trade-off too, right?
If I'm building Google, I'm making different trade-offs than if I'm building a small hotel's
website.
A best practice for Google is wasting money for the hotel and vice versa.
The point there is that it always comes down to your use case, right?
If your use case would be better served by using class-based views and having the mix-in
pattern that Django has, then that's your best practice.
But if your use case is better served by a function, then use the function and be okay
with it.
As long as the thing works.
That's what matters more, is that the thing that you're building works.
And then you can optimize as you need to for your specific use case.
Yeah, for sure.
All right, so you brought up Django.
Let's move on to Django.
So the summary there is it's a high-level Python web framework, and it encourages rapid development
and pragmatic design.
So it comes with lots of pre-built stuff, and the building blocks are kind of large.
They're more like Duplo rather than Lego building blocks.
I like to think of them as, right?
Exactly.
I would even say they're more like, if you know Power Rangers, where the robots come together
to make one larger robot.
There's still machinery in the individual robots, but their job is not to be inspected individually.
Their job is to make one larger conglomerate.
Yeah, yeah.
One of the things that Django doesn't say in their description is that it is extremely opinionated
about the way that things should be done.
And so, yes, there are function-based views in Django.
There's also class-based views in Django.
There's the ability to talk to a database in Django, but the database you're talking to should
probably be a SQL database.
And the way that you build models in Django, at least through the tutorials and the documentation,
assumes you want rows and columns.
There are ways to incorporate a thing like Mongo into a Django application, but that takes a lot
of extra legwork that you may not want to do.
You're kind of fighting.
You're going against the grain a lot of times, even though it's possible, I feel like.
Django, it encourages rapid development as long as you want to do things the Django way.
Which is oftentimes a good way to do things, but if you want to go outside that norm,
you're going to have to pull apart some code to do that.
I think Django is good.
A lot of people use it.
It certainly seems to be super effective for people who want to kind of get started quick
and stuff.
I personally lean more towards the micro framework because I want to pick that little data access
layer and that little bit over here and just put it together, you know, but I think
that's just my personality.
Yeah, but if you want to start quick and build big to start, then Django is pretty much the
way to go.
Yeah.
So in here, you design the models differently in a similar but different way because you
use the Django ORM, not the SQLAlchemy style, right?
Where the SQLAlchemy style has you inherit from this thing called the base.
It's actually fairly similar with Django.
When you're building a model, you inherit from Django's own base model, which handles the
database interaction layer for you.
And then instead of having columns or column objects, you have field objects, but it's still
the same thing underneath.
There are one of the benefits of using Django's fields is that there are some specific keyword
arguments you can set for specific fields.
One of my favorites is the auto now add that comes with the daytime field, which says, you
know, when you create a new instance of this object, then I'm going to just set the date
time on like for now.
Whatever now is, that's the date time on this field.
Yeah.
And you could do that with SQLAlchemy, but it's easy to make mistakes on it, right?
Like you could say, instead of saying the now function, you say now with parentheses and you
get like every model is marked at the time that when the app started, you know, funky stuff
like that.
Exactly.
One thing that's always kind of put me off on Django is the way you define URLs is like
regular expressions.
That's always sort of driven me crazy.
Yeah.
I mean, to a degree you do that in pyramid as well.
If you want to have any variable routes.
Right.
If you want to, you say this can only be an integer.
Right.
Here.
Right.
You say the variable name, but if you want to constrain it, then it's a regular expression.
Up through Django 111.
I'm not sure if that's still the case in Django 2, actually, because they have the pattern
now.
They changed it.
They changed the new pattern to make it a lot nicer.
Up through Django 111, which is what I built the app in, is you have to have a specific
regular expression to be matched for your pattern.
And the way that you, like the whole pattern itself is a regular expression, not just the
variable part.
Whereas with Django 2 now, it's a little bit more natural, a little less nuanced for just
regular expressions.
You can still do the old way if you want to, but they're encouraging you to use the new pattern
that isn't a regex unless you absolutely need it.
Yeah.
So instead of having like a regular expression for the integer, you know, you just say angle
bracket int colon, you know, oh, so nice.
Right.
But if you want an integer that's only, you know, that must be four numbers long, then you
want to get more and get more into doing regular expressions.
Yeah, that's cool.
All right.
So you went through this whole experience.
You went through these four frameworks.
And to be honest, you just scratched the surface.
There's a bunch more web frameworks like there's, there's bottle and there's webbed pie and there's
There's cherry pie.
There's sanding and cherry pie.
There's hug, which is apparently a web framework.
There's, yeah.
Which is based on Falcon, which is another web framework.
It's like, oh my gosh.
So just to like, on one hand, this is just a sampling, but it is a sampling of the major
elements of the Python web framework.
So what are your takeaways here?
My takeaways here for these four specifically, because I just didn't have a time to dig into
any other ones.
Well, and it's a talk.
How many could, how many more could you have actually presented in like 35 minutes, right?
Right.
I mean, when I gave my talk, it was at 25 minutes, right?
And even with just these four and with just a little bit of detail that I gave for each
one, I still ran over time and I had to get cut off toward the end.
They're shaking that red thing at you like, oh, you're over time.
Yeah, exactly.
But my impressions were as follows.
For Flask, like Flask is good for small tasks or tasks that don't require a database.
You can still do database stuff with Flask, but it becomes harder.
So if you're going to start small and stay small and be simple, Flask is the way to go.
It's really quick to get up and running.
It's really simple to put together.
And you can think more about the actual implementation of some of the logic you want to do.
Pyramid is great if, as the slogan says, if you want to start small, but you anticipate
getting larger, Pyramid is great for that.
If you anticipate getting larger and you still want to know what's going on, you want to have
a hand, you still want to have that do-it-yourself feel, Pyramid will give that to you.
But it also can hand you some of the pieces to work with so you don't have to do too much
thinking for yourself.
Tornado is kind of like an in-between between Flask and Django.
It can do Flask stuff if you want to do Flask sort of stuff.
It can do Django sort of stuff if you want to do Django sort of stuff.
But it's specifically good for any sort of asynchronous work you want to do or if you want to build a
chat room, that's good for Tornado.
If you want to have access to more of the bare networking layer of a web framework, Tornado
is good for that as well.
Django is if you want to build big and stay big, if you anticipate a lot of complexity
and you don't want to think too much about the details, you want to think more about how
it's supposed to all fit together, Django is good for that.
All right.
That sounds pretty good.
What other frameworks were you thinking about or have you thought about that maybe?
We sort of touched on them a little bit, but what else did you consider for this list?
I was thinking, so it's interesting.
One of the things that I only noticed after I started teaching about web dev is that we use
a Jupyter Notebook, which is a popular data science tool for displaying your analysis,
displaying your code.
When you install Jupyter Notebook, let me just check if I could be installing it right
now.
When you install Jupyter Notebook, one of the dependencies is a web framework.
And the web framework is Tornado.
I think in the past it might have been Twisted, which is another asynchronous web framework.
I didn't get a chance to look into it.
From what I understand, it's a little twisted for writing.
But yeah, that's another web framework that I kind of wanted to get into.
I had seen Web2Py, but never actually used it.
My friend Chris Ewing, he's a big proponent of Plone, which is an older web framework where
Pyramid learned a lot from what Plone used to do.
It's still around.
Yeah, it's almost like the next generation of Plone, almost.
The same people seem to work on it and stuff.
Yeah.
It's got some same idioms.
When I started doing web dev, I started with WordPress.
And this is a long way from WordPress.
And I'm glad I didn't have to go through WordPress again.
Yeah, that's cool.
Those are all interesting ideas.
I guess the other ones that kind of capture my imagination now are the async await enabled
Python 3 ones, like API star, Sanic, Jepronto, Cort.
They're sort of the Python 3 only ones that are pretty interesting.
I think I might look into those then because I've kind of really had the fire lit under me
for async.
I feel like it doesn't need to be this esoteric thing.
You know, it's a pattern in Python.
It should be learnable.
Yeah, it definitely should be learnable.
I think, well, you know, you and I are teachers on one aspect of what we do.
So we can work on that stuff, right?
We can build it out for people.
Yeah.
Awesome.
So I want to throw an idea out there that I just had while you're doing this that would
be amazing that you could build for the community.
You may be busy and not interested, but it would be amazing if there was like a website
whose job was to have these comparisons.
And somehow if it was like open to PRs, like somebody's like, oh, I want to submit an API
star version of the same app to you.
And that would be a killer community resource.
If it like it was available for the community to write this app and sort of write an article
for every framework that existed.
The GitHub organization that holds all four of the web frameworks is there.
You know, I'm perfectly happy to have PRs for that.
Yeah, that's actually a pretty good starting point, isn't it?
So we'll be sure to link to your repo for this in the show notes.
Are you open for people to do PRs for you?
To do another one?
Sure.
Oh, yeah.
All right.
So we talked about the web frameworks.
We talked about your boot camp.
What else have you got going on that you want to chat about that you'd like to let people
know about?
Yeah, absolutely.
If you're in the Seattle area, the meetup group Puppy, Puget Sound Programming Python
is really awesome.
I've been lucky enough to be involved with them for the last year and a half or so.
And they're really open to new people, to new developers.
In the last year or so, we have a Slack channel.
We've started the Q&A channel in the Slack team for people to just ask questions.
We kind of have our own little Stack Overflow going in there.
You know, and also just random stuff.
If you have a pretty much like whatever interest you have, the organizers, Don and Alan, two of
the people who helped put together PyCascades, they are always open to new ideas, to fresh
ideas, to people who want to get more involved.
So that's been cool to be a part of that.
I've been really lucky there.
Yeah, that's really great.
And Puppy seems like a good organization.
And what was surprising to me is how many people from Seattle and Portland we met in
Vancouver.
Yeah.
Right?
We left the country to meet people just down the street.
It's time and opportunity, right?
Like the conferences bring people together.
But, you know, when you're at home, you have your work schedule, you have your home schedule.
Like I have a kid.
I can't even go out that much anymore.
I know.
I have three kids.
It's like, go out at night?
What are you talking about?
Like it's super rare that I can go just hang out at like some tech evening event, right?
Exactly.
My wife's teaching or something.
I got to be home.
Right.
Like if I'm going to go to Puppy, I need to know like two months in advance.
You know, so I can, I can, I can warn my, my, my, my fiance.
I can warn her again, two weeks later and warn her again, two weeks later after that.
That, you know, I'm going to be going to this thing.
We have to get a sitter or like you have to stay home.
You know what?
Something's got to happen.
So we can, there's a lot of, there's a lot of logistical stuff going on in there.
Right.
But you go to a conference, you kind of, you've already stepped away from that.
You've created that space.
And so it's, it's easy to meet people, right?
I'm here for this one specific reason.
Just learn about Python and meet people.
So that's, that was cool.
And actually through Puppy, one of the things that I'm trying to do in the, in the coming
year is to be more of a mentor.
I've been, I've been the beneficiary of some really awesome people who have been mentors
in the short term or the long term to give me advice every once in a while, give me some
advice or, or help me deliver you through a process.
And I kind of want to give that back to the community.
And so as a teacher for the last two years, I've been able to graduate about a hundred or
more people from the Python program.
And I kind of want to get back in touch with those people and kind of figure out like what they're
doing, what they're working on, where they're headed, where they're heading in their
careers.
Maybe if I can, if I can, even if it's not a mentorship position, more, more like a
accountability partner, you know, help them move forward through their careers.
I like being able to have a hand in developing talent in the same way that people help me
develop my talent.
It doesn't take a lot of effort on somebody who's experienced on their part to just give
a little bit of guidance.
Yeah.
Because when you're new, you just look around and it's even like, it gets worse every day.
There are more frameworks.
There are more languages.
There are more libraries.
You're like, I have no idea what to do.
I know I want to learn this stuff and I want to accomplish this, but where do I start?
Right?
Like, how do I go about this?
And so you can give them some guidance.
It goes beyond that too.
It's like, you know, well, you know, I never thought about giving a talk at a conference.
I never thought about giving a talk at a meetup.
I hadn't thought about giving a talk at a meetup until my friend Chris said, Hey, you should
give talks at meetups.
And I was like, Oh, I can, I can do that.
That's a thing that I can do.
Yeah.
There's no gatekeepers.
You just have to decide that you can do it.
Then you can do it.
Exactly.
There are going to be some things that I'm aware of that people who are my former students
are not aware of.
Like if there's a panel going on, like, Hey, you should be on this panel.
We should attend this panel.
We should meet this person.
You should go to this coffee meeting and see these people and be aware of these, of these
concepts of these environments.
Because, you know, have I found I've been in a lot of different spaces in the last, let's
say like 10 years or so.
And what I've noticed in each of those roles has been that most of the work isn't just
being in the right place at the right time or meeting the right person at the right time.
And if you never meet that person or if you're never in that place, you don't even know that
those opportunities are there to be taken advantage of.
Like I've been able to make some great contacts at Facebook just by going to a hackathon once and
chatting up one of the organizers of the hackathon.
Or Twitter has been an amazing resource to meet people, see what they're into, learning
about other things going on in the field of Python development, just being aware of being
around and being able to help new people get into that community.
Yeah.
I find that a lot of these little hands that you offer to people to help them actually
come back in unexpected ways.
And, you know, there's a lot of karma in the world in that sense.
Oh, absolutely.
Absolutely.
I never would have gone to my first conference as an astronomer if my advisor never told
me about that it existed.
Yeah.
And then I wouldn't have met the person who introduced me to Marcel Agueros, who runs the
Bridge of the PhD program at Columbia.
If I'd never gone to that, I would probably never be here in Seattle doing Python instruction
at Code Fellows because I never would have gone for a PhD at UDEL.
There's so many things in the chain of events that could have gone a different way if I had
just been in the right place at the right time or talked to the right people.
I think the big takeaway here is you can't too deeply overthink these little variations
because your life could be so different.
Just, you know, sort of chaos theory, right?
Butterfly wings type of thing.
Absolutely.
Yeah.
Cool.
All right.
Well, I think we're getting close to the end of our time together.
Let me hit you with the two questions that I always put at the end.
If you're going to write some Python code, what editor do you open up?
My first instinct is Sublime Text, but I've been going more toward Visual Studio Code
in the last week.
Okay.
Yeah, nice.
Visual Studio Code with a Python plugin is quite nice.
Oh, yeah.
I use Visual Studio Code for like if I just want to open up one file and stuff.
I'm doing a big project.
I usually use PyCharm, but I definitely like Visual Studio Code as well.
All right.
And then notable PyPI package.
I love the requests library.
I also love beautiful soup.
And then pandas, when I was a researcher, pandas changed my life.
Like how I did research, how I did analysis.
I was using NumPy and NumPy arrays.
Pandas all the way.
Oh, that's awesome.
Yeah.
Pandas is really, really cool and important.
And to me, requests and beautiful soup literally feels like magic.
Like there's this web page with stuff.
And then I write like five lines of code.
And then I have it like in structured data on my machine.
I'm like, that just blew my mind that that just happened.
Right?
It is really cool.
Oh, yeah.
All right.
So final call to action.
People are excited.
Maybe they're about checking out these web frameworks, your project, or maybe even your bootcamp.
What do you say?
If you want to talk to me, the easiest way to reach me is on Twitter.
It's just at Enhan Walker.
I'm on there literally all the time.
Probably more than I should be.
If you're interested in learning how to code, Code Fellows is a dope place.
If you're in Seattle or in Portland, Code Fellows, great place to learn JavaScript, Java, C#, or Python.
We have some really dedicated instructors who are really focused on getting people into careers as best as they can.
All right.
Awesome.
Well, Nick, it's really been great to share the four framework comparison with you and the stories.
Thank you so much for being on the show.
Thanks for having me.
I hope this was helpful to somebody.
Yeah, I'm sure it will be.
All right.
Bye.
This has been another episode of Talk Python to Me.
Today's guest was Nicholas Hunt Walker, and this episode has been brought to you by Linode.
Linode is bulletproof hosting for whatever you're building with Python.
Get four months free at talkpython.fm/linode.
That's L-I-N-O-D-E.
Are you or a colleague trying to learn Python?
Have you tried books and videos that just left you bored by covering topics point by point?
Well, check out my online course, Python Jumpstart, by building 10 apps at talkpython.fm/course
to experience a more engaging way to learn Python.
And if you're looking for something a little more advanced, try my Write Pythonic code course
at talkpython.fm/pythonic.
Be sure to subscribe to the show.
Open your favorite podcatcher and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, Google Play feed at /play, and direct
RSS feed at /rss on talkpython.fm.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Now get out there and write some Python code.
I'll see you next time.
Bye.
you
Thank you.