WEBVTT

00:00:00.080 --> 00:00:04.920
Refactoring your code is a fundamental step on the path to professional and maintainable software.

00:00:04.920 --> 00:00:09.760
We rarely have the perfect picture of what we need to build when we start writing code,

00:00:09.760 --> 00:00:16.760
and attempts to overplan and overdesign software more often lead to analysis paralysis rather than ideal outcomes.

00:00:16.760 --> 00:00:21.240
Join me as I discuss refactoring with Brendan McGinnis and Nick Thoppen,

00:00:21.240 --> 00:00:27.600
as well as their tool, Sorcery, which adds automatic refactoring in the popular Python editors.

00:00:28.000 --> 00:00:32.980
This is Talk Python To Me, episode 266, recorded May 21st, 2020.

00:00:32.980 --> 00:00:52.360
Welcome to Talk Python To Me, a weekly podcast on Python, the language, the libraries, the ecosystem, and the personalities.

00:00:52.360 --> 00:00:56.440
This is your host, Michael Kennedy. Follow me on Twitter where I'm @mkennedy.

00:00:56.640 --> 00:01:02.600
Keep up with the show and listen to past episodes at talkpython.fm, and follow the show on Twitter via at Talk Python.

00:01:02.600 --> 00:01:05.860
This episode is sponsored by Datadog and Linode.

00:01:05.860 --> 00:01:09.440
Please check out what they're offering during their segments. It really helps support the show.

00:01:09.440 --> 00:01:12.300
Brendan, Nick, welcome to Talk Python To Me.

00:01:12.300 --> 00:01:13.000
Thank you very much.

00:01:13.000 --> 00:01:14.520
Thank you for having us.

00:01:14.520 --> 00:01:15.860
Yeah, it's great to have you here.

00:01:16.060 --> 00:01:26.260
I'm such a huge fan of refactoring and code quality and all these ways of taking living software and making it evolve, right?

00:01:26.340 --> 00:01:32.960
I think long gone are the days of we have to plan this perfectly, and then we're going to build the perfect thing that we've thought up, right?

00:01:33.020 --> 00:01:40.000
And so having this idea of continuously evolving and improving code, it just frees you from worrying about trying to get it all right and you can just get started.

00:01:40.000 --> 00:01:43.000
And so I'm really excited to talk about sorcery and refactoring with you guys.

00:01:43.000 --> 00:01:45.380
Awesome. Yeah, we think iteration is super important as well.

00:01:45.380 --> 00:01:51.460
Sort of trying to get a skeleton of the thing up and running and then sort of tidying up later.

00:01:51.460 --> 00:01:52.180
Yeah, absolutely.

00:01:52.280 --> 00:01:53.340
That's kind of how we like to work.

00:01:53.340 --> 00:01:57.240
No one really understands the domain when they first write the code anyway.

00:01:57.240 --> 00:02:03.440
You have to write the code, find out all the mistakes that you've made, and then tidy it up, clean it up.

00:02:03.440 --> 00:02:13.100
Over time, like you say, it evolves into what looks to be a nice quality code base and solves the needs of the users.

00:02:13.100 --> 00:02:19.500
Yeah, I think that's a super good point because understanding, you don't fully understand it until you've gotten mostly into it.

00:02:20.040 --> 00:02:23.320
But if you tried to understand it all, it's just so much work.

00:02:23.320 --> 00:02:27.780
Even if you get it right, it's so much work to get to that point that you might as well have just written it three times.

00:02:27.780 --> 00:02:29.080
So that's awesome.

00:02:29.080 --> 00:02:33.400
But before we jump into more of that, let's just get your stories.

00:02:33.400 --> 00:02:34.900
And Nick, I guess we'll start with you first.

00:02:34.900 --> 00:02:36.740
How do you all get into programming into Python?

00:02:36.740 --> 00:02:42.120
So I guess the first program I did was back in school on these graphics calculators we had back in the 90s.

00:02:42.120 --> 00:02:47.640
And I remember reading a book about complex numbers and being super proud of getting my calculator to draw a fractal.

00:02:47.640 --> 00:02:49.720
I think it took about 12 hours to draw it.

00:02:50.240 --> 00:02:54.460
But I end up with a Mandelbrot set on my little calculator.

00:02:54.460 --> 00:02:56.660
Like the Mandelbrot set or something cool like that.

00:02:56.660 --> 00:02:57.560
Could you zoom in?

00:02:57.560 --> 00:03:00.120
I think you could zoom in, but it would take another 12 hours to show you.

00:03:00.120 --> 00:03:03.360
You could only do it twice because then the battery would run out.

00:03:03.360 --> 00:03:03.820
Pretty much.

00:03:04.140 --> 00:03:10.980
I did a little bit of basics and stuff, but I never did programming in a serious way until joining a software company after university.

00:03:10.980 --> 00:03:12.280
What are you studying at university?

00:03:12.280 --> 00:03:13.320
So it's maths and philosophy.

00:03:13.320 --> 00:03:13.700
Okay.

00:03:13.700 --> 00:03:15.400
That's a cool combination, actually.

00:03:15.400 --> 00:03:15.740
Yeah.

00:03:15.740 --> 00:03:19.100
And there's like a lot of logic, which I guess is quite key to programming.

00:03:19.720 --> 00:03:24.920
And then the first languages I learned in the software company were this mainframe language called IBM RPG.

00:03:24.920 --> 00:03:27.240
I don't know if you've come across that one.

00:03:27.460 --> 00:03:30.540
I could not look at RPG source code and tell you what it is.

00:03:30.540 --> 00:03:32.280
Like I couldn't identify it from code.

00:03:32.280 --> 00:03:33.200
Yeah, I've heard of it.

00:03:33.200 --> 00:03:33.760
That's incredible.

00:03:33.760 --> 00:03:35.300
It's sort of, it's like punch cards.

00:03:35.300 --> 00:03:38.880
Everything has to be in the same, in the right column kind of thing.

00:03:38.880 --> 00:03:39.220
Okay.

00:03:39.220 --> 00:03:40.480
Because it was this finance company.

00:03:40.480 --> 00:03:41.320
Brendan went there as well.

00:03:41.320 --> 00:03:43.500
It sounds as useful, but I think I'll stick with Python.

00:03:43.500 --> 00:03:43.920
Yeah.

00:03:43.920 --> 00:03:46.400
I had this code base from the eighties.

00:03:46.400 --> 00:03:47.240
Okay, cool.

00:03:47.400 --> 00:03:48.980
And you had to program it in a green screen terminal.

00:03:48.980 --> 00:03:50.300
So that didn't put me off.

00:03:50.300 --> 00:03:50.560
Yeah.

00:03:50.560 --> 00:03:52.580
If you go through that, you're definitely good for this industry.

00:03:52.580 --> 00:03:55.140
If you can make it through that, Steve, you'll be good.

00:03:55.140 --> 00:03:59.580
And then it was Delphi, which I also look back on as not being super amazing.

00:03:59.580 --> 00:04:01.080
And then Java.

00:04:01.080 --> 00:04:08.580
And then it was only when I joined Imperial and started doing sort of machine learning that I got into Python, I guess, mid 2010s.

00:04:08.580 --> 00:04:08.760
Cool.

00:04:08.760 --> 00:04:10.900
You're like, why does this language have semicolons?

00:04:10.900 --> 00:04:11.580
What happened to it?

00:04:11.580 --> 00:04:11.780
Yeah.

00:04:11.780 --> 00:04:14.140
I mean, after Java, it just was like a breath of fresh air, really.

00:04:14.140 --> 00:04:17.340
And when I had to go back to doing Java, it seemed so verbose.

00:04:17.520 --> 00:04:17.680
Yeah.

00:04:17.680 --> 00:04:18.260
You're like, why?

00:04:18.260 --> 00:04:18.960
I can't read this.

00:04:18.960 --> 00:04:21.060
There's symbols all over what it's trying to tell me.

00:04:21.060 --> 00:04:21.300
Yeah.

00:04:21.300 --> 00:04:21.540
Yeah.

00:04:21.540 --> 00:04:24.220
Curly braces and parentheses and semicolons.

00:04:24.220 --> 00:04:24.700
Yeah.

00:04:24.700 --> 00:04:28.420
And the way they do the libraries and things, actually, it seems to be all done in a very verbose way.

00:04:28.420 --> 00:04:28.740
Yeah.

00:04:28.740 --> 00:04:29.300
Indeed.

00:04:29.300 --> 00:04:30.060
Lots of boilerplate.

00:04:30.060 --> 00:04:30.400
Nice.

00:04:30.400 --> 00:04:30.860
Cool.

00:04:30.860 --> 00:04:31.900
Well, Brendan, how about you?

00:04:31.900 --> 00:04:36.040
The first programming I did was in my final year math degree.

00:04:36.040 --> 00:04:43.700
So we had a project to do, which was to simulate various mathematical equations.

00:04:44.360 --> 00:04:47.380
So the ones that I chose were the heat equation.

00:04:47.380 --> 00:04:57.060
And it would simulate one wall being hot and another wall being cold and various obstacles between the two walls.

00:04:57.700 --> 00:05:03.700
And then after it ran, it would show this chart of the temperature at different places in the room.

00:05:03.700 --> 00:05:10.200
And the other thing I simulated was the Schrodinger equation, which quantum mechanics.

00:05:10.300 --> 00:05:10.460
Yeah.

00:05:10.460 --> 00:05:12.200
Quantum mechanics is so interesting.

00:05:12.200 --> 00:05:17.020
And it's just like, it seems like such a weird Twilight Zone alternative reality.

00:05:17.020 --> 00:05:20.560
And yet it seems to be applying to real reality.

00:05:20.560 --> 00:05:21.760
It's such a weird world.

00:05:21.760 --> 00:05:22.900
I love quantum mechanics.

00:05:22.900 --> 00:05:23.320
Yeah.

00:05:23.320 --> 00:05:26.280
It's amazing how accurate the predictions are.

00:05:26.280 --> 00:05:32.440
And yet when you try to understand it, it just has no similarity to reality.

00:05:32.440 --> 00:05:33.420
Just making that up, aren't you?

00:05:33.420 --> 00:05:34.480
There's no way this is real.

00:05:35.080 --> 00:05:39.340
When you get so small, it doesn't match up with what you understand.

00:05:39.340 --> 00:05:41.080
Yeah, for sure.

00:05:41.080 --> 00:05:43.820
How can this object be in two places at the same time?

00:05:43.820 --> 00:05:45.360
What does that even mean?

00:05:45.360 --> 00:05:45.780
Exactly.

00:05:45.780 --> 00:05:46.280
Yeah.

00:05:47.140 --> 00:05:52.020
Well, the equation, I was just simulating a single object in the waveform of it.

00:05:52.020 --> 00:05:54.760
So it was quite simple.

00:05:54.760 --> 00:06:03.460
But the way they did it was, here's min GW, go and program it in C, and then just send us off to go and do it.

00:06:03.460 --> 00:06:06.080
And we knew nothing about how to program.

00:06:06.460 --> 00:06:13.940
So my programs were just hundreds of lines of statements, absolutely no functions, nothing, no structure.

00:06:13.940 --> 00:06:14.240
Yeah.

00:06:14.240 --> 00:06:15.520
I think we probably all got-

00:06:15.520 --> 00:06:17.540
Probably some memory leaks in there as well if it was written in C.

00:06:17.540 --> 00:06:18.220
Oh, yeah.

00:06:18.220 --> 00:06:19.380
The whole thing, yeah.

00:06:19.380 --> 00:06:21.540
The whole thing was pretty terrible.

00:06:21.540 --> 00:06:28.500
But you get to the end of the project and you simulate it correctly and you think, I can program now.

00:06:28.500 --> 00:06:29.680
I know how to program.

00:06:30.320 --> 00:06:36.620
Even if that's not entirely true, I think you do come away with this feeling of like, oh my gosh, look what I built.

00:06:36.620 --> 00:06:39.740
Like, this is so awesome, even if it's not really.

00:06:39.740 --> 00:06:44.560
It's just like that feeling of creating that thing is so cool in those days when you're getting started.

00:06:44.560 --> 00:06:45.160
Absolutely.

00:06:45.160 --> 00:06:55.340
I think that, yeah, the first time that I managed to output the heat equation onto the screen where you see the different temperature across the room,

00:06:55.340 --> 00:06:58.500
they provided us with a charting library to use.

00:06:58.500 --> 00:06:59.700
That was amazing.

00:06:59.700 --> 00:07:01.720
And I was like, wow, I can program.

00:07:01.720 --> 00:07:03.320
I can do anything.

00:07:03.320 --> 00:07:04.720
I know computers now.

00:07:04.720 --> 00:07:05.920
Yeah.

00:07:05.920 --> 00:07:06.540
Yeah, yeah.

00:07:06.540 --> 00:07:07.040
Super cool.

00:07:07.040 --> 00:07:08.480
So, yeah.

00:07:08.480 --> 00:07:12.580
After I finished university, I joined the same company as Nick.

00:07:12.580 --> 00:07:15.440
I learned RPG and I learned Delphi.

00:07:15.440 --> 00:07:16.620
I learned Java.

00:07:16.620 --> 00:07:21.640
And then I achieved quite a senior role in the company.

00:07:21.640 --> 00:07:24.200
I was part of the architecture team.

00:07:24.780 --> 00:07:32.920
And I managed to introduce Scala to the company, which, yeah, we did a language comparison and it was between JVM languages.

00:07:32.920 --> 00:07:38.240
So, one of the languages was actually J Python or Jiton.

00:07:38.400 --> 00:07:43.280
We didn't go for that or JRuby because it wasn't first class language on the platform.

00:07:43.920 --> 00:07:48.540
So, really, the main contenders were Java, Scala and Clojure.

00:07:49.540 --> 00:07:54.920
And we had someone come in and talk to us about Scala, who was really, really amazing.

00:07:54.920 --> 00:07:57.920
And he convinced us to use it.

00:07:58.340 --> 00:08:07.420
So, yeah, I ended up leading the project to bring Scala into the company and re-architect a lot of the systems in that.

00:08:07.420 --> 00:08:12.580
When I left that company, I was very much down the functional programming route.

00:08:12.580 --> 00:08:16.340
So, I did some more Clojure, which is very functional.

00:08:16.340 --> 00:08:17.440
I did some Haskell.

00:08:18.280 --> 00:08:22.560
But then I joined Nick, Imperial College London.

00:08:22.560 --> 00:08:28.000
And that's where he said he got into the Python.

00:08:28.000 --> 00:08:30.100
That's where I got into it as well.

00:08:30.100 --> 00:08:34.840
So, I joined a reading group that was all about deep learning.

00:08:35.660 --> 00:08:42.460
And I went to the reading group and we read a paper, which was called Differential Neural Computer.

00:08:42.460 --> 00:08:44.720
And I had no understanding what it meant.

00:08:44.720 --> 00:08:48.300
And I was like, OK, I'm going to go home and I'm going to implement it.

00:08:48.300 --> 00:08:53.240
So, I went home and I cracked out some Python, cracked out TensorFlow.

00:08:53.240 --> 00:08:59.300
And it took me weeks and weeks to implement it because I had no idea what was going on.

00:08:59.300 --> 00:09:02.140
That was the start.

00:09:02.140 --> 00:09:06.940
So, I just started implementing more and more of these papers as I went to more and more reading groups.

00:09:06.940 --> 00:09:16.660
And it tended to be all of the Atari playing reinforcement learning algorithms, which is really fascinating to me.

00:09:16.660 --> 00:09:17.460
OK, cool.

00:09:17.460 --> 00:09:20.800
So, I learned how to play Breakout and learned how to play Pong.

00:09:20.800 --> 00:09:21.420
Right.

00:09:21.420 --> 00:09:23.240
Maybe some Pitfall in there.

00:09:23.240 --> 00:09:25.200
I never tried it on Pitfall, actually.

00:09:25.200 --> 00:09:26.740
That was a good one.

00:09:26.740 --> 00:09:28.160
Nice.

00:09:28.160 --> 00:09:33.480
I'm really fascinated with these ways to train AIs around video games.

00:09:33.480 --> 00:09:36.880
I mean, I'm blanking on one of the options.

00:09:36.880 --> 00:09:42.200
But there's a handful of libraries that you can kind of plug your AI into the virtual world.

00:09:42.200 --> 00:09:46.780
So, it has somewhere to interact with and things to interact with.

00:09:46.780 --> 00:09:47.700
And yeah, that's fascinating.

00:09:47.700 --> 00:09:48.180
Yeah.

00:09:48.420 --> 00:09:50.000
I really did find it fascinating.

00:09:50.000 --> 00:09:52.580
That's why I was doing it every week.

00:09:52.580 --> 00:09:56.920
And then just around that time, AlphaGo came out as well.

00:09:56.920 --> 00:09:59.400
And it was like a shock to the world.

00:09:59.400 --> 00:10:05.460
Suddenly, the hardest game that humanity can play is beaten by a computer.

00:10:05.800 --> 00:10:05.940
Yeah.

00:10:05.940 --> 00:10:12.900
And it's one of the first, it might have been the first real AI opponent that used like

00:10:12.900 --> 00:10:17.780
strategizing rather than just deep exploration of the paths.

00:10:17.780 --> 00:10:18.240
Right.

00:10:18.240 --> 00:10:23.820
Like the chess one is like, well, I can hold 12 steps ahead in every direction in my mind.

00:10:23.820 --> 00:10:26.020
That's more than the chess master.

00:10:26.020 --> 00:10:26.800
So, right.

00:10:26.800 --> 00:10:31.160
Like we'll just play them all out, all the possible futures out and then go down the best

00:10:31.160 --> 00:10:31.420
one.

00:10:31.420 --> 00:10:31.580
Right.

00:10:31.580 --> 00:10:34.900
But that's not how AlphaGo worked, which is, I think, part of the magic.

00:10:34.900 --> 00:10:36.340
Yeah, it's got intuition in a sense.

00:10:36.340 --> 00:10:37.280
That's the interesting bit.

00:10:37.280 --> 00:10:38.420
Yeah.

00:10:38.420 --> 00:10:38.760
Yeah.

00:10:38.760 --> 00:10:41.620
It was just fascinating the way they did that.

00:10:41.620 --> 00:10:46.080
I ended up writing a version of AlphaGo to play Kinect 4.

00:10:46.080 --> 00:10:46.680
Okay.

00:10:46.680 --> 00:10:49.620
Which is actually pretty strong.

00:10:49.620 --> 00:10:52.060
That was a really fun project as well.

00:10:52.060 --> 00:10:53.960
I mean, it can beat me.

00:10:53.960 --> 00:10:56.220
You're a very strong player.

00:10:56.220 --> 00:10:56.580
That's awesome.

00:10:56.580 --> 00:10:57.140
Yeah.

00:10:57.140 --> 00:10:59.000
I'm an average player out there.

00:10:59.000 --> 00:11:00.140
Yeah.

00:11:00.140 --> 00:11:00.360
Yeah.

00:11:00.360 --> 00:11:00.820
How cool.

00:11:00.820 --> 00:11:01.380
How cool.

00:11:01.380 --> 00:11:01.900
All right.

00:11:01.900 --> 00:11:04.340
So what are you both working on the same project yet again?

00:11:04.340 --> 00:11:05.480
What are you doing day to day?

00:11:05.480 --> 00:11:06.300
What are you doing now?

00:11:06.300 --> 00:11:08.240
We're both working on Sorcery full time.

00:11:08.240 --> 00:11:12.960
We kind of started working on it back at the end of 2018 from Brendan's flat.

00:11:12.960 --> 00:11:16.240
So I'd turn up and he'd be still in his pajamas eating cereal.

00:11:16.240 --> 00:11:19.700
Sit down and code away.

00:11:19.700 --> 00:11:20.840
Yeah.

00:11:20.840 --> 00:11:26.560
We're kind of totally focused on making Sorcery as good a refactoring tool as can be really.

00:11:26.560 --> 00:11:26.880
Yeah.

00:11:26.880 --> 00:11:27.140
Cool.

00:11:27.200 --> 00:11:30.940
We'll get into what Sorcery is more later, but what's the quick elevator pitch before

00:11:30.940 --> 00:11:33.540
we dive into just more general software stuff?

00:11:33.540 --> 00:11:36.200
I guess we've been pitching it as kind of Grammarly for code.

00:11:36.200 --> 00:11:41.500
And if you don't know what Grammarly is, it's like it improves the style of the code without

00:11:41.500 --> 00:11:43.280
changing the sort of meaning or the content.

00:11:43.280 --> 00:11:44.600
I guess that's what refactoring is.

00:11:44.600 --> 00:11:48.560
You improve this quality in the structure without changing the functionality.

00:11:48.560 --> 00:11:50.000
And that's what we aim to do.

00:11:50.100 --> 00:11:55.480
So as you're writing it, we analyze it and we suggest refactoring improvements sort of

00:11:55.480 --> 00:11:55.960
as you go.

00:11:55.960 --> 00:12:01.840
So maybe I got a loop and I'm doing some kind of accumulation into a list and it could say,

00:12:01.840 --> 00:12:03.260
you know what, that could just be a list comprehension.

00:12:03.260 --> 00:12:04.000
Yeah, exactly.

00:12:04.000 --> 00:12:04.860
Yeah.

00:12:04.860 --> 00:12:05.120
Okay.

00:12:05.120 --> 00:12:06.700
That sounds awesome.

00:12:06.700 --> 00:12:12.480
It's easy to just get focused on writing code and then not really worrying about the quality.

00:12:12.480 --> 00:12:19.580
It's also equally easy to get super obsessed with the quality and not just get the thing

00:12:19.580 --> 00:12:19.860
done.

00:12:19.860 --> 00:12:20.220
Right.

00:12:20.220 --> 00:12:23.160
So I kind of see like these two bimodal distributions.

00:12:23.160 --> 00:12:24.680
One's like, I don't give a crap.

00:12:24.680 --> 00:12:25.680
I'm not going wrong as it works.

00:12:25.680 --> 00:12:26.820
I'm just going to write, write, write.

00:12:26.820 --> 00:12:27.280
Yeah.

00:12:27.280 --> 00:12:30.840
And, you know, that's one group of people's philosophy.

00:12:30.840 --> 00:12:36.600
The other is they're like really slow and super meticulous to get it just right because

00:12:36.600 --> 00:12:38.480
they want to write it the best way.

00:12:38.480 --> 00:12:44.200
And it sounds to me like the tool would let people kind of find a middle ground, right?

00:12:44.200 --> 00:12:47.120
Like write it a little more loose and free.

00:12:47.260 --> 00:12:50.180
But then it says, oh, by the way, that thing you just wrote, actually, we could make that

00:12:50.180 --> 00:12:51.680
way better if you just let us.

00:12:51.680 --> 00:12:52.500
Yeah, that's kind of the idea.

00:12:52.500 --> 00:12:53.760
And that's some of the feedback we've been getting.

00:12:53.760 --> 00:12:57.940
That's people write codes a bit more quickly without worrying so much about the quality and

00:12:57.940 --> 00:12:59.220
it'll kind of tidy up for them.

00:12:59.220 --> 00:12:59.960
Okay, cool.

00:13:00.180 --> 00:13:07.220
And the other aspect of it is some people don't actually know what good quality code

00:13:07.220 --> 00:13:07.540
is.

00:13:07.540 --> 00:13:13.840
So if you're starting out in Python, you may be able to write the solution, but you won't

00:13:13.840 --> 00:13:15.860
necessarily know how to write it well.

00:13:15.860 --> 00:13:19.280
So you may not even know about this comprehensions yet.

00:13:19.280 --> 00:13:20.860
Right, right, right.

00:13:20.860 --> 00:13:29.260
And the benefit of using Sorcery in that case is it can teach you the Pythonic way of writing

00:13:29.260 --> 00:13:29.720
code.

00:13:29.720 --> 00:13:34.040
This portion of Talk Python To Me is brought to you by Datadog.

00:13:34.040 --> 00:13:38.360
Are you having trouble visualizing bottlenecks and latency in your apps and you're not sure

00:13:38.360 --> 00:13:40.380
where the issue is coming from or how to solve it?

00:13:40.380 --> 00:13:46.120
With Datadog's end-to-end monitoring platform, you can use their customizable built-in dashboard

00:13:46.120 --> 00:13:49.780
to collect metrics and visualize app performance in real time.

00:13:49.780 --> 00:13:55.520
Datadog automatically correlates logs and traces at the level of individual requests, allowing

00:13:55.520 --> 00:13:57.700
you to quickly troubleshoot your Python application.

00:13:57.700 --> 00:14:02.740
Plus, their service map automatically plots the flow of requests across your application

00:14:02.740 --> 00:14:07.420
architecture so you understand dependencies and can proactively monitor the performance

00:14:07.420 --> 00:14:08.100
of your apps.

00:14:08.100 --> 00:14:11.540
Be the hero that got your app back on track at your company.

00:14:12.040 --> 00:14:16.360
Get started today with a free trial at talkpython.fm/datadog.

00:14:17.560 --> 00:14:19.900
So maybe you don't necessarily know the idioms.

00:14:19.900 --> 00:14:25.900
I think one of the challenges of Python in particular, I mean, all languages have this problem, but

00:14:25.900 --> 00:14:28.020
Python suffers more than others from it.

00:14:28.020 --> 00:14:34.540
One is that it's so easy to learn that people feel like they can learn it in a weekend and

00:14:34.540 --> 00:14:36.260
then they just go write code in it, right?

00:14:36.260 --> 00:14:38.500
Because like, look, it's a simple little language.

00:14:38.500 --> 00:14:39.420
There's not a whole lot to it.

00:14:40.060 --> 00:14:42.120
Which I think is actually not true, right?

00:14:42.120 --> 00:14:44.240
I still feel like I'm learning Python every day.

00:14:44.240 --> 00:14:48.460
I'm like, I didn't know, or I should have done this, right?

00:14:48.460 --> 00:14:49.380
Like, there's all these things.

00:14:49.380 --> 00:14:52.440
There's just, there's so much nuanced detail to it.

00:14:52.440 --> 00:14:58.460
But it's easy for people to come from a language like C or Java or something else and just do

00:14:58.460 --> 00:15:03.400
the Java style programming there or the C style programming there.

00:15:03.400 --> 00:15:08.800
And not, like you said, not even know that there's this other component, right?

00:15:08.860 --> 00:15:10.740
They say, oh, Python's crappy.

00:15:10.740 --> 00:15:14.160
It doesn't have, you know, a four, a numerical for loop.

00:15:14.160 --> 00:15:15.560
This is crummy, right?

00:15:15.560 --> 00:15:20.260
When really a better way to do it would be to use enumerate collection where you get the

00:15:20.260 --> 00:15:22.160
index and the item, right?

00:15:22.160 --> 00:15:22.860
You don't have to go back.

00:15:22.860 --> 00:15:25.360
If you didn't know, like that's multiple layers.

00:15:25.360 --> 00:15:26.940
One, you have to know there's a four in loop.

00:15:26.940 --> 00:15:29.460
And then two, you have to know that enumerate is a thing.

00:15:29.460 --> 00:15:30.920
And then you've got to know about tuple and back.

00:15:30.920 --> 00:15:34.260
And like, that's a pretty complex set of topics.

00:15:34.260 --> 00:15:38.120
If you've, well, I spent the weekend now, I kind of know, let's, let's finish this project.

00:15:38.660 --> 00:15:38.960
Yeah.

00:15:38.960 --> 00:15:39.580
If you took that philosophy.

00:15:39.580 --> 00:15:40.200
Absolutely.

00:15:40.200 --> 00:15:46.740
I mean, like you said, the learning, the Python language, and it's so beautifully simple that

00:15:46.740 --> 00:15:50.480
most people can pick it up in a week to a month's time.

00:15:50.860 --> 00:15:56.420
But then you've got all of these items and they're not just the different bits of syntax

00:15:56.420 --> 00:15:58.200
or the enumerate.

00:15:58.200 --> 00:16:00.840
There's multiple libraries all over the place.

00:16:00.840 --> 00:16:05.720
And they're the libraries that are built into the Python main library.

00:16:05.880 --> 00:16:11.060
But there are also all of the libraries out there that you need to accomplish more complicated

00:16:11.060 --> 00:16:11.500
tasks.

00:16:11.500 --> 00:16:11.720
Yeah.

00:16:11.720 --> 00:16:17.020
Just finding out what the best library is for the job is a difficult piece of research often.

00:16:17.020 --> 00:16:17.560
It is.

00:16:17.560 --> 00:16:21.700
Sometimes it's something built in, like inner tools or something like that.

00:16:21.800 --> 00:16:26.660
Or other times it's something you've never heard of because there's 200,000 options and

00:16:26.660 --> 00:16:28.840
they all have their, their behaviors and whatnot.

00:16:28.840 --> 00:16:33.680
But if you would grab it like that would take 20 lines down to one, probably be faster at the

00:16:33.680 --> 00:16:34.020
same time.

00:16:34.020 --> 00:16:35.000
It's like, it's incredible.

00:16:35.000 --> 00:16:35.280
Right.

00:16:35.520 --> 00:16:36.660
That's kind of what I was thinking.

00:16:36.660 --> 00:16:40.720
I'm like, I've never done learning Python because like, oh, there's this other standard

00:16:40.720 --> 00:16:45.140
library module I discovered where I wasn't using counter in this way or, you know, like

00:16:45.140 --> 00:16:45.860
whatever it is, right?

00:16:45.860 --> 00:16:46.800
There's just all these options.

00:16:46.800 --> 00:16:46.920
Yeah.

00:16:46.920 --> 00:16:47.900
We've definitely come across that.

00:16:47.900 --> 00:16:48.320
Sorry.

00:16:48.320 --> 00:16:48.640
Come on.

00:16:48.640 --> 00:16:48.920
Yeah.

00:16:48.920 --> 00:16:49.280
Yeah.

00:16:49.280 --> 00:16:50.000
I can imagine.

00:16:50.000 --> 00:16:50.580
I can imagine.

00:16:50.580 --> 00:16:54.800
And coming from an academic space, I'm sure you see that a lot there as well.

00:16:54.800 --> 00:17:01.600
Cause there's probably a lot of people who don't see themselves as a developer, but they're

00:17:01.600 --> 00:17:03.960
still touching Python, writing code.

00:17:03.960 --> 00:17:07.000
It's full of code you kind of write once and then don't, don't look at again.

00:17:07.000 --> 00:17:10.280
So it's kind of, I guess done with a different aim in mind.

00:17:10.280 --> 00:17:13.840
You're not, they're not so worried about reuse by other people often.

00:17:13.840 --> 00:17:14.180
Right.

00:17:14.180 --> 00:17:14.380
Right.

00:17:14.380 --> 00:17:20.580
It's actually been quite a challenge for us because we learn Python together effectively

00:17:20.580 --> 00:17:22.380
at the same time.

00:17:22.380 --> 00:17:29.580
And we've never written Python in a large code base apart from our own.

00:17:29.580 --> 00:17:33.020
So we've had to learn all of these things ourselves.

00:17:33.480 --> 00:17:39.860
So over time, we've rewritten bits of the system where we found out, oh, we can use this,

00:17:39.860 --> 00:17:43.040
this feature of Python that makes it so much better.

00:17:43.040 --> 00:17:50.460
And, at one point we integrated mypy into our code base and that was a big improvement.

00:17:51.000 --> 00:17:53.460
And you say, it's slowly learn about these options.

00:17:53.460 --> 00:17:58.160
And I think a lot of people out there who are learning Python probably fall into that bracket

00:17:58.160 --> 00:17:58.620
as well.

00:17:58.620 --> 00:18:01.240
Then they're learning it as their first language.

00:18:01.240 --> 00:18:05.040
They're not learning it with people who can guide them how best to use it.

00:18:05.300 --> 00:18:07.040
And it's really hard on your own.

00:18:07.040 --> 00:18:12.380
I mean, we're experienced developers and I think we're finding it really hard ourselves.

00:18:12.380 --> 00:18:12.740
Yeah.

00:18:12.740 --> 00:18:15.280
To do it right and to take full advantage of it, it is.

00:18:15.280 --> 00:18:20.260
So it's cool to have like extensions for the IDE that will sort of not quite be a paired

00:18:20.260 --> 00:18:22.520
program partner, but someone to sort of sit there.

00:18:22.680 --> 00:18:26.780
But you know what, that actually is not the right way to do it, but it's super easy to fix

00:18:26.780 --> 00:18:28.360
and I can take care of that for you, right?

00:18:28.360 --> 00:18:28.740
Exactly.

00:18:28.740 --> 00:18:29.840
Yeah.

00:18:29.840 --> 00:18:31.000
That's exactly what we...

00:18:31.000 --> 00:18:31.720
That's awesome.

00:18:31.720 --> 00:18:37.280
So we talked about code quality and, you know, that's a little bit in the eye of the

00:18:37.280 --> 00:18:37.560
beholder.

00:18:37.560 --> 00:18:38.980
It's also a little bit in the trade-off.

00:18:38.980 --> 00:18:42.940
Like Nick, you talked about this concept of I'm going to write a script and get an answer

00:18:42.940 --> 00:18:44.240
and never run it again, right?

00:18:44.240 --> 00:18:51.020
That has a different threshold for code quality than, you know, the core trading engine at a bank,

00:18:51.020 --> 00:18:52.240
right?

00:18:52.300 --> 00:18:59.200
Like it would probably be improper to put that much energy into that script that's going

00:18:59.200 --> 00:19:00.140
to be run once, right?

00:19:00.140 --> 00:19:03.820
You should just write the thing and get it to work and not worry too much about it.

00:19:03.820 --> 00:19:07.580
But at the same time, if you're building something to be reused and is important, it's going

00:19:07.580 --> 00:19:08.420
to be run by lots of people.

00:19:08.420 --> 00:19:10.280
You really want to get it right.

00:19:10.280 --> 00:19:14.320
And so I think there's this spectrum and people got to like figure out where they live on it.

00:19:14.320 --> 00:19:19.040
But no matter where you live, you would like to have better code quality rather than less

00:19:19.040 --> 00:19:22.240
good code quality by like whatever applies to your situation.

00:19:22.240 --> 00:19:22.520
Right.

00:19:22.520 --> 00:19:23.060
Oh, definitely.

00:19:23.060 --> 00:19:25.360
And it is kind of hard to quantify what code quality is.

00:19:25.360 --> 00:19:29.080
Sometimes, you know, when you see it, I guess it was reading the book Clean Codes.

00:19:29.080 --> 00:19:30.320
I think it's by Bob Martin.

00:19:30.320 --> 00:19:30.980
Robert C. Martin.

00:19:30.980 --> 00:19:31.180
Yeah.

00:19:31.180 --> 00:19:31.480
Yeah.

00:19:31.480 --> 00:19:32.980
I really crystallized it for me.

00:19:32.980 --> 00:19:36.260
And I was always trying to get the graduates at the old company I worked at to read it.

00:19:36.260 --> 00:19:37.580
And eventually one of them stole it.

00:19:37.900 --> 00:19:41.020
So I think, I guess that means they liked it.

00:19:41.020 --> 00:19:41.540
You won.

00:19:41.540 --> 00:19:41.780
Yeah.

00:19:41.780 --> 00:19:43.100
It worked.

00:19:43.100 --> 00:19:45.820
You converted and they stole your book.

00:19:45.820 --> 00:19:50.800
I guess the real core of it is just high quality code is easy to read and understand.

00:19:50.800 --> 00:19:52.360
It just reads like a sort of story.

00:19:52.360 --> 00:19:53.580
Does this and this and this.

00:19:53.580 --> 00:19:53.800
Yeah.

00:19:53.800 --> 00:19:57.800
I really love this idea of clean code and the stuff that Bob Martin talks about.

00:19:57.800 --> 00:19:59.000
He's got some really good ideas.

00:19:59.100 --> 00:20:02.860
I don't totally agree with everything he says, but I think there's a lot of good lessons

00:20:02.860 --> 00:20:04.500
to take from what he's doing.

00:20:04.500 --> 00:20:04.820
Yeah.

00:20:04.820 --> 00:20:05.060
Sure.

00:20:05.060 --> 00:20:05.440
Yeah.

00:20:05.440 --> 00:20:10.780
One of the really interesting ideas that comes from one of his contemporaries, Martin Fowler,

00:20:10.780 --> 00:20:13.560
way back at the origins of refactoring.

00:20:13.560 --> 00:20:20.560
I remember reading the book called Refactoring in 1999 or something like that, just going,

00:20:20.560 --> 00:20:22.080
my mind is blown, right?

00:20:22.080 --> 00:20:27.620
I've had this problem of bad code quality and I've had this problem of trying to write it

00:20:27.620 --> 00:20:28.840
well or to fix it.

00:20:28.840 --> 00:20:32.560
And then I realized, you know, reading what he was talking about, like, oh, there's this

00:20:32.560 --> 00:20:38.100
way to take the bad stuff you've already put down as like sediment in the software.

00:20:38.100 --> 00:20:42.160
It's crystallized and like turn that into something that can be improved and grown over

00:20:42.160 --> 00:20:42.500
time.

00:20:42.500 --> 00:20:47.980
And I just, I remember it really changed my way of thinking about programming, like digging

00:20:47.980 --> 00:20:48.600
into refactoring.

00:20:48.600 --> 00:20:49.880
So I'm just such a huge fan.

00:20:49.880 --> 00:20:51.300
How do you guys come across it?

00:20:51.300 --> 00:20:56.240
It's an interesting one because the code base we worked on our old company was so huge and

00:20:56.240 --> 00:20:57.140
difficult to change.

00:20:57.360 --> 00:20:59.200
Often we didn't even try refactoring it.

00:20:59.200 --> 00:21:01.340
It's just kind of, you did a surgical approach.

00:21:01.340 --> 00:21:04.600
You went in and tried to understand it and made the smaller changes you could.

00:21:04.600 --> 00:21:05.420
Please don't break.

00:21:05.420 --> 00:21:07.500
Just take the new feature without breaking.

00:21:07.500 --> 00:21:12.080
Or I guess, Brendan, you actually sort of took the other approach and said like, okay, I'll

00:21:12.080 --> 00:21:13.640
just rewrite this whole bit.

00:21:13.640 --> 00:21:15.260
Yeah.

00:21:15.520 --> 00:21:21.320
Well, I mean, it was a risky approach given that the system was not under test at all.

00:21:21.320 --> 00:21:25.580
So I would only do that on front end components.

00:21:25.580 --> 00:21:31.420
So the UI, but yeah, sometimes it was, it was just the case of, I don't understand what's

00:21:31.420 --> 00:21:32.140
going on here.

00:21:32.300 --> 00:21:34.980
I can see what the functionality currently is.

00:21:34.980 --> 00:21:37.280
So I'm just going to re-implement it from scratch.

00:21:37.280 --> 00:21:42.900
You know, if people are in that space, like the whole area of what Michael Feathers talked

00:21:42.900 --> 00:21:48.140
about with legacy code and like how to take these, these huge systems that are hard to

00:21:48.140 --> 00:21:49.560
change that you don't necessarily know.

00:21:49.560 --> 00:21:53.400
They don't have tests and how to like break off little bits that are maintainable.

00:21:53.500 --> 00:21:56.080
That's such a cool book working effectively with legacy code.

00:21:56.080 --> 00:22:01.360
I really do enjoy sort of tinkering with code, tracking down bugs, sort of improving it, making

00:22:01.360 --> 00:22:01.840
it a little better.

00:22:01.840 --> 00:22:06.500
I think when I see a blank sheet of paper or blank screen, I kind of sometimes find it difficult

00:22:06.500 --> 00:22:06.940
to start.

00:22:06.940 --> 00:22:08.040
I think Brendan's a bit better at that.

00:22:08.040 --> 00:22:10.720
So I, yeah, I super enjoy refactoring.

00:22:10.720 --> 00:22:16.120
And I guess it's one of the things we're trying to kind of achieve with Sorcery is sort of if

00:22:16.120 --> 00:22:20.840
there's a machine that can do the refactoring for you, you can be less worried about it

00:22:20.840 --> 00:22:23.720
being under test because, you know, it's done proper analysis.

00:22:23.720 --> 00:22:26.640
Because whenever I do refactoring, I break something.

00:22:26.640 --> 00:22:29.040
And I would lean heavily on the tests.

00:22:29.040 --> 00:22:33.940
It's almost never seems like a good idea to me to do a refactoring manually.

00:22:33.940 --> 00:22:39.400
If there's some sort of like tool-based way in which it will happen, right?

00:22:39.400 --> 00:22:42.820
It's just, you never know what little thing you're going to, you're like, oh, there's that

00:22:42.820 --> 00:22:46.280
one, that cron job thing that we had that was also using that.

00:22:46.280 --> 00:22:48.020
Now, apparently it's not going to take it anymore.

00:22:48.020 --> 00:22:50.200
And with, with Python, you don't have compiling, right?

00:22:50.200 --> 00:22:52.420
So you're not going to catch the obvious stuff.

00:22:52.420 --> 00:22:53.960
Like I move this function over here.

00:22:53.960 --> 00:22:55.440
It's just like, well, don't run that part.

00:22:55.440 --> 00:22:56.020
It's going to crash.

00:22:56.020 --> 00:22:58.980
That is one of the challenges with Python.

00:22:58.980 --> 00:23:07.020
And I mean, the way we've approached it with our Sorcery code base is testing and

00:23:07.020 --> 00:23:09.460
mypy type annotations.

00:23:09.460 --> 00:23:09.860
Yeah.

00:23:09.980 --> 00:23:13.660
I think they give enormous confidence when you're refactoring the code.

00:23:13.660 --> 00:23:18.680
So nowadays I don't do crazy refactors, crazy rewrites like that.

00:23:18.680 --> 00:23:23.060
I incrementally improve through small changes.

00:23:23.060 --> 00:23:27.620
But yeah, I've experimented with that once and realized it's not the way to go.

00:23:28.340 --> 00:23:35.700
But yeah, the real key is having those tests and the type annotations.

00:23:35.700 --> 00:23:41.020
You can move something anywhere in the system and you'll get told about all of the errors

00:23:41.020 --> 00:23:42.120
that you now have.

00:23:42.120 --> 00:23:44.460
And then you can go and fix all of those.

00:23:44.460 --> 00:23:49.640
And then you can do the next refactoring and build it up through there.

00:23:49.640 --> 00:23:52.500
Most of our bugs are in the bits we hadn't added mypy to.

00:23:53.000 --> 00:24:00.740
So I totally expected to hear automation from you guys and applying Sorcery back unto itself

00:24:00.740 --> 00:24:01.560
and things like this.

00:24:01.560 --> 00:24:03.540
And we'll dig into the features in a second.

00:24:03.540 --> 00:24:06.700
But I didn't expect to hear typing in mypy.

00:24:06.700 --> 00:24:09.800
I'm personally a huge fan of the type annotations in Python.

00:24:09.800 --> 00:24:13.940
I think they make working with Python code so much easier.

00:24:13.940 --> 00:24:20.460
You don't annotate everything, but certain places like this function returns one of these,

00:24:20.460 --> 00:24:22.960
just knowing like actually it expects to return one of these.

00:24:22.960 --> 00:24:26.340
It's super helpful and it'll light up the editors as well, right?

00:24:26.340 --> 00:24:29.840
They can all of a sudden give you autocomplete for what they weren't sure before.

00:24:29.840 --> 00:24:32.860
But now they know, oh, here's the five things you can do with what you got back.

00:24:32.860 --> 00:24:33.160
Perfect.

00:24:33.160 --> 00:24:36.200
How does mypy fit into your world?

00:24:36.200 --> 00:24:37.300
I think that's pretty interesting.

00:24:37.300 --> 00:24:38.240
What are you doing with that?

00:24:38.240 --> 00:24:43.620
We really only use it internally because most code out there doesn't actually have mypy

00:24:43.620 --> 00:24:45.460
or type annotations.

00:24:45.460 --> 00:24:45.740
Right.

00:24:45.740 --> 00:24:51.220
Even if it has some type annotations, there's like sort of a chain of annotations that have

00:24:51.220 --> 00:24:51.960
to be consistent.

00:24:52.200 --> 00:24:56.000
Like mypy is a stronger level than just saying, oh, this function happens to return a list.

00:24:56.000 --> 00:24:56.400
Yeah.

00:24:56.400 --> 00:25:02.960
I mean, one of the great things about type annotations is you can just look at a function

00:25:02.960 --> 00:25:06.580
at the definition of it and understand the interface.

00:25:06.580 --> 00:25:08.540
You don't need to read the code.

00:25:08.540 --> 00:25:13.340
Without those type annotations, you have to actually read the code and say, oh, actually

00:25:13.340 --> 00:25:19.460
this is a string and this is an integer and it returns a list of integers or something

00:25:19.460 --> 00:25:19.960
like that.

00:25:19.960 --> 00:25:20.160
Yeah.

00:25:20.160 --> 00:25:21.400
With the type annotations.

00:25:21.400 --> 00:25:21.800
Yeah.

00:25:21.800 --> 00:25:22.600
That's a really good point.

00:25:22.600 --> 00:25:23.600
I like that.

00:25:23.600 --> 00:25:27.160
So I think type annotations are a form of documentation.

00:25:27.660 --> 00:25:32.060
They're really, really powerful just from a readability point of view.

00:25:32.120 --> 00:25:37.840
But then you get all of the security as well of knowing when you've broken the code or when

00:25:37.840 --> 00:25:39.440
you've not called something correctly.

00:25:39.440 --> 00:25:45.880
One of the things that is really important to us with Sorcery is that we never break other

00:25:45.880 --> 00:25:46.760
people's code.

00:25:46.760 --> 00:25:50.000
So we have to have extremely strong gar...

00:25:50.000 --> 00:25:50.200
Yeah.

00:25:50.200 --> 00:25:54.380
So let's take a step back and why don't you tell people about what Sorcery is?

00:25:54.380 --> 00:25:55.560
How do people use it?

00:25:55.560 --> 00:25:59.160
So you mentioned that it's a plugin for IDEs, but give us a little bit more detail and then

00:25:59.160 --> 00:26:03.240
we can talk about how you keep from breaking people's code, which is probably...

00:26:03.240 --> 00:26:04.460
People probably appreciate that.

00:26:04.460 --> 00:26:06.900
If you...

00:26:06.900 --> 00:26:09.660
It acts as a plugin to your IDE.

00:26:09.660 --> 00:26:13.060
So we've got plugins for VS Code and PyCharm.

00:26:13.060 --> 00:26:18.640
And as you're coding away, it sits there reading your code and analyzing it.

00:26:18.640 --> 00:26:26.140
And if it identifies a change to a function that you're working on that will improve the

00:26:26.140 --> 00:26:28.420
code quality, it'll suggest it to you.

00:26:28.420 --> 00:26:30.840
And you can review that suggestion.

00:26:30.840 --> 00:26:33.940
And if you like it, you can accept it.

00:26:33.940 --> 00:26:35.780
And it'll apply that change in line.

00:26:35.780 --> 00:26:39.000
And you carry on coding it.

00:26:39.000 --> 00:26:41.940
It works almost seamlessly in your workflow.

00:26:41.940 --> 00:26:42.460
Okay.

00:26:42.460 --> 00:26:43.500
That sounds awesome.

00:26:43.500 --> 00:26:46.920
Does it change the way the editors work in other ways?

00:26:46.920 --> 00:26:51.400
Like, for example, does it change the autocomplete or things like that?

00:26:51.400 --> 00:26:56.300
Or is it really more like the code intentions, like the little light bulb in PyCharm?

00:26:56.300 --> 00:26:58.660
Yeah, it's kind of exactly like a code intention in PyCharm.

00:26:58.660 --> 00:27:00.900
That's kind of the thing we've gone with.

00:27:00.900 --> 00:27:01.200
Yeah.

00:27:01.200 --> 00:27:02.740
So yeah, it does a little underline.

00:27:02.740 --> 00:27:02.960
Cool.

00:27:02.960 --> 00:27:04.780
So as you're going along, you're watching...

00:27:04.780 --> 00:27:05.820
Oh, there's a little pop-up.

00:27:05.820 --> 00:27:07.040
I should go see what this is about.

00:27:07.040 --> 00:27:07.660
Yeah, yeah, exactly.

00:27:08.280 --> 00:27:09.780
And it runs locally on your machine.

00:27:09.780 --> 00:27:11.600
I guess that was quite a sort of concern for people.

00:27:11.600 --> 00:27:13.200
They didn't want their code being sent to the cloud.

00:27:13.200 --> 00:27:14.160
I can't imagine why.

00:27:14.160 --> 00:27:20.280
So when we first started it, we were going to do it kind of as a service in the cloud.

00:27:20.280 --> 00:27:23.820
And we kind of had to do a pivot and get it running locally on the machine.

00:27:23.820 --> 00:27:24.100
Okay.

00:27:24.100 --> 00:27:28.820
So somehow behind this, how does it make decisions about refactorings?

00:27:28.820 --> 00:27:32.000
Is it like an AI-based thing?

00:27:32.000 --> 00:27:32.920
Is it pattern matching?

00:27:32.920 --> 00:27:34.660
Like, what is it doing inside?

00:27:34.880 --> 00:27:39.560
So at the moment, there's no machine learning or AI in it.

00:27:39.560 --> 00:27:43.360
The way it works is it is essentially pattern matching.

00:27:43.360 --> 00:27:44.800
So it's looking for...

00:27:44.800 --> 00:27:48.420
Well, it works at the level of the abstract syntax tree.

00:27:48.800 --> 00:27:53.080
So it takes the code and it parses it into a data structure.

00:27:53.080 --> 00:27:58.460
And that data structure will have, for instance, an if node.

00:27:58.460 --> 00:28:03.220
And within that if node, it will have a function call.

00:28:03.980 --> 00:28:07.140
And the if node will also have a list of statements.

00:28:07.140 --> 00:28:12.280
It looks at those nodes and it looks for the patterns, like you say.

00:28:12.280 --> 00:28:20.280
So, for instance, it might look for a for loop that has an if statement within it that appends to a list.

00:28:20.280 --> 00:28:22.840
And then it says, okay.

00:28:22.840 --> 00:28:25.420
Like, that's a list comprehension waiting to be made right there.

00:28:25.420 --> 00:28:25.860
Yeah.

00:28:26.080 --> 00:28:26.480
Exactly.

00:28:26.480 --> 00:28:33.140
And I guess the clever bit is it kind of has these little, lots of little tiny little patterns of improvements it can do.

00:28:33.140 --> 00:28:36.280
But it can compose those together into like a bigger refactoring.

00:28:36.280 --> 00:28:40.880
And it's guided by a load of code metrics we've kind of incorporated into it.

00:28:40.880 --> 00:28:41.940
So we can get into those later.

00:28:41.940 --> 00:28:45.460
Like cyclomatic complexity and some of those types of things?

00:28:45.460 --> 00:28:45.860
Yeah.

00:28:45.860 --> 00:28:46.140
Yeah.

00:28:46.140 --> 00:28:48.500
So we don't use cyclomatic.

00:28:48.500 --> 00:28:52.860
We do use cognitive complexity, which I think is like a trademark of SonarCube or something.

00:28:52.860 --> 00:28:54.340
But it's a different metric.

00:28:54.340 --> 00:28:56.000
And we use a few we've written ourselves.

00:28:56.000 --> 00:29:00.380
And so it can kind of chain together little refactorings to do something bigger.

00:29:00.380 --> 00:29:06.460
So, for example, on the, I don't know if you've seen the Gilded Rose refactoring CARTA.

00:29:06.460 --> 00:29:07.580
No, tell people about it.

00:29:07.580 --> 00:29:11.220
So it's kind of this big fantasy.

00:29:11.220 --> 00:29:12.640
Wait, let's take a step back.

00:29:12.640 --> 00:29:13.260
What's a CARTA?

00:29:13.260 --> 00:29:17.840
So a coding CARTA is a coding exercise to improve your programming.

00:29:17.840 --> 00:29:18.420
Right, right.

00:29:18.420 --> 00:29:20.240
And there are various ones of these floating around the internet.

00:29:20.240 --> 00:29:24.720
And Gilded Rose is like this big, complicated set of nested ifs, basically.

00:29:24.720 --> 00:29:28.340
And it's sort of about this fantasy in, I think.

00:29:28.340 --> 00:29:33.420
And it takes maybe an hour to kind of manually sort the code out and refactor it.

00:29:33.420 --> 00:29:34.900
And it's sort of an exercise people do.

00:29:34.900 --> 00:29:39.760
And our aim when we started Sorcery was to, this was like our initial target problem.

00:29:40.360 --> 00:29:45.560
So it can kind of do all that work at once by chaining together lots of little refactorings.

00:29:45.560 --> 00:29:51.620
So it can take the sort of complex mess of spaghetti code and then turn it into something understandable.

00:29:51.620 --> 00:29:52.100
Right.

00:29:52.100 --> 00:30:01.920
Instead of having to say, okay, here's a little if statement that could be improved and then apply it again and say, well, now that we have this code, there's another thing we can improve than apply it again.

00:30:02.020 --> 00:30:05.760
It'll like chain those all together and go, actually, we could roll this all up.

00:30:05.760 --> 00:30:06.120
Exactly.

00:30:06.120 --> 00:30:06.520
Yeah.

00:30:06.520 --> 00:30:08.860
Because when you're doing manual refactoring, that's kind of what often happens.

00:30:08.860 --> 00:30:11.780
You sort of do a little thing and then you realize, oh, now I can do this.

00:30:11.780 --> 00:30:14.000
And you might have an aim in mind or you might not.

00:30:14.000 --> 00:30:16.440
And then you start chaining these things together.

00:30:16.440 --> 00:30:19.080
And in the end, you're like, oh, now it's an understandable code base.

00:30:19.080 --> 00:30:19.780
Yeah.

00:30:19.780 --> 00:30:20.480
Yeah.

00:30:20.480 --> 00:30:21.060
Very cool.

00:30:21.060 --> 00:30:23.120
Well, that sounds super, super useful.

00:30:23.120 --> 00:30:31.820
I know that some refactorings build into certain tools like PyCharm has certain refactorings, but they don't seem to take this more holistic approach.

00:30:31.820 --> 00:30:32.240
Right.

00:30:32.240 --> 00:30:37.120
They're like, oh, this list, this list comprehension could be expanded to a for loop if you need it or something like that.

00:30:37.120 --> 00:30:38.840
But that's kind of as far as it goes.

00:30:38.840 --> 00:30:39.120
Yeah.

00:30:39.120 --> 00:30:40.400
And they're kind of very developer driven.

00:30:40.400 --> 00:30:41.800
You have to know you want to do them.

00:30:41.800 --> 00:30:42.340
Yeah.

00:30:42.340 --> 00:30:44.360
And you have to know where you can do them and then you have to do them.

00:30:44.360 --> 00:30:47.480
So they're very useful if you know you want to do something because it'll do it for you.

00:30:47.480 --> 00:30:52.820
And like, it won't make mistakes, but they don't sort of, they don't tell you if it's a good idea or not.

00:30:52.820 --> 00:30:58.100
So our idea is we're kind of suggesting things that we think are good ideas to actually change.

00:30:58.100 --> 00:31:01.920
This portion of Talk Python To Me is brought to you by Linode.

00:31:01.920 --> 00:31:10.880
Whether you're working on a personal project or managing your enterprise's infrastructure, Linode has the pricing, support, and scale that you need to take your project to the next level.

00:31:10.880 --> 00:31:21.380
With 11 data centers worldwide, including their newest data center in Sydney, Australia, enterprise grade hardware, S3 compatible storage, and the next generation network.

00:31:21.380 --> 00:31:25.540
Linode delivers the performance that you expect at a price that you don't.

00:31:25.940 --> 00:31:41.580
Get started on Linode today with a $20 credit and you get access to native SSD storage, a 40 gigabit network, industry-leading processors, their revamped cloud manager at cloud.linode.com, root access to your server, along with their newest API and a Python CLI.

00:31:41.580 --> 00:31:49.600
Just visit talkpython.fm/Linode when creating a new Linode account and you'll automatically get $20 credit for your next project.

00:31:50.100 --> 00:31:50.900
Oh, and one last thing.

00:31:50.900 --> 00:31:51.660
They're hiring.

00:31:51.660 --> 00:31:54.780
Go to linode.com slash careers to find out more.

00:31:54.780 --> 00:31:56.100
Let them know that we sent you.

00:31:56.100 --> 00:32:02.960
Let me share one of my favorite concepts from refactoring and then ask you about some of your favorite refactorings.

00:32:02.960 --> 00:32:10.540
So there's all these different refactorings, even in the early days that Mark Fowler talked about, like, okay, there's a God object and here's how you break it down.

00:32:10.540 --> 00:32:12.200
Or there's a function that's too long.

00:32:12.200 --> 00:32:13.460
Here's what you do and so on.

00:32:13.460 --> 00:32:15.200
But those are all kind of interesting.

00:32:15.400 --> 00:32:20.120
Like, the most interesting concept around all that stuff to me was the concept of a code smell.

00:32:20.120 --> 00:32:20.860
Right?

00:32:20.860 --> 00:32:24.380
Just like, there's something wrong with this.

00:32:24.380 --> 00:32:28.100
Like, it works, but your nose kind of turns up when you look at it.

00:32:28.100 --> 00:32:33.500
You're like, there's something wrong with this part of my code or code probably I inherited from somebody else.

00:32:33.500 --> 00:32:33.780
Right?

00:32:34.640 --> 00:32:45.120
And the other thing was he would talk about comments and say, often comments have value, but a lot of times they're really just deodorant for these code smells.

00:32:45.120 --> 00:32:47.620
Like, this is really hard to understand because it's written badly.

00:32:47.620 --> 00:32:51.080
So let me write a comment that tells people what it really means.

00:32:51.080 --> 00:32:51.420
Yeah.

00:32:51.420 --> 00:32:53.040
And then just leave the bad stuff there.

00:32:53.040 --> 00:32:53.220
Right?

00:32:53.220 --> 00:32:55.440
It kind of deodorizes the code smell a little bit.

00:32:55.580 --> 00:33:03.020
And that's this idea of, like, if you have those comments, it's like this underlying thing of, like, you should start thinking of applying these different refactorings.

00:33:03.420 --> 00:33:14.800
So my question to you with, like, sort of putting that out there is, what are some of the favorite refactorings that you guys are seeing possible with, like, this deeper integration, right?

00:33:14.800 --> 00:33:18.960
Like, obviously, for loop to Liz comprehension, Liz comprehension to for loop.

00:33:18.960 --> 00:33:26.740
Like, those are pretty straightforward, but it sounds like there might be either things you just really love or there might be, like, some more interesting, larger refactorings.

00:33:26.740 --> 00:33:34.580
The main code smell that I think Sorcery does really well with is eliminating duplicate code within a function.

00:33:34.580 --> 00:33:41.700
And in particular, within different branches of a complicated set of if expressions.

00:33:41.700 --> 00:33:46.660
So you may have the same body of code in two different places.

00:33:46.660 --> 00:33:54.320
And Sorcery can restructure the code until there's just a single condition that applies for that block of code.

00:33:54.320 --> 00:33:54.900
That's cool.

00:33:54.900 --> 00:33:57.660
Yeah, I think that lets me delete lines of code is always very pleasing.

00:33:57.660 --> 00:33:58.340
So, yeah.

00:33:58.340 --> 00:33:59.100
Yeah, yeah.

00:33:59.100 --> 00:34:03.480
And delete conditionals as well, right, if possible, or simplify them.

00:34:03.480 --> 00:34:08.940
You know, I feel like the more the word legacy gets applied to a code base, the less you want to do those kinds of things.

00:34:08.940 --> 00:34:17.160
You're like, I'm pretty sure these three things are the same, but I don't want to be responsible for what happens if I misunderstand that these are actually slightly different.

00:34:17.160 --> 00:34:19.240
And try to refactor it to a cleaner version.

00:34:19.240 --> 00:34:22.880
So as much as you can get software, does you go, actually, no, this is totally safe.

00:34:22.880 --> 00:34:23.400
We got you.

00:34:23.900 --> 00:34:35.200
It's actually quite interesting because one of the things that has happened is we've suggested refactorings to people and they've gone, this is incorrect.

00:34:35.660 --> 00:34:42.320
And there's been these examples of eliminating duplicate code and simplifying if expression.

00:34:42.320 --> 00:34:43.960
It's kind of once you work through the logic.

00:34:43.960 --> 00:34:44.400
Yeah.

00:34:44.400 --> 00:34:48.740
We've discovered actually sorcery is correct here.

00:34:49.080 --> 00:34:56.300
And it turns out your code was either very confusing or possibly had a bug in it, which you have now identified.

00:34:56.300 --> 00:34:57.020
Right, right.

00:34:57.020 --> 00:35:00.380
You thought these two things were doing different stuff, but in fact, it has no...

00:35:00.380 --> 00:35:05.160
The effect of this is not what you had in your mind its actual effect being, right?

00:35:05.160 --> 00:35:05.680
Yeah.

00:35:05.680 --> 00:35:13.540
You misunderstood what was actually happening and your mental model didn't match the refactoring result, but that's because it wasn't actually doing that.

00:35:13.660 --> 00:35:14.080
Exactly.

00:35:14.080 --> 00:35:20.940
And so actually, once it's done that refactoring, you can say, oh, actually, there is a bug in my code.

00:35:20.940 --> 00:35:22.520
I can fix it.

00:35:22.960 --> 00:35:30.140
But you have to have the trust in sorcery to know that it's correct before you're willing to take that step.

00:35:30.140 --> 00:35:33.520
So it takes a little bit of usage to build up that trust.

00:35:33.520 --> 00:35:37.460
So how do you guys check that your refactorings are valid?

00:35:37.460 --> 00:35:47.060
So like we said, we have a library of smaller refactorings, and then we have a search engine that composes those together.

00:35:47.060 --> 00:35:53.020
So the important thing is making sure each of those individual refactorings in the library is correct.

00:35:53.020 --> 00:35:53.560
Right, right.

00:35:53.560 --> 00:35:56.940
Because composing a bunch of things that are correct is not going to break anything.

00:35:56.940 --> 00:35:57.540
Exactly.

00:35:57.540 --> 00:35:58.240
Yeah.

00:35:58.240 --> 00:36:03.420
So the challenge is to try and make sure that those individual ones are correct.

00:36:04.200 --> 00:36:09.660
So we have lots and lots of tests, and those tests are of the form.

00:36:09.660 --> 00:36:15.520
Here is a piece of source code, and here is the expected refactored source code.

00:36:15.520 --> 00:36:18.940
And for each refactoring, there's a multitude of those.

00:36:18.940 --> 00:36:22.620
But there's also a multitude of tests of the form.

00:36:22.620 --> 00:36:27.960
Here's a piece of source code that looks similar to these other bits that you have refactored,

00:36:27.960 --> 00:36:34.860
but you shouldn't refactor it because if you do refactor it, or if you do make the change, you'll break the code.

00:36:34.860 --> 00:36:37.180
There's got some gotcha in there, yeah.

00:36:37.180 --> 00:36:38.760
It's not a true refactoring.

00:36:38.760 --> 00:36:45.420
And it will tend to be things like you're calling a function, and so you can't swap these statements

00:36:45.420 --> 00:36:48.260
because one of them is actually a global variable.

00:36:48.920 --> 00:36:57.500
So we have an awful lot of analysis, which determines what statements in a function depend on the other statements.

00:36:57.500 --> 00:36:58.340
Yeah, it sounds interesting.

00:36:58.340 --> 00:37:01.500
It turns out to be the hardest problem that we've tried to solve.

00:37:01.500 --> 00:37:02.740
I can imagine.

00:37:02.740 --> 00:37:06.800
Have you guys looked at using things like hypothesis or other property-based testing,

00:37:06.800 --> 00:37:11.680
where it's like, here's a block of code, apply refactoring to it,

00:37:11.680 --> 00:37:16.260
feed it a bunch of inputs to both versions, and see if as long as you get the same outputs,

00:37:16.260 --> 00:37:17.680
or things like that?

00:37:17.680 --> 00:37:20.480
That's a future plan that we have.

00:37:20.480 --> 00:37:23.240
We do have a second form of testing that we do at the moment,

00:37:23.240 --> 00:37:26.340
which is, as part of our build process,

00:37:26.340 --> 00:37:33.380
we run Sorcery over a whole bunch of popular open source libraries and refactor them.

00:37:33.380 --> 00:37:39.220
And then once they've been refactored, we run their tests over themselves

00:37:39.220 --> 00:37:42.820
to check that we haven't broken any of their code.

00:37:42.820 --> 00:37:48.600
Because people have already written a ton of tests for SQLAlchemy, for requests or whatever, right?

00:37:48.600 --> 00:37:49.080
Exactly.

00:37:49.080 --> 00:37:55.760
So, I mean, that has identified, I mean, when we first introduced it, identified lots of issues.

00:37:55.760 --> 00:38:02.020
And since then, it's stopped us releasing any new bugs as far as we're aware.

00:38:02.020 --> 00:38:07.080
That sounds like a pretty good way to just hit it with enough information that it's going to get caught in the issues.

00:38:07.080 --> 00:38:11.580
Have you found errors in other libraries because of this and gotten back to them?

00:38:11.580 --> 00:38:12.540
Like, you know what?

00:38:12.540 --> 00:38:17.320
This is actually, we thought our stuff was broken, but actually your stuff is broken.

00:38:17.320 --> 00:38:19.220
I mean, that'd be cool.

00:38:19.480 --> 00:38:22.240
I mean, sometimes the tests are failing in master.

00:38:22.240 --> 00:38:28.440
So after a while, we just decided to pick a tag and stick with it and be done with it.

00:38:28.440 --> 00:38:33.920
But actually, we found that there's just a lot of backcode to review.

00:38:33.920 --> 00:38:37.360
So we tend not to review it at the moment.

00:38:37.360 --> 00:38:42.120
Yeah, it's not your job to check all open source libraries for correctness, right?

00:38:42.120 --> 00:38:42.820
Exactly.

00:38:43.200 --> 00:38:48.940
And some of the libraries like SQLAlchemy that we do run it on are absolutely enormous.

00:38:48.940 --> 00:38:54.380
There's hundreds of files and multiple drivers for different database backends.

00:38:54.380 --> 00:38:57.300
So it takes a long time to run those tests.

00:38:57.300 --> 00:38:57.620
Yeah.

00:38:57.620 --> 00:38:58.000
Yeah.

00:38:58.000 --> 00:39:01.880
We just rely on the test to tell us whether we're good to release or not.

00:39:01.880 --> 00:39:02.440
Yeah, that's cool.

00:39:02.440 --> 00:39:08.960
But yeah, the hypothesis-based testing is a very interesting idea that we have talked about.

00:39:09.360 --> 00:39:14.420
So the way we were considering doing it was exactly how you talked about.

00:39:14.420 --> 00:39:21.400
You write a piece of code and then you put some inputs and you check what the output is.

00:39:21.400 --> 00:39:23.280
And then you run Sorcery over it.

00:39:23.280 --> 00:39:29.920
And the way we were going to do it is actually also write a generator for source code that takes

00:39:29.920 --> 00:39:35.240
maybe an initial piece of code and does random mutations to it to start off with.

00:39:35.240 --> 00:39:38.760
So here's a piece of code that Sorcery should refactor.

00:39:38.760 --> 00:39:46.260
Let's apply a bunch of random mutations to it and then run Sorcery over it.

00:39:46.260 --> 00:39:48.440
Check the inputs and outputs are the same again.

00:39:48.440 --> 00:39:53.600
So yeah, the generator for that would have been quite interesting to write.

00:39:53.600 --> 00:39:56.040
And it is something that we're considering in the future.

00:39:56.040 --> 00:39:56.440
Okay.

00:39:56.440 --> 00:39:57.400
Yeah, it sounds cool.

00:39:57.400 --> 00:40:00.600
It sounds like it would take forever to run, but it sounds like a cool project.

00:40:00.600 --> 00:40:03.520
Maybe don't run it on every save.

00:40:03.520 --> 00:40:04.800
All right.

00:40:04.800 --> 00:40:06.160
Well, let's see.

00:40:06.160 --> 00:40:10.320
There's a bunch of things I want to ask you about, but I don't want to go over too much

00:40:10.320 --> 00:40:10.680
on time.

00:40:10.680 --> 00:40:16.180
So I guess one area that looks interesting to me is we've talked about this being a plugin

00:40:16.180 --> 00:40:17.760
for an editor that's interactive.

00:40:17.760 --> 00:40:21.840
You also talk about just applying it to open source libraries.

00:40:21.840 --> 00:40:28.520
And on the Sorcery homepage, I see that there's a get instant quality of your Python code base,

00:40:28.520 --> 00:40:31.460
like just point it at your repo and it'll give you some answers.

00:40:31.460 --> 00:40:34.480
So is there more stuff that it does than just be a plugin?

00:40:34.480 --> 00:40:35.240
Yeah.

00:40:35.240 --> 00:40:38.040
Or is there like a CLI way to use it?

00:40:38.040 --> 00:40:40.820
So it is also available as a GitHub bot.

00:40:41.160 --> 00:40:48.300
So you install the Sorcery bot into your GitHub repo.

00:40:48.300 --> 00:40:53.740
And every time you do a pull request, Sorcery will review that pull request.

00:40:53.740 --> 00:41:00.100
And if it finds any improvements to any of the files that have been touched by the pull request,

00:41:00.100 --> 00:41:05.980
then it will create a pull request on top of that saying, here's the changes that you can make.

00:41:05.980 --> 00:41:07.120
An improvement to it.

00:41:07.120 --> 00:41:07.280
Yeah.

00:41:07.280 --> 00:41:10.980
Then you can just merge that pull request in straight away.

00:41:10.980 --> 00:41:15.680
When you first install it, also it can refactor the whole library kind of all at once.

00:41:15.680 --> 00:41:16.140
Very cool.

00:41:16.140 --> 00:41:17.000
All right.

00:41:17.000 --> 00:41:19.220
So let's talk about pricing.

00:41:19.220 --> 00:41:24.100
So this is something that is free for some people, but it's not free for some other people.

00:41:24.760 --> 00:41:28.120
What's the story with the whole business model, open source side of things?

00:41:28.120 --> 00:41:30.720
Like what is, what are you guys offering here?

00:41:30.720 --> 00:41:36.680
Because it sounds really useful to a lot of people, but at the same time, you are charging some folks for it.

00:41:36.680 --> 00:41:40.080
So that might, you know, that might influence people's opinion on how they feel about it.

00:41:40.080 --> 00:41:40.260
Yeah.

00:41:40.260 --> 00:41:43.080
So the plugins are free at the moment.

00:41:43.080 --> 00:41:46.840
We think in the future, we'll probably introduce a premium version and still have a free version.

00:41:46.980 --> 00:41:47.180
I see.

00:41:47.180 --> 00:41:52.360
So if I'm sitting here and I want to write code on my MacBook on PyCharm, I can just go get it for free.

00:41:52.360 --> 00:41:53.420
I don't have to pay anything.

00:41:53.420 --> 00:41:53.580
Yeah.

00:41:53.580 --> 00:41:55.320
You can just go get it for free right now and not pay anything.

00:41:55.320 --> 00:41:58.220
And that's whether you're open source or closed source or anything.

00:41:58.220 --> 00:41:59.740
I could be working for a bank even, huh?

00:41:59.740 --> 00:42:00.160
You could.

00:42:00.160 --> 00:42:03.820
We have had users from banks working on it or using it.

00:42:03.820 --> 00:42:04.240
So yeah.

00:42:04.240 --> 00:42:04.720
Right on.

00:42:04.720 --> 00:42:08.460
But there is some business model where you guys charge money for something.

00:42:08.460 --> 00:42:10.500
So what are you, what is that side of the things?

00:42:10.500 --> 00:42:10.740
Yes.

00:42:10.740 --> 00:42:13.780
So for the code review, it's free for open source again.

00:42:13.780 --> 00:42:18.460
But if you want to use it on a closed source repository, there's a small charge per developer

00:42:18.460 --> 00:42:19.480
per month, basically.

00:42:19.480 --> 00:42:23.580
And that's something we've only just released in the last few days, basically.

00:42:23.580 --> 00:42:24.060
All right.

00:42:24.060 --> 00:42:24.320
Cool.

00:42:24.320 --> 00:42:30.680
So basically, if I'm going to apply it to my code base as a autonomous bot type of thing

00:42:30.680 --> 00:42:33.340
and I'm open source, it's 100% free.

00:42:33.340 --> 00:42:33.960
Right.

00:42:33.960 --> 00:42:38.820
So if I was taking care of requests or SQLAlchemy or Flask or whatever, I could just plug it

00:42:38.820 --> 00:42:40.160
into the Flask repo on GitHub.

00:42:40.160 --> 00:42:45.160
And all of a sudden it would solve those problems of like, you didn't seriously just give me

00:42:45.160 --> 00:42:46.960
a four loop that depends to a list, did you?

00:42:46.960 --> 00:42:48.100
Right.

00:42:48.100 --> 00:42:49.280
Yeah, exactly.

00:42:49.280 --> 00:42:50.740
So yeah.

00:42:50.740 --> 00:42:57.360
Particularly useful for people maintaining large open source libraries because they'll get a

00:42:57.360 --> 00:43:00.000
lot of pull requests and they may come in at various standards.

00:43:00.000 --> 00:43:05.080
So it does the initial code review for the maintainer of the project.

00:43:05.080 --> 00:43:07.220
There's another way of trying it out.

00:43:07.400 --> 00:43:16.540
If you have a GitHub account and that is simply to star our public repo and the GitHub bot,

00:43:16.540 --> 00:43:23.440
our GitHub bot will find your most popular Python repository and send you a pull request

00:43:23.440 --> 00:43:26.040
to refactor your code base.

00:43:26.400 --> 00:43:30.120
So it's as simple as click a star and you'll get a pull request.

00:43:30.120 --> 00:43:30.500
Oh wow.

00:43:30.500 --> 00:43:31.080
Okay, cool.

00:43:31.080 --> 00:43:32.240
Yeah.

00:43:32.240 --> 00:43:38.180
I mean, it seems to me really useful to have it just built into GitHub automatically looking

00:43:38.180 --> 00:43:40.200
over the code because I don't know.

00:43:40.240 --> 00:43:43.880
You all have worked with different groups of people at different companies, different languages.

00:43:43.880 --> 00:43:49.960
My experience has been that people that care about code quality and refactoring and testing

00:43:49.960 --> 00:43:53.720
and maintainability and patterns and all that kind of stuff.

00:43:53.720 --> 00:43:57.140
There's a massive spectrum on any given team.

00:43:57.140 --> 00:44:00.700
Some people, it really matters to them and others.

00:44:01.240 --> 00:44:04.200
Those failing tests and that failing build is just a nuisance.

00:44:04.200 --> 00:44:07.080
And how do I turn off the build so I don't have to hear about it again?

00:44:07.080 --> 00:44:07.820
Right?

00:44:07.820 --> 00:44:15.500
And so having it as part of the repo means that I get kind of applies to everyone.

00:44:15.500 --> 00:44:17.000
At least it suggests for everyone.

00:44:17.000 --> 00:44:22.380
Whereas if it's just in the editor, there's going to be the people who love it and the people who just

00:44:22.380 --> 00:44:24.460
like, how do I uninstall this or disable this?

00:44:24.460 --> 00:44:28.240
So it doesn't, because it's just, I wrote my code and I don't want it to, you know what I mean?

00:44:28.240 --> 00:44:31.200
Like there's just, it doesn't matter how much advocacy there is.

00:44:31.200 --> 00:44:31.940
There's going to be that.

00:44:31.940 --> 00:44:33.820
And so having that kind of external is pretty cool.

00:44:33.820 --> 00:44:34.040
Yeah.

00:44:34.040 --> 00:44:37.980
Like we started doing in the editor because we thought that was kind of the way to really

00:44:37.980 --> 00:44:42.760
make you write code faster and kind of you hack it a bit and it straight away does the change.

00:44:42.760 --> 00:44:47.700
But like you're saying, definitely that's why we introduced the GitHub plugin because the

00:44:47.700 --> 00:44:51.200
code review, because not everyone's at the same level.

00:44:51.200 --> 00:44:53.040
It kind of brings things up to a level.

00:44:53.040 --> 00:44:53.360
Yeah.

00:44:53.360 --> 00:44:57.400
So it's got, it gives you the benefit as a beginner programmer in the team.

00:44:57.700 --> 00:45:03.100
So you get those code reviews, but also as the experienced developer, it saves you time

00:45:03.100 --> 00:45:08.580
doing the code review because there's already a tool doing the simple steps.

00:45:08.580 --> 00:45:13.920
It's not dealing with the architectural elements of it, but it's making sure each function is

00:45:13.920 --> 00:45:14.580
nicely written.

00:45:14.580 --> 00:45:14.900
Yeah.

00:45:14.900 --> 00:45:18.340
I think that makes a lot of sense because it doesn't matter how good you are.

00:45:18.340 --> 00:45:21.780
You don't want to have to go think of the implications throughout the whole code base.

00:45:21.780 --> 00:45:22.340
Absolutely.

00:45:22.340 --> 00:45:24.340
And we're just looking to say the tool set is good.

00:45:24.340 --> 00:45:24.980
So it's good.

00:45:26.420 --> 00:45:27.240
Press merge.

00:45:27.240 --> 00:45:28.360
Yeah.

00:45:28.360 --> 00:45:28.960
Beautiful.

00:45:28.960 --> 00:45:33.020
But I do think it's really important that it's an editor because it teaches you, maybe it

00:45:33.020 --> 00:45:33.420
could teach you.

00:45:33.420 --> 00:45:36.280
It teaches you the idiomatic, the Pythonic ways of writing things.

00:45:36.280 --> 00:45:41.260
You're like, I had no idea that I could create a for loop with enum that had tuple unpacking

00:45:41.260 --> 00:45:46.580
instead of like trying to do a for over range and then pulling out the item and things like

00:45:46.580 --> 00:45:46.820
that.

00:45:46.820 --> 00:45:49.060
So it seems like a really cool combination.

00:45:49.060 --> 00:45:49.360
Yeah.

00:45:49.360 --> 00:45:52.140
I think definitely that educational thing is something we want to focus on more, like improving

00:45:52.140 --> 00:45:52.780
our documentation.

00:45:53.140 --> 00:45:56.380
So I wrote a blog post recently with a few little refactorings.

00:45:56.380 --> 00:45:59.420
We're doing like why we think they're a good idea as opposed to just what we've done.

00:45:59.420 --> 00:46:02.280
Is it the one that is called Python refactorings part one?

00:46:02.280 --> 00:46:02.520
Yeah.

00:46:02.520 --> 00:46:02.780
Yeah.

00:46:02.780 --> 00:46:02.920
Yeah.

00:46:02.920 --> 00:46:03.460
I looked through that.

00:46:03.460 --> 00:46:07.280
So maybe you could give us a couple of the refactorings out of there that you like.

00:46:07.280 --> 00:46:11.940
Code hoisting is like one of the best things because anytime you've got duplicate code,

00:46:11.940 --> 00:46:14.340
you've got a way you can introduce mistakes really easily.

00:46:14.440 --> 00:46:18.200
So that would be like maybe you have the same code in an if and an else statement.

00:46:18.200 --> 00:46:18.620
Yes.

00:46:18.620 --> 00:46:19.740
And it's just duplicated.

00:46:19.740 --> 00:46:24.700
So often people will write sort of a bit at the end of the same thing in the if and the

00:46:24.700 --> 00:46:28.420
else or in loads of elifs even maybe because it happens in every branch.

00:46:28.420 --> 00:46:29.520
It means it always happens.

00:46:29.520 --> 00:46:31.360
So it doesn't actually need to be in the condition at all.

00:46:31.360 --> 00:46:32.940
And if you take it out.

00:46:32.940 --> 00:46:33.320
Exactly.

00:46:33.320 --> 00:46:34.040
Just put it at the end.

00:46:34.040 --> 00:46:37.460
It also becomes kind of more clear what the conditional is doing, what it's controlling,

00:46:37.460 --> 00:46:39.780
because it hasn't got this extraneous thing in it.

00:46:39.880 --> 00:46:45.520
Another one you have in there is converting from a for loop, which does a yield to a yield

00:46:45.520 --> 00:46:48.580
from that collection directly, which is pretty nice.

00:46:48.580 --> 00:46:52.660
I mean, it might even apply to code that was written long ago before yield from was introduced

00:46:52.660 --> 00:46:54.160
to the language, but yield was there.

00:46:54.160 --> 00:46:55.880
And you could say, hey, look.

00:46:55.880 --> 00:46:56.400
Yeah, for sure.

00:46:56.400 --> 00:46:57.520
Nightgash, you've got quite a few comments.

00:46:57.520 --> 00:46:58.540
This old way could be gone.

00:46:58.540 --> 00:47:00.320
Quite a few comments that they didn't realize you could do that.

00:47:00.320 --> 00:47:03.560
So it's like a lot of people aren't reading every kind of pep.

00:47:03.560 --> 00:47:04.300
What?

00:47:04.300 --> 00:47:05.220
Really?

00:47:05.220 --> 00:47:07.740
And seeing everything they can do.

00:47:07.740 --> 00:47:09.760
Strangely, it may seem to us.

00:47:10.640 --> 00:47:11.200
I know.

00:47:11.200 --> 00:47:11.600
It's so bizarre.

00:47:11.600 --> 00:47:13.740
I think I'm sure there's peps that I don't read as well.

00:47:13.740 --> 00:47:21.980
You know, if I had to pick a single most favorite absolute love it refactoring, it has to be

00:47:21.980 --> 00:47:28.160
convert like a deeply nested set of code to something with guarding clauses.

00:47:28.160 --> 00:47:30.860
So it's like flat, right?

00:47:30.860 --> 00:47:36.180
Instead of going, if this is true, then if this is true, while this is true, if this is true,

00:47:36.520 --> 00:47:42.360
and you end up like writing, starting on column 40 to write your code, if you negate them all

00:47:42.360 --> 00:47:46.420
and like return early or break out early or something, it's just so much cleaner.

00:47:46.420 --> 00:47:47.560
Yeah, so avoiding nesting is...

00:47:47.560 --> 00:47:48.620
Okay, that case is out.

00:47:48.620 --> 00:47:49.860
That case is out.

00:47:49.860 --> 00:47:50.560
That case is out.

00:47:50.560 --> 00:47:51.820
Now I focus on the essence.

00:47:51.820 --> 00:47:54.900
Avoiding nesting is one of our course kind of code metrics.

00:47:54.900 --> 00:47:58.460
Some of the other things I think we didn't touch on is how you get the computer to realize

00:47:58.460 --> 00:47:59.460
that there's a code smell.

00:47:59.460 --> 00:48:02.400
It's like writing good code metrics is quite...

00:48:02.400 --> 00:48:03.620
How do you get a computer to know?

00:48:03.620 --> 00:48:04.220
It's quite difficult.

00:48:04.220 --> 00:48:09.120
So there's these metrics like cyclomatic complexity, which...

00:48:09.120 --> 00:48:10.080
What's that about?

00:48:10.080 --> 00:48:13.040
It's about avoiding conditionals, basically.

00:48:13.040 --> 00:48:14.280
Number of decisions.

00:48:14.280 --> 00:48:15.000
Yeah.

00:48:15.000 --> 00:48:18.540
How many branches would you potentially go down, right?

00:48:18.540 --> 00:48:22.360
There's kind of this enhanced version of it we've looked at called cognitive complexity,

00:48:22.360 --> 00:48:26.240
which is trying to get to an idea of how hard something is to hold in your head.

00:48:26.240 --> 00:48:27.720
And that really penalizes nesting.

00:48:28.100 --> 00:48:29.620
How many variables are at play?

00:48:29.620 --> 00:48:31.720
How many other things like that as well, right?

00:48:31.720 --> 00:48:32.460
Probably.

00:48:32.460 --> 00:48:32.840
Yeah.

00:48:32.840 --> 00:48:35.880
So like that sort of penalizes nesting most of all.

00:48:35.880 --> 00:48:38.820
So that's kind of like how sorcery knows not to...

00:48:38.820 --> 00:48:41.280
Like nesting is a bad idea.

00:48:41.280 --> 00:48:44.200
And then we've written metrics about...

00:48:44.200 --> 00:48:46.100
Oh, I never really had thought about it that way.

00:48:46.100 --> 00:48:50.560
But that's exactly the problem is like the reason it sucks so much is like that next test

00:48:50.560 --> 00:48:54.280
is piled on as a and, and, and, and, and this.

00:48:54.280 --> 00:48:57.700
And that all the stuff that you've nested yourself into, you've got to think of like all

00:48:57.700 --> 00:48:59.700
those at the same time while I'm in here.

00:48:59.700 --> 00:48:59.880
Yeah.

00:48:59.880 --> 00:49:02.820
Cause the number of things you have to hold in your head, you know, a human can only hold

00:49:02.820 --> 00:49:04.920
six or seven things in their head at once.

00:49:04.920 --> 00:49:05.260
Yeah.

00:49:05.260 --> 00:49:06.640
Maybe if you're exceptional, you can do eight.

00:49:06.640 --> 00:49:12.240
So like some of our metrics is sort of focusing on how many variables you have to be thinking

00:49:12.240 --> 00:49:15.100
of and how many conditionals you have to be thinking of when you're sort of halfway

00:49:15.100 --> 00:49:17.380
down the function and it's gone off to the right somewhere.

00:49:17.380 --> 00:49:20.700
So we actually call that the working memory metric.

00:49:20.700 --> 00:49:20.980
Yeah.

00:49:20.980 --> 00:49:21.480
Oh, cool.

00:49:21.620 --> 00:49:26.200
That specifically measures the number of variables that are in scope at the current

00:49:26.200 --> 00:49:26.640
time.

00:49:26.640 --> 00:49:32.680
So we think you have, if you're reading the code from top to bottom, by the time you've

00:49:32.680 --> 00:49:37.500
got to the 10th line of code, if you've got seven variables in your head, then you don't

00:49:37.500 --> 00:49:40.640
understand the, you don't understand the function anymore.

00:49:40.640 --> 00:49:44.340
You can't keep all that in your head and understand the next page.

00:49:44.340 --> 00:49:48.320
So we keep having to scroll back and forth instead of just reading it.

00:49:48.320 --> 00:49:48.600
Yeah.

00:49:48.600 --> 00:49:49.000
Yeah.

00:49:49.000 --> 00:49:49.360
Yeah.

00:49:49.360 --> 00:49:54.040
There's this really interesting saying from a friend of mine that talked about, it went

00:49:54.040 --> 00:50:01.080
something like when you write code, I guess debugging code is harder than writing code.

00:50:01.080 --> 00:50:07.860
So if you write code at the very limit of what you're kind of able to write and do and like

00:50:07.860 --> 00:50:11.640
the most complicated stuff you can do, you probably can't debug it because trying to think through

00:50:11.640 --> 00:50:15.640
it actually is like a more complex than you kind of just pushed it over your limit.

00:50:15.640 --> 00:50:20.460
And so there's anytime you can kind of dial that back a bit through refactorings or other

00:50:20.460 --> 00:50:22.140
stuff, like, you know what, that should be three functions.

00:50:22.140 --> 00:50:24.300
Then you won't have to think about so hard.

00:50:24.300 --> 00:50:24.560
Sure.

00:50:24.560 --> 00:50:26.920
And like the most three things in this part, so much about it.

00:50:26.920 --> 00:50:31.240
The most interesting figure we found in a scientific paper that analyzed developers was sort of,

00:50:31.240 --> 00:50:37.140
they spend 70% or we spend 70% of our time trying to understand the codes and only 5% of the

00:50:37.140 --> 00:50:38.240
code time actually typing.

00:50:38.700 --> 00:50:43.600
So it's that 70% of the time you really need to cut down on by making it more readable and

00:50:43.600 --> 00:50:44.000
refactoring.

00:50:44.000 --> 00:50:47.760
And you have the, that's kind of the whole Zen of Python, right?

00:50:47.760 --> 00:50:52.960
I think that's why it's a popular language is because it's like clean to read presents itself

00:50:52.960 --> 00:50:53.400
well.

00:50:53.400 --> 00:50:53.960
Right.

00:50:53.960 --> 00:50:56.600
So don't undo that by writing bad code, I guess.

00:50:56.600 --> 00:50:57.440
Definitely.

00:50:57.440 --> 00:50:57.920
Yeah.

00:50:58.980 --> 00:50:59.540
All right.

00:50:59.540 --> 00:51:02.760
Well, I think this is probably a good place to leave it.

00:51:02.760 --> 00:51:04.860
You guys, it looks like a really cool project.

00:51:04.860 --> 00:51:09.240
If people are using PyCharm or they're using VS Code, they could just go get the plugin and

00:51:09.240 --> 00:51:09.720
give it a try.

00:51:09.720 --> 00:51:09.940
Right.

00:51:09.940 --> 00:51:10.500
Yeah, for sure.

00:51:10.500 --> 00:51:14.160
Just search for sorcery in the marketplace of the ID.

00:51:14.160 --> 00:51:14.580
Yeah.

00:51:14.580 --> 00:51:15.060
Okay.

00:51:15.060 --> 00:51:19.760
So you get it like as a, you go to the plugin marketplace in PyCharm or you do the extensions

00:51:19.760 --> 00:51:21.360
in VS Code and it'll just be in there.

00:51:21.360 --> 00:51:22.080
Sorcery with a U.

00:51:22.080 --> 00:51:24.340
As in computer source.

00:51:24.340 --> 00:51:24.660
Yeah.

00:51:24.660 --> 00:51:25.780
Not as in Gandalf.

00:51:25.780 --> 00:51:26.000
Yeah.

00:51:26.000 --> 00:51:26.220
Yeah.

00:51:28.100 --> 00:51:28.460
Yeah.

00:51:28.460 --> 00:51:34.500
And also if you go to our website, it has full instructions for installing both the plugins

00:51:34.500 --> 00:51:36.820
and using it on GitHub.

00:51:36.820 --> 00:51:38.760
And it also has.

00:51:38.760 --> 00:51:39.020
Right.

00:51:39.020 --> 00:51:42.760
And people have open source GitHub repo, they should just drop it in there and it'll give

00:51:42.760 --> 00:51:43.500
them some ideas, huh?

00:51:43.500 --> 00:51:43.680
Yeah.

00:51:43.680 --> 00:51:44.140
Give it a try.

00:51:44.140 --> 00:51:44.760
Absolutely.

00:51:44.760 --> 00:51:48.020
And links to our documentation as well.

00:51:48.020 --> 00:51:48.480
Very cool.

00:51:48.480 --> 00:51:49.500
All right.

00:51:49.500 --> 00:51:53.240
Now, before I let you out of here, I've got the two questions I always ask at the end of

00:51:53.240 --> 00:51:53.520
the show.

00:51:53.520 --> 00:51:55.220
So we'll just be quick since there's two of you.

00:51:55.220 --> 00:51:56.480
Brendan, how about you go first?

00:51:56.480 --> 00:51:57.900
You're going to write some Python code.

00:51:57.900 --> 00:51:58.980
What editor do you use?

00:51:58.980 --> 00:52:00.140
I use Vim nowadays.

00:52:00.140 --> 00:52:08.320
I ended up with wrist injuries from refactoring code using control and shift and the arrow keys

00:52:08.320 --> 00:52:09.000
too much.

00:52:09.000 --> 00:52:10.460
So I decided to learn Vim.

00:52:10.460 --> 00:52:16.560
I've ended up with that as well a long time ago and had to like rejuggle a lot of interesting

00:52:16.560 --> 00:52:16.980
stuff.

00:52:16.980 --> 00:52:20.020
Have like funky, curvy keyboards and all sorts of stuff.

00:52:20.020 --> 00:52:21.080
And yeah.

00:52:21.080 --> 00:52:23.200
Try to use hotkeys rather than mouse a lot.

00:52:23.360 --> 00:52:23.600
Yeah.

00:52:23.600 --> 00:52:25.480
It was turning into a real issue.

00:52:25.480 --> 00:52:31.140
So I had to learn Vim, which slowed me down by about 10 times for 10 weeks.

00:52:31.140 --> 00:52:35.660
But now I feel as though it's magic under my fingertips.

00:52:35.660 --> 00:52:36.440
That's awesome.

00:52:36.440 --> 00:52:37.560
Nick, how about you?

00:52:37.560 --> 00:52:38.360
Write Python code?

00:52:38.600 --> 00:52:39.960
I use PyCharm at the moment.

00:52:39.960 --> 00:52:43.840
So I'm a bit visually impaired and the high contrast mode is just really, really good.

00:52:43.840 --> 00:52:45.580
Dabble with VS Code a bit.

00:52:45.580 --> 00:52:49.360
I really like how it starts up super quick, but it's a little difficult to see.

00:52:49.360 --> 00:52:50.160
So I've made the switch.

00:52:50.460 --> 00:52:52.400
I can imagine that'll definitely push you over the edge.

00:52:52.400 --> 00:52:52.640
All right.

00:52:52.640 --> 00:52:57.640
Then notable PyPI package, maybe not something that everyone necessarily knows, but is like,

00:52:57.640 --> 00:52:58.020
oh, cool.

00:52:58.020 --> 00:53:00.300
I found this the other day and you should check it out.

00:53:00.300 --> 00:53:01.560
Any ideas, recommendations?

00:53:01.560 --> 00:53:09.560
Amazing one that we've used is this package called NUTKA, which is spelled N-U-I-T-K-A.

00:53:10.240 --> 00:53:19.720
And it takes your Python code, cross-compiles it into C, and then compiles the C code and creates an executable.

00:53:19.720 --> 00:53:32.140
And without that package, Sorcery just wouldn't exist as a locally running project because you'd have all sorts of deploy issues.

00:53:32.140 --> 00:53:36.620
We'd just be delivering all of our source codes with the plugins and the extensions.

00:53:36.620 --> 00:53:37.140
Interesting.

00:53:37.140 --> 00:53:38.440
So you're packaging it up.

00:53:38.440 --> 00:53:40.060
You're packing up Sorcery with NUTKA, huh?

00:53:40.060 --> 00:53:40.320
Yeah.

00:53:40.320 --> 00:53:40.820
Exactly.

00:53:40.820 --> 00:53:41.280
Yeah.

00:53:41.280 --> 00:53:43.040
How interesting.

00:53:43.040 --> 00:53:43.840
Okay.

00:53:43.840 --> 00:53:44.100
Yeah.

00:53:44.100 --> 00:53:45.080
It's fantastic.

00:53:45.080 --> 00:53:54.620
It builds in the version of Python that you're using and it reads all the imports to work out which bits of the code it needs to compile.

00:53:54.620 --> 00:53:59.280
It compiles the whole thing down and it works on Mac Windows and Linux.

00:53:59.280 --> 00:53:59.780
That's awesome.

00:53:59.780 --> 00:54:01.020
It's magnificent.

00:54:01.020 --> 00:54:01.620
Very cool.

00:54:01.620 --> 00:54:09.880
I had Kay Hayen from the NU-U-K-A project on for episode 174, which is like a year and a half,

00:54:09.880 --> 00:54:10.540
two years ago.

00:54:10.540 --> 00:54:11.020
I don't know.

00:54:11.020 --> 00:54:12.220
Quite a long while ago.

00:54:12.220 --> 00:54:14.080
But yeah, that's super cool.

00:54:14.080 --> 00:54:17.800
I didn't realize that it was so flexible in packaging up apps.

00:54:17.800 --> 00:54:20.740
I thought of more as like Cython, like this little bit we can make faster.

00:54:20.740 --> 00:54:22.020
So that's good to hear.

00:54:22.020 --> 00:54:22.740
Very nice.

00:54:23.060 --> 00:54:23.300
All right.

00:54:23.300 --> 00:54:24.380
Final call to action.

00:54:24.380 --> 00:54:26.440
People are interested in sorcery.

00:54:26.440 --> 00:54:27.960
They're interested in refactoring.

00:54:27.960 --> 00:54:28.520
What do you tell them?

00:54:28.520 --> 00:54:29.400
Try it out now.

00:54:29.900 --> 00:54:36.780
If you have a GitHub account, you can star our repo and try it out in five seconds.

00:54:36.780 --> 00:54:41.720
Or you can install it and get all of your pull requests refactored.

00:54:43.340 --> 00:54:47.180
If you're using VS Code or PyCharm, go and install it right now.

00:54:47.180 --> 00:54:47.980
Try it out.

00:54:47.980 --> 00:54:49.900
Get your code refactored as you work.

00:54:49.900 --> 00:54:50.440
And let us know.

00:54:50.440 --> 00:54:53.700
I mean, we're really keen to get feedback from people and keep on making it better and better,

00:54:53.700 --> 00:54:54.000
basically.

00:54:54.000 --> 00:54:54.440
Awesome.

00:54:54.440 --> 00:54:55.760
Do you guys have like a GitHub repo?

00:54:55.760 --> 00:55:01.000
Or how should they give you feedback or say, you know, my favorite refactoring is whatever

00:55:01.000 --> 00:55:01.880
you guys don't do.

00:55:01.880 --> 00:55:03.340
How do they make that happen?

00:55:03.340 --> 00:55:05.840
Yeah, we've got the Sorcery AI repo where you can raise issues.

00:55:05.840 --> 00:55:07.140
Or just email us.

00:55:07.260 --> 00:55:16.400
And our GitHub repo is sorcery-iai slash sorcery.

00:55:16.400 --> 00:55:16.860
Very cool.

00:55:16.860 --> 00:55:17.560
Okay, there.

00:55:17.560 --> 00:55:18.540
Awesome.

00:55:18.540 --> 00:55:22.380
Well, Brendan and Nick, thank you both for being here and creating this cool project.

00:55:22.380 --> 00:55:22.980
Looks awesome.

00:55:22.980 --> 00:55:23.560
Thanks very much.

00:55:23.560 --> 00:55:25.320
Thank you very much for having us, Michael.

00:55:25.320 --> 00:55:26.060
Yep, you bet.

00:55:26.060 --> 00:55:26.380
Bye-bye.

00:55:26.380 --> 00:55:26.840
Bye-bye.

00:55:26.840 --> 00:55:27.240
Bye.

00:55:27.240 --> 00:55:31.040
This has been another episode of Talk Python To Me.

00:55:31.040 --> 00:55:35.220
Our guests on this episode were Brendan McGinnis and Nick Thappen.

00:55:35.220 --> 00:55:38.060
And it's been brought to you by Datadog and Linode.

00:55:38.060 --> 00:55:42.340
Datadog gives you visibility into the whole system running your code.

00:55:42.340 --> 00:55:46.160
Visit talkpython.fm/datadog and see what you've been missing.

00:55:46.160 --> 00:55:48.320
Go throw in a free t-shirt with your free trial.

00:55:48.320 --> 00:55:52.980
Start your next Python project on Linode's state-of-the-art cloud service.

00:55:52.980 --> 00:55:57.280
Just visit talkpython.fm/Linode, L-I-N-O-D-E.

00:55:57.280 --> 00:56:00.600
You'll automatically get a $20 credit when you create a new account.

00:56:00.600 --> 00:56:03.180
Want to level up your Python?

00:56:03.180 --> 00:56:08.040
If you're just getting started, try my Python Jumpstart by Building 10 Apps course.

00:56:08.040 --> 00:56:13.120
Or if you're looking for something more advanced, check out our new async course that digs into

00:56:13.120 --> 00:56:16.180
all the different types of async programming you can do in Python.

00:56:16.180 --> 00:56:20.140
And of course, if you're interested in more than one of these, be sure to check out our

00:56:20.140 --> 00:56:20.860
Everything Bundle.

00:56:20.860 --> 00:56:22.740
It's like a subscription that never expires.

00:56:23.200 --> 00:56:24.880
Be sure to subscribe to the show.

00:56:24.880 --> 00:56:27.380
Open your favorite podcatcher and search for Python.

00:56:27.380 --> 00:56:28.520
We should be right at the top.

00:56:28.520 --> 00:56:33.360
You can also find the iTunes feed at /itunes, the Google Play feed at /play,

00:56:33.360 --> 00:56:37.520
and the direct RSS feed at /rss on talkpython.fm.

00:56:37.520 --> 00:56:39.580
This is your host, Michael Kennedy.

00:56:39.580 --> 00:56:41.100
Thanks so much for listening.

00:56:41.100 --> 00:56:42.140
I really appreciate it.

00:56:42.400 --> 00:56:43.920
Now get out there and write some Python code.

00:56:43.920 --> 00:57:03.920
I'll see you next time.

00:57:03.920 --> 00:57:33.900
Thank you.