Tuesday, June 1, 2021

Episode 113 - Full Stack Web Apps Using Only Python with Meredydd Luff

Download

We are sponsored by audible! http://www.audibletrial.com/programmingthrowdown

We are on Patreon! https://www.patreon.com/programmingthrowdown

T-Shirts! http://www.cafepress.com/programmingthrowdown/13590693

Join us on Discord! https://discord.gg/r4V2zpC

Full Stack Web Apps Using Only Python with Meredydd Luff


In this episode, we’re excited to have Meredydd Luff, the founder of Anvil. Anvil is a powerful tool that allows you to build full stack web apps with just Python. Without the need to be fluent in Javascript or other languages, Anvil is easy enough for beginners, but robust enough for professional work. We talk to Meredydd about Anvil and its features, as well as delve into the importance of making programming more accessible to more people.


This episode touches on the following key topics and ideas:


00:00:17 Jason introduces Meredydd and Anvil 

00:01:06 What is Anvil?

00:09:27 Web hydration

00:11:00 Jupyter Notebook

00:12:49 The Uplink

00:14:02 GraphQL

00:23:06 How Anvil works

00:24:19 Skulpt

00:28:09 Brython

00:29:04 Pyodide

00:32:46 Javascript daisy chaining

00:37:11 GRPC and protocol buffers 

00:39:03 “Anvil is an abstraction.”

00:40:09 Escape hatches

00:43:10 Anvil and Webpack

00:44:35 “Learn Python and build a website.”

00:45:02 Accessibility

00:47:16 Meredydd’s personal background, and Anvil’s beginnings

00:52:56 Putting your work out there

00:56:01 Logging and capturing what people want

01:01:06 Ad: ConfigCat

01:03:04 Anvil’s parent company, The Tuesday Project Ltd. 

01:05:22 Meredydd’s take on venture capitalism on developer tools

01:08:42 Working in Anvil

01:17:02 Contact details for Meredydd and Anvil


Resources mentioned in this episode:


Tools


Videos


Podcast


Catch Meredydd on Twitter @meredydd


Anvil’s features are offered completely free for teachers and educators. Send Meredydd an inquiry through email at education@anvil.works.


Get ConfigCat: https://configcat.com/

Get Audible: http://www.audibletrial.com/programmingthrowdown


If you’ve enjoyed this podcast, you can listen to more programming news and updates like this one on Programming Throwdown’s website: https://www.programmingthrowdown.com/, or send us an email at programmingthrowdown@gmail.com.


You can also follow Programming Throwdown on 

Facebook | Apple Podcasts | Spotify | Player.FM 


You can also help support Programming Throwdown through our Patreon.


 

Programming Throwdown Episode 113: Full Stack Web Apps Using Only Python with Meredydd Luff

Patrick Wheeler: Programming Throwdown Episode 113: Full Stack Web Apps Using Only Python with Meredydd Luff. Take it away, Jason.

[00:00:24] Jason Gauci: Hey everybody. This is a super, super exciting episode. I can't tell you how many times I've gone into Google and typed in like 'Python GUI' because it was, most people know, I do a lot of, of machine learning. That's my day job. And I do a lot of it on the side too, for fun. And I always want some way to visualize things. I'm always looking for new ways to do that. And so I'm really excited that we have Meredydd here, who is the founder and CEO of Anvil. And he's going to talk to us about how Anvil, how you can use Python kind of all the way through the full stack.

[00:01:01] So thanks. So glad to have you on the show, Meredydd. 

[00:01:05] Meredydd Luff: Thank you very much for having me. 

[00:01:06] Jason Gauci: Cool. So yeah, there's, there's a lot to unpack here. Why don't you kind of talk about what Anvil is, and then we can dive into a lot of the details. 

[00:01:15] Meredydd Luff: All right. So, Anvil is a development environment for building web apps quickly and simply, and it does that by letting you use Python everywhere.

[00:01:27] So if you jump into the Anvil editor, you'll get a drag and drop UI creator where you can build by component-based UIs. And then if you double click a button, now you're editing the Python code that runs in the web browser when you interact with that UI. And then you can also write some server code, and build the database, and add all sorts of external integrations, user authentication, that sort of thing. And then, click and publish it in a kind of serverless sort of way. 

[00:01:55] So, maybe the best way to think about it is, if you think about those old school, rapid app dev tools, we had like at the end of the desktop era, it's like Visual Basic Adelphi? It's like that for the web. 

[00:02:10] Jason Gauci: Oh, I see. So the, if I remember those tools, basically you had this kind of WYSIWYG-like editor, and you could kind of drag and drop buttons. You double click on them and it kind of takes you to some partially auto-generated code. 

[00:02:24] Meredydd Luff: Yeah, exactly that. So, what it means is that you can build your user interface without having to get down and dirty into the HTML and CSS instantly. You can, it's real program. This is not one of those no code things, because you're actually writing real code and a real programming language, Python, that runs in the browser.

[00:02:49] We compare that to JavaScript and we can talk about how we do that later, if you like. And then rather than having to deal with the HTTP and routing and REST endpoints and all that stuff, you can just say, okay, I'm going to define a Python module. It runs on the server, and then I'm going to tag like these functions as something we can call from the browser.

[00:03:12] So what we've done is we have taken the web stack, which is actually really, really complicated and forbidding, and we've turned that into all one representation. 

[00:03:25] So if you think about an ordinary web application, if you built these before. You know, if you think about your data, like an ordinary database bank web application, your data starts out as rows in a table in your database. And then, the first thing you do is you take them out and you transform those into objects in your server side code, whatever language that's in, maybe Python. 

[00:03:48] And then you immediately turn around, turn around and represent those objects, which have their own methods and attributes. You turn those into JSON served over HTTP with this really limited set of verbs, like GET POST PUT DELETE, and on the other end of that HTTP request is some JavaScript that immediately transforms that JSON into a JavaScript object with its own set of methods, its own set of attributes, and then you turn around and you represent, re-represent that data as HTML DOM. And then you use CSS representative pixels.

[00:04:21] And that is, the day-to-day work of web development. Is shoveling your data and your applications state between these different representations. And we thought, it's not difficult to work out that this is way, way, way more complicated than it needs to be. 

[00:04:41] Have you ever looked at one of those, there's this really great chart on GitHub? Like, these are the basic technologies you need to know to be a web developer. And like, it's just like pages and pages and pages and pages of stuff.  (laugh) And it's all, it's all kind of wired together and you need to fit these 20 different components together.

[00:05:00] And we thought, well, if it were all just a Python program, If you could just, if getting from the server to the client, wasn't a matter of mashing things into JSON, it was a matter of making a function call. If putting something on the screen wasn't a matter of like generating source code in one programming language that templates a different markup language that is then transformed into pixels by a third language, and they all kind of work together and you squint and you get something on the screen. 

[00:05:26] If we could replace that by putting a button there, and then you make its text be such and such. If we could replace the process of, you know, standing up machinery on AWS and setting up a web server and setting up the front end and the standing up a database with, well, hey, here's this serverless hosting.

[00:05:43] If we could do all of that, suddenly creating a web application is no more complicated than writing a Python script. And frankly, that's where it should be. There is no, there is no reason that the greatest application delivery platform on earth should have the bar set that high for you. Like, you must know these five different programming languages before you can ride this ride.

[00:06:05] You know, you must know HTML and JavaScript and CSS and Python and SQL and React and Redux and Bootstrap and flask and SQLAlchemy and... you know, that's before we even got to the dev ops stuff. Like, that, that is not necessary complexity. A web application where you click something and something happens ought to be as simple as writing the equivalent Python script. And we set out to make that happen. 

[00:06:32] Jason Gauci: Yeah, totally makes sense. I think the, the, a lot of the open source libraries, and this is true in general, but, but especially for web, they're, they're built by companies that have gigantic websites. I mean, I have websites that are, you know, the code base is enormous, and a throughput to QPS is enormous.

[00:06:52] And so yeah, if you have a gigantic, a massive organization of people, then it kind of makes sense, we'll have sort of people design, sort of GraphQL server, and that's going to be whole teams of people working on that. And then there's a whole bunch of other teams of people consuming that, and it's all sort of decentralized, right? 

[00:07:15] But the problem is, nothing starts that way, right? Like nobody goes into the first iteration of their company and they're trying to find product market fit and they have three customers and, and they're, they're like, stressing about the GraphQL throughput. Like it just doesn't work that way. And there's not that much visualization for people who are wanting to get started quickly. 

[00:07:42] Meredydd Luff: I totally agree with you, but I, I would take that analysis even further. Even those huge high throughput guys, like the web isn't the architecture they would have chosen. You just mentioned like several different technologies that are actually about taking the primitives that the web gives you, which basically, they were organic. They kind of grew up over the early 2000s, now we're stuck with the, and turning them into something that these hyper, hyperscale people can use. 

[00:08:13] Like, things like GraphQL is literally a solution to the problem. Oh, wait. REST is not a good way of representing our service site API, guess we're going to have to build something else on top. React is, HTML DOM is not a good way of representing our UIs, guess we're going to have to build some, build something else on top. 

[00:08:32] Like all of this stuff is patching over the web. Patching upon patches upon patches, to try and make it a usable development environment. And that is as true when you are these incredibly high scale people building funky GraphQL backends, as it is, if you're a data scientist who just wants to be able to like, select from a dropdown and draw the appropriate graph on the screen. 

[00:08:56] Actually, almost everybody who's using the web is suffering from these problems in some respect. Having said which, of course you're absolutely right that these are the core customers we're starting with first, like the sorts of people who go, well, I just want to put a bus in here or draw a graph on the screen, or I want to prototype my product. And those are the people we could really say, Hey, there is in fact a better option. Here's how you can do it 10 times faster.

[00:09:27] Jason Gauci: Yeah, it makes sense. I think you really hit the nail on the head that the whole HTTP invention was for just, server side rendering. You know, it's for just dropping, almost like a printing press, right? It's sort of like, we just, we just give you this sort of structure and you just drop it onto your screen.

[00:09:45] And then obviously the web is totally different now. Now things are sort of hydrated and the hydration for a lot of websites is everything. Like, there's some websites that if you don't have JavaScript on you just get a blank screen or something, right? So... 

[00:09:58] Meredydd Luff: Yeah. And there's nothing wrong with that, with that architecture right there. It's just like your classic fit client architecture. You have this runtime, so you can have fast responses and fast interactions on the device you're actually using. And then it talks to a server and that server talks to a database. Like, none of that architecture is actually bad. 

[00:10:18] What I would assert is unnecessarily difficult to use, is the particular way the web has evolved around that, because just like, yeah, exactly what you said. Because it's evolved over this document-based substrate, it's kind of, at every point it's done, like the minimum requires to hack this next piece of functionality on. And so you end up with this mess. That's really, really difficult to approach. 

[00:10:44] And, there's, there's no reason that a beginner or a data scientist or someone who's experienced in somewhere else, like, manufacturing engineer, should have to learn all this amount of stuff just to be able to produce an interactive screen. 

[00:11:00] Jason Gauci: Yeah, exactly. I think this is even true for, and this is going to be a bit of a tangent, it is even true for desktop. I think this is one of the reasons why, at least for data science, this Jupyter Notebook has been so popular because, it took all the painstaking time and effort to do that. But then you're kind of limited to whatever supported by Jupyter. Ideally you would have, as Anvil is a, programming environment where, which is much more open-ended.

[00:11:29] Meredydd Luff: Well, funny you should mention that actually, because yes, absolutely. Jupyter is a fantastic piece of technology and the way that it's got that, this kind of cell-based interactive programming is a really great fit for a lot of these science tasks.

[00:11:44] But as you say, it's fundamentally just a Python script. And so, there's limits to what you can do in terms of interactivity. We actually have a library that can connect to Jupyter Notebook to an Anvil UI. So because this is a problem again that keeps recurring, because there are a lot of problems for which actually, just writing a Python script is the right answer. And then you go, Oh, well, true. But I would like to connect this to a web UI. So in your machine learning work, I'm sure you will have done a lot of this, right? 

[00:12:14] You are in there, you've got your nose on a Jupyter Notebook. You are training, designing, training, refining a model, and then you go, okay, like I've got this thing working. I'm at the point where actually I've gone as far as I want to go by interactively typing Python into a programming environment. Now I want someone else to be able to use it. I would like to be able to put some interactive visualization on it. I'd like to stick it up there, so, I've got an image recognize, and I'd like someone else to be able to come along and take a picture with their mobile phone or upload something from their computer.

[00:12:49] And, what we've actually got is something called the Uplink, which is a library you can PIP install anywhere you're running a Python script. And it makes a connection up to the Anvil service. And then your Python interpreter, wherever it is say, inside your Jupyter Notebook. It's like it's part of that app, so you can access the data tables in your app, with exactly the same API as you could if you were running in our serverless environment. 

[00:13:19] You can call functions in that serverless environment. You can even define those callable functions that can be called from the webpage. So actually we have a neat demo, perhaps we can drop a link in the show notes, of taking a Jupyter Notebook that does an image recognition task, and then going, well okay, now I want to turn this into a web app, import the library, take the function that takes an image and returns to classification. 

[00:13:41] Tag it as, Hey, this is a function we want to be callable from the browser and then just going into the browser, you know, having a file uploader, when a file gets uploaded, into that widget. Server.call, classify image, pass the file in, and get the return value.

[00:13:57] It's just a function call. It's just Python. It just works. So yeah, we, we have something for that.  (laugh) 

[00:14:02] Jason Gauci: Yeah. Yeah. I think that, that makes a ton of sense. So I'm trying to think, like, I think you did a good job explaining kind of the, the sort of traditional web development, right? And just, just to kind of reiterate, actually, I didn't really explain what GraphQL is, we'll cover a bit of terminology and then we can dive into, into how Anvil, works, right?

[00:14:25] Yeah. So typically, if you're on a website, your browser's running this engine called JavaScript, you know, programmers can go in and write things like change colors of buttons, add content that wasn't there before, things like that. And the way that it does that is, by running this JavaScript engineer browser, but, often it needs to go back to the server and get more information, right?

[00:14:47] Maybe someone sends you a message and you have some, IM thing on your, some IM website. It needs to be interactive. So, it's constantly going to the server and saying, Hey, is there something new that I need to know about? And the way it does that is by basically visiting websites that are just meant to return data.

[00:15:09] So, if you go to google.com, you're going to get, this rendering, but there are other websites. If you go to them, you're just going to get, a batch of data. And most of the time people are doing JSON as the transport. So you're going to get some actually human readable, I guess. I mean, it's usually like a mess, but you got to get something in characters that you can see that's going to represent some structured information.

[00:15:36] And so if you were to build a, let's say, I don't know, old school, if you were to build an old-school kind of your interactive website, you would have a bunch of, you'd have your main website. Mycoolwebsite.com/index.html, but then you'd also have, and you'd also have your images and all of that. Each of those would be URLs and the server would, would know where to go to get those. 

[00:15:58] And then you'd have all these other URLs that just returned data. And presumably they, they have logic behind them. So, so they're going to return different data when you call them, depending on the context. There's something else called cookies, which is, think of cookies is like a really small database that your computer and the server are sharing for your connection. And so the cookies are a way so that when you go from one page to the next, you're still logged in every time. 

[00:16:24] But this was a huge pain. It's like I have to make a URL for every piece of data I need, like, give me the current time. Tell me how many friends I have. Tell me all my friends names. 

[00:16:35] Meredydd Luff: Well, and crucially, when, when you click to go from one of those thing to the other, your whole page refresh, you were staring at a little bit of white screen while the next whole page downloaded, then it showed the next whole page to you, and the web was advancing and we wanted to be more interactive.

[00:16:49] Jason Gauci: Yeah. Oh, that's so true. So, so then we get to the sort of single page apps where, it's even fetching, not only just this data and HTML, but it's actually kind of fetching new HTML and kind of building as it goes. And then, but, but you're having all these URLs just 'cause it becomes really cluttered.

[00:17:06] So this GraphQL was this idea that let's just have one URL, but you'll pass in, a specification that says what you need. Kind of like when you, write sequel queries, there's only one sequel engine. And the query just tells the engine to do different things. So with GraphQL, there's only one URL that you go to for all your data, but by passing in different, almost like different queries, you're going to get back different pieces of information.

[00:17:37] And so that, that was better, but it still has this challenge that, that Meredydd talked about where, GraphQL does everything in this thing called JSON. And so if you want to pass an image, for example, in GraphQL, you actually have to convert that image into letters and then send it to the client and then turn it back.

[00:18:00] And so it just becomes a huge hassle to represent everything in this way. And then just to turn it back into something that you're going to render. 

[00:18:10] Meredydd Luff: Yeah. Well, and also the fundamental structure of a web application is that your browser goes to a site and your site serves up the source code for an app that will run in your browser. This is how it mostly works these days. 

[00:18:24] And then the browser is running an application that's built with JavaScript and HTML. And then when that app running in your browser wants to get some kind of data from the server, it will make an HTTP request to the server. And there are various conventions for how we use those, those requests to get data, instead of HTML, there's sort of a, you could have a URL for every thing. So, which is the, the REST pattern. Or you can have. Something like a GraphQL, where you have one URL that you post this complicated query to, and it gives you back some complicated response.

[00:19:05] But all of this is being squeezed over HTTP requests, which is exactly the same thing that your browser is using to fetch the web page in the first place.

[00:19:14] And HTTP is a great protocol for fetching web pages. It's not necessarily a great protocol for doing what your application actually wants to do, which is that the part of your code that's running in the web browser wants to talk to the part of your code that's running on the server and do something that's, well, do something that's part of your application.

[00:19:35] And if this were a desktop, old school desktop application, you just make a function call, and you, you be modular and expose a certain API or, the GUI section caused the backend engine for these things. And these days on the web, whether you use something like REST or whether you use something like GraphQL, you're kind of twisting the way your app thinks about the world, until it's shaped like the way that HTTP thinks about the world.

[00:20:04] And that's just an amount of stress that as a programmer, you don't need, and this is why in Anvil, we have a, you can still use those. So if you already have an API that's built in REST or GraphQL, you could absolutely use it with the standard HTTP stuff, but the usual way of communicating between the bit of your app, that's running in the user's web browser, and the bit of the app that's running on the server is just to make a function call. And you can pass arguments to that function call. You can get returned values to that function call. Unlike a classic JSON API request, you're not limited to just, dictionaries and strings and numbers and lists.

[00:20:41] You can, I mean, in the image recognition example, you can just pass a blob of binary data that was uploaded as a file from the computer. You can just pass that as an argument to the function and Anvil takes care of taking all that, that large lump of binary bytes from your browser to the server and putting it into a form that your server side code can easily deal with.

[00:21:03] And this is just one example of how twisting your applications logic into the shape that the web stack expects is just making you do unnecessary work. And we've done the same in the client where, instead of generating HTML, which is a kind of programming language all of its own, you can say, well, actually, the thing I want to do is I, I want to add a UI component.

[00:21:29] And so we have this object-oriented thing where you could just construct an object in Python. You could construct a button object, set it's dot button, one dot text equals blah self-taught, add component button, and put a button on the screen. And that's again, it's not making you twist what your application's doing into the shape of what the web platform is expecting.

[00:21:54] And so that's, that is I think the crucial theme that we're, that runs all the way through Anvil's architecture from top to bottom, and doing function calls instead of REST or GraphQL is just one example of that. 

[00:22:09] Jason Gauci: Yeah, totally makes sense. I think too, if there's this extra benefit where if you're, if you're already using Python for, for a task, then if you have some Python program and you want people to see it on the web, or you want to write a web visualizer, then without using Anvil, everything you, you want, you want to see us to be represented in JavaScript.

[00:22:31] So now it's like you have to have sort of your Python representation of all this knowledge. And then you have to have this JavaScript representation, and you have to constantly be converting from one to the other. And, and so, yeah, that, that ends up taking, a huge amount of time and it can actually be really difficult.

[00:22:47] You know what I mean? JavaScript wasn't designed to handle binary data. Now they have a whole bunch of cool things for it. So, I mean, it's definitely evolved to meet the demand, but...

[00:23:00] Meredydd Luff: Yeah, it it's, it's devolved rather than being designed is sort of the point.  (laugh) Yeah.

[00:23:05] Jason Gauci: Exactly, 

[00:23:06] Meredydd Luff: Exactly that. 

[00:23:06] Jason Gauci: So, yeah, let's dive into the, into the magic here. I mean, it seems pretty magical that someone, we  just told people that you can only write JavaScript in the browser. So somebody, someone's writing some Python. And so I think you said that they're, they're annotating some functions of saying these are server endpoints.

[00:23:25] And I guess there's maybe like some Python files that are running in the browser. Some are running on the server. Like how does, how does all of that come together?

[00:23:33] Meredydd Luff: Oh, right. Yeah. So here's what happens. When you open the Anvil editor, you've got, it's a standard IDE type layout. You've got your sort of list down the left of your, your modules.

[00:23:45] And there are two sorts, there are client modules, and then there are server modules. And whenever you're editing client code, which includes like these, these forms, these drag and drop, these, sorry, these pieces of user interface that can appear on your page, they're also client side Python modules, they're just, they're just Python classes, actually. It's, everything is a Python object. We try not to be, not to be magical about this part. But when you write code that runs on the client, Anvil will actually translate that from Python to JavaScript. 

[00:24:19] So when someone visits your application, what they load is actually a Python runtime written in JavaScript. It's called Skulpt, S K U L P T. It's a really cool open source project, we contribute heavily to it. And that is the kind of the translator that allows you to run your, it turns your Python code into JavaScript code that does the same thing. And so when you click on that button, what's actually happening is that the JavaScript function is running, but that JavaScript function was created from the Python code you wrote.

[00:24:53] And when you call something that's on the surface. So you say, if you do anvil.server.call, that, which is our library function for this, that's Anvil's cue to send a message to the server. And it then goes and talks to anvil service, which then spin up your server modules, which are those, the Python modules that you created in the section, that's no, this doesn't get sent to the web browser. This only executes in on the server. And loads all of those modules. And then any functions that you have annotated with anvil.server.quotable are accessible. 

[00:25:30] And so when the request comes in and says, I want to call the classify image function, then we look up and say, yes, there's a function called site classify image. Yes, it's tagged as accessible. So we run that function. And then when that function returns, return something, we will send a message back to the browser saying, this function has completed and here is its return value. And the Python code that's running in the browser gets that as the return value from anvil.servercall.

[00:25:56] Jason Gauci: I see, I think, I guess. So let me, let me see if I can reiterate it and that'll figure out if-- isn't that one of the, what's the, what do they call that, is if you can reiterate something, then you understand? I don't remember the word for that, but yeah, so, so, okay.

[00:26:09] So the idea is, actually, so what is getting sent to the client then? Is it Python files that, that are being executed by this virtual machine? Or is it, is it been compiled somehow? 

[00:26:22] Meredydd Luff: So it is, actually, what gets sent to the browser is a Python source code, and a Python to JavaScript compiler, and Runtime. So it actually gets compiled when it's opened in your user's browser.

[00:26:35] Jason Gauci: Okay. What's the, what's the reason for that? Like, what's the reason for not compiling it server side?

[00:26:40] Meredydd Luff: Oh, I see. That is a speed optimization that we will make at some point. Remarkably, actually, when we profile it, that is not the, that's not our current limiting factor in terms of performance. So, one day we will compile it ahead of time and just serve up the compiled JavaScript when your user access to your app, we just haven't got there yet.

[00:26:59] Jason Gauci: Got it. Okay. Makes sense. Can people, since it's compiled on the client side, can people write Python interactively then? 

[00:27:06] Meredydd Luff: So people can write Python fairly interactively. We don't have a, like an interactive Python consult in the Anvil editor yet, but watch this space actually, by the time this episode goes out, we might have a, that it tracks... 

[00:27:20] Jason Gauci: Your console might be released. Very cool. Okay.

[00:27:23] Meredydd Luff: But yeah, if you go to skulpt.org, you can actually get a demo of the Skulpt Python JavaScript compiler, and that is like a live Python console running in your web browser. It is very cool. 

[00:27:32] Jason Gauci: Wow. It's amazing. And, and so, so they actually wrote a Python VM in JavaScript, like from scratch?

[00:27:40] Meredydd Luff: Believe it or not, they did, and they're not even the only ones. There are about five different projects I think, that have tried to put Python in the browser. And like, there are really good reasons for this, because a whole bunch of people who are used to the ease of using Python have looked at the web and gone, Oh my goodness, this needs to be simpler. You know, how can we make it simpler? 

[00:28:02] Well, I find Python really easy to write. Let's make it so you can run Python in the web browser. 

[00:28:09] And there's a few of these. So there's something called Brython, which is, it kind of replaces JavaScript with Python. So you still write your script tags in your HTML, which is where you'd normally put your JavaScript, but you write them in Python. And then the Brython compiler jumps in and compiles them to JavaScripts, lets you use that JavaScript instead.

[00:28:26] You've got, there is something called Transcrypt, which is, it compiles that something that's mostly Python. It doesn't quite behave exactly like Python, but it compiles it into really clean and fast JavaScript. And that happens ahead of time. So you feed it a bunch of .py files and it generates a bunch of .js Files. And then you load those .js files in your web application, just as normal. 

[00:28:53] And that's kind of cool, although it doesn't really have a particularly good fidelity to exactly how Python behaves. Like if you're used to, messing around with objects at a low level, then that's not going to work for you. 

[00:29:04] There's also a really cool project called Pyodide, which is out of Mozilla. And that has taken the, rather than writing a new Python VM in JavaScript, it's taken C Python, the standard Python interpreter, and compiled it to WebAssembly, which is, kind of like, a fast compiled virtual machine that runs in your browser. And so if you go to the Pyodide page, you can get something that's kind of like a Jupyter Notebook. And it's got like all these standard data science libraries only it's running in your browser. It's mind bending. 

[00:29:43] Jason Gauci: What is that one called?

[00:29:44] Meredydd Luff: Pyodide.  P Y O D I D E.

[00:29:48] Jason Gauci: Wow. Did they, they ran the entire Python source code through enscript in or something? 

[00:29:54] Meredydd Luff: The entire path and source code, and a bunch of the classic libraries. I think you can actually use TensorFlow in your web browser. It's nuts. 

[00:30:02] Jason Gauci: Wow. Amazing. 

[00:30:04] Meredydd Luff: I mean, of course it takes like a minute to start. Cause it's downloading the entire Python ecosystem when you open the page of the web browser. So it's not going to be that great as an application delivery platform, which is what we're looking for Anvil for, but as a technological achievement, it is spectacular. 

[00:30:21] Jason Gauci: Yeah. I wonder if that can be cached somehow. So this gets to, starting to get to my limits on what I know about the web, but I think there's like CDNs, like cached things or something, right? Is there any way to speed that up? 

[00:30:32] Meredydd Luff: There are ways to speed it up, and you could, if you really worked at it, you could get it down from that many seconds to, to only, only a couple of seconds, but it's, it's never going to be like an instant snappy response. 

[00:30:47] Jason Gauci: Got it. 

[00:30:47] Meredydd Luff: So it's, it's great for what it is, which is loading a Python environment in your browser, where you're okay with it taking a few seconds to start up, but it's not going to replace JavaScript for what JavaScript is really used for, which is driving the page in your browser and making it interactive. 

[00:31:06] Jason Gauci: Yeah, totally makes sense. Okay. So someone goes to the website, they get the default HTML, that whatever, it hasn't been hydrated yet so that, whatever the server is rendered. And they get a bunch of PI files and they get this virtual machine.

[00:31:23] So they, they grabbed the virtual machine, they grabbed the PI files. They run the PI files through the virtual machine and that, that executes some, some logic. And then part of that logic says things like call this function on the server, you're on the client, you don't have that function, but, but there's, there's some way where it knows to take the arguments, I guess pickle them on, there's like maybe a pickle in the browser? 

[00:31:48] Meredydd Luff: It's kind of like that. Yes. 

[00:31:49] Jason Gauci: Yeah. Okay. So the server runs, the server unpickles it. Pickle is just, by the way, if you'll know, it's just a serialization library in Python. So the server deserializes it back to those objects, executes the function on the server, packages up the return value, sends it back to the client. And so the client then keeps going. 

[00:32:09] Is there support for like, asynchronous calls? There has to be right? Otherwise it'd be kind of...

[00:32:14] Meredydd Luff: Watch this space  (laugh) in short. We've actually, we're working on that on an ongoing basis, but actually, so, when you make a call that takes a long time, it doesn't freeze the browser, but you do get a loading spinner, which is, just like you get with most other web applications, while they're  loading some  some data from the server, we started with this synchronous programming model where, you call a function, then you get a return value, and then you carry on executing because actually that is what most people want most of the time.

[00:32:44] Jason Gauci: Yup. Yup. 

[00:32:46] Meredydd Luff: And one of the, one of the reasons, one of the things that makes JavaScript so unfriendly to use is that it's not like that. It's default mode is asynchronous where you say, well, do this task, make this request to a web server, do this other thing and then call this other function when you're done.

[00:33:05] And so you end up kind of daisy chaining. Pretty simple. What would otherwise be pretty simple logic like, okay, well, they've clicked the button, call this function, then call that function. Then do the other, you end up like daisy chaining them with a series of callbacks and then you have syntactic sugar. Like async await if people are familiar with that with JavaScript.

[00:33:26] But what that is is actually just a syntax for daisy chaining a set of functions. And you still end up, if you want to use something like async await at an advanced level, you end up still needing to know, Oh, this is producing a promise object. And this promise object will invoke its callbacks. If you do such and such. And that's again, an example of the problems caused by, well, building this application delivery system out of, kind of the bits of pieces we had lying around in the web browser. 

[00:33:59] And so we wanted to start with this very straightforward programming model, where if you wanted to get something from the server, you could do, X equals call this function and then use X on the next line of code without having to understand everything about async programming in order to get "hello worlds" to work.

[00:34:20] Jason Gauci: I see it. I think that works because of the VM, right? So I think, correct me if I'm wrong, but with JavaScript, I'm pretty sure the machine is only single threaded. So, actually there are web workers, but we'll put that aside. So, so basically you kind of need everything to be asynchronous because you can only be executing one line of code at a time.

[00:34:42] And if that line is waiting for the server to come back, then nothing else can get done. But, but here, because you have this VM, I don't think you're limited in this way, right? 

[00:34:50] Meredydd Luff: Absolutely. I actually gave a lightning talk at PyCon in 2017. And if you still have any space in your show notes, I'll send you the link to that, which where I take apart the Skulpt compiler, and I show exactly how we did it.

[00:35:05] And you're exactly right. It's because we control the compiler, we can turn this really simple synchronous logic into highly asynchronous JavaScript. So there's, it's, I can summarize it, but really go watch the talk for, for all the diagrams. 

[00:35:18] But the way that the compiler works is it walks over the source code it's been given, and it breaks that up into a tree of syntax, we call it an abstract syntax tree, and that's things like, well, this is a function definition. This function has these three statements inside them. And one of them is the function call and the other one's in assignment and the other ones are returned. And you end up with this, this tree of figures in your language, like assignments, function calls, function definitions, if statements and so on. 

[00:35:50] And then we, there's a, there's another stage, which is the compile stage, which walks over that abstract syntax tree spitting out, the compiled representation in Skulpt's case, that's spitting out JavaScript. And because we control that compile phase, we can say actually every time you're calling a function, call a function and if that function signals that it's blocked, that's waiting for something, then suspend all execution and wait until it gets back. 

[00:36:21] And then when, the result from that function call returns from the server, restore, go back to where we were nested inside however many function calls, and resume execution. And because we control the compiler, we can save, what all your local variables, what functions were on the stack and so on and resume it. It's really, really cool. Watch the talk. 

[00:36:42] Jason Gauci: Cool. Yeah, that makes sense. Yeah, I think, yeah, I think it was a really powerful model. It reminds me a little bit of, like protocol buffers and GRPC, where you could kind of like, this actually supports cross language too, but, but, but even just focusing on, let's say Python, you would kind of define your server calls and this sort of IDL, and then it would, package all the arguments for you and all of that.

[00:37:11] The thing about GRPC and protocol buffers is it's just, it's a huge pain to be, auto generating all of this code all the time. and so Anvil kind of avoids that really messy step. Also, you have to get protocol buffers, which now with like Chocolatey and some of these things it's not too bad on Windows. On Linux, you can always AppGet just about anything.

[00:37:32] But, but yeah, just having the protocol, buffers, runtime, and compiler, and putting it in your code and all of that, it's just a huge amount of overhead. 

[00:37:40] Meredydd Luff: Absolutely. I suppose that's another example of something. Google a very big company, a demonstration like HTTP request are actually a helpful way of transmitting stuff around inside Google. And, you know, Google turns everything from HTTP into protocol buffers as soon as they can, because  (laugh) because the web, the web is it's like, it doesn't fit any size.

[00:38:03] It's not a great answer. That's a one size fits none is the web. 

[00:38:07] Jason Gauci: Yeah, that's right.  (laugh) 

[00:38:08] Meredydd Luff: Like it's not a good fit for those hyperscale users, and it's really hostile to beginners. Anyway, you can tell that, like, this is a rant. I just keep sort of circling back to. 

[00:38:18] Jason Gauci: Yeah. So actually one question about this. I mean, what the, I wouldn't say what the web is good at, but what the, let's say the ecosystem is really, really powerful at and what the real sticking value is in the components. Right? 

[00:38:33] So, if I need a really nice calendar component, I can find just about anything on npm, right? And so there's going to be an audience of people who want to do the, the client, the design part in something like react. Is there sort of a way to do maybe like the business logic in Anvil and, and does that, does that then make you susceptible to the problem we talked about earlier, right?

[00:39:03] Meredydd Luff: Well, so obviously if you're going, if you want to use something lower level and gritty in JavaScript, we, you're going to pay the price of doing something in JavaScript, but we don't want to stop you. And actually this is another big point. 

[00:39:20] Anvil is an abstraction. It takes something complicated, the web, and it gives you an easy way to manipulate it. And the problem with abstractions is that they don't always exactly match the underlying reality. And for example, every abstraction fails like this, Google, leaky abstractions, every abstraction kind of reaches its edges and fails. 

[00:39:44] Jason Gauci: I'm thinking of those, the thing where it's a website, but they tried to make it look like an app. I think it's Core Dara or something, but these always look terrible, right? 

[00:39:53] Meredydd Luff: So yeah, I'm thinking like at a higher level than that, like any time you try it, you take something and you try to make a simpler abstraction for it. There are going to be limits of that abstraction. Anvil's, Anvil's Python API are not going to cover every square inch of what the browser can do.

[00:40:09] It's, I mean, the browser is a, mind-boggling huge platform. It's just not going to happen. And so, rather than lock you in and say, well tough, you're using Anvil now, you can't use any of that JavaScript goodness, we have escape hatches everywhere. I've actually, I've already talked about one of them in a different context. The Uplink is an escape hatch. 

[00:40:27] Serverless computing is great. It means you don't have to host anything. But I have like a Jupyter Notebook sitting here on my physical computer with a physical graphics card in it. And I want to run my code right here. Not somewhere off in your cloud. Well, that's okay. We have an escape hatch that says, that's fine. You can run your code right there on your computer and you can plug it into your app, but it's just as good as our serverless code. And in the same way, we have escape hatches to use things in HTML and JavaScript. 

[00:40:55] So if you have a funky calendar component that you really want to use, it's better for your use system, Anvil's built-in calendar widget. What you can do is you can drop down to HTML in JavaScript. You can drive that JavaScript from Python, and then, and here's the cool part. You're not stuck in JavaScript thereafter. What you can do is you could drive that calendar component from Python, and then you can define that as a custom component.

[00:41:25] So the Anvil form in which you've included this calendar widget, you can say uses custom components, and then you can take your app and say, make this app available as a dependency, and now you or anybody else can, in their own Anvil applications, add your app as a dependency, and into the toolbox in the drag and drop editor, alongside Anvil;'s built in buttons and date pickers, and so on, will be your calendar widget. And somebody else can drag and drop it onto the screen. 

[00:41:56] And you can define the properties and the events in your Python class. Cause remember the form you create is just a Python class. And so you can define properties and events. So it behaves like any other Anvil component.

[00:42:09] And so you've taken this piece of external JavaScript. You've wrapped it up as an easy to use Python class that can then be used slotted right into every other people's Python code and even the drag and drop editor. So, yes, we're really, really, we are religious about making escape hatches for anywhere where our platform doesn't quite eek it out.

[00:42:31] And actually, there's a, there's a cool example of this. We're recording this just before Christmas, 2020. And we're doing, like an advent calendar of a web app every day till Christmas. And the one we did a couple of days ago was a 3D Christmas tree. And that 3D Christmas tree is built using Three.js.

[00:42:50] We don't have native 3D support in Anvil, but that's okay because you can go from anvil.js.window it import three, and you can actually drive the Three JavaScript API, three.js JavaScript API from Python. Because we've got that bridge, and then you can wrap it up and uses as a striker drop components somewhere else.

[00:43:10] Jason Gauci: That makes sense. Does this play well with Webpack? Probably not, right? That would be... 

[00:43:14] Meredydd Luff: The thing you would do would be you'd, you'd use Webpack to generate your JavaScript and then you would import that JavaScript's like you, at that point, you'd be dropping down to JavaScript, interfacing with those modules. And then, then you would do the bridge to Python.

[00:43:28] You're going to have to write that bridge, if you want to drop down to the low level technologies like JavaScript, you're going to have to, to get some JavaScript on you at some point, right? What we're concerned about is that we don't force you to drag the rest of your app into JavaScript as well.

[00:43:43] Jason Gauci: Yeah, that totally makes sense. But like, does it, I don't know too much about Webpack. I assumed it would kind of mangle all the names and everything. 

[00:43:49] Meredydd Luff: The answer is that, you tell Webpack your public APIs and it, so Webpack knows which names not to mangle. So for example, with three.js, all that internal stuff is going to be mangled.

[00:44:02] Sure. It's going to be minified. But, the actual APIs you're using like, create this mesh, render this here, those, those names are remain unmangled, so that they can be used. Again, this is just, you do it just how any other JavaScript programmer would, because that's exactly how any other Javascript programming interacts with these libraries.

[00:44:20] Jason Gauci: Yeah, totally makes sense. So, so yeah, this is awesome. I mean, everyone out there should try this out. there's a lot of people who are using Python. I mean, that's the language I recommend people kind of get started with. And it's, it's really cool to see that there's a way to... 

[00:44:35] You know, Patrick and I always tell people like, use it. Well, actually, this, this fits in perfectly with our advice, which before was pretty schizophrenic, which was, learn Python and build a website.  (laugh) That's what we would tell people. It's easy to build a website. You don't have to write an installer, but you should learn Python. And don't tell us how you're going to do those things at the same time.

[00:44:56] And this, this episode actually completes our advice for once after what, 11 years or something. 

[00:45:02] Meredydd Luff: Well, I mean, the thing is, you're not the only people giving that advice because, like when you're facing someone who's just onto programming, "Use Python" is absolutely the right advice. You do not want, like the first thing they do to be exposed to unshielded like JavaScript and HTML and DOM, they'll run away screaming.

[00:45:17] But yes, exactly. That's where everyone starts, and a web app is where everyone wants to finish. And there's like this, there's the underpants gnomes like, step one, learn Python, step two, question mark, question mark. Step three, build a web app. And,. you know, bridging that is explicitly what we're about.

[00:45:32] So tangentially related to this, because what this is really about is making building web applications more accessible, and accessible has two meanings here really. Because, of course like you, if you have something that is difficult to complicated, well, the thing you want to do is to, make it easy enough for novices to pick up.

[00:45:59] And absolutely, if I went on an album to the street and asked three people, what does accessibility mean, that's probably what they'd say.

[00:46:08] But that's only half of it, because if you just try to make something easy, what you make is like it's a children's playpen. You make something that is kind of a toy, and that does your users a disservice. 

[00:46:25] For two reasons, I mean, one it's that the people who are just starting, like they are just starting, they're not finished yet. And they need room to grow their powers. And if they're stuck in the, in the kitty section, then they can't grow and that is doing them a massive disservice. But it also does a disservice to the rest of the world because, just because I can write five different programming languages and five different frameworks to build a web app, doesn't mean I want to, and it doesn't mean that anybody else in my company wants to wait for me to do it either.

[00:46:57] And so, to be properly accessible, you have to be simple enough for novices and powerful enough for seasoned professionals, because that's how you give the novices space to grow. And that's how you actually solve problems for the professionals rather than only solving problems for beginners because professionals have problems too.

[00:47:16] Jason Gauci: Yeah, that totally makes sense. Yeah. So, one kind of question is a little bit different. Like what inspire you? You give us a little bit of background on yourself and what, this is an enormous undertaking and, what inspired you to say, we're going to do this? 

[00:47:35] I mean, there's probably, I mean, you, you could tell me, but there's, there's gotta be at least, I know several people years' worth of effort here. And, what inspired you to really buckle down and build this? 

[00:47:49] Meredydd Luff: So my personal background is, I started programming with QBasic back in the day. And, I came up using these tools like Visual Basic as I was learning, and it was great because it meant that I could, I could build real applications that looked like everything else, on your system, whether that was in DOS, it looked like any other DOS program,or whether it was on Windows. It had Windows, it had Windows and buttons and menus and so on.

[00:48:15] And that is what got me into programming. And, I have a old university friend called Ian, and he came up very much the same way. And we ended up, I took a detour, biology because I already knew I loved computers enough that, they would always be somewhere in my life. So I could do go do something else that was fun, fun at university. But I eventually came home and did a PhD focusing on building usable programming systems. 

[00:48:45] And, Ian was actually in the research group next door, also working on human computer interaction and he has exactly the same experience. He also came up, building things in Visual Basic, tinkering stuff together with soldering irons. He's much better with his hands than I am. 

[00:49:00] And if you have two people doing, with that sort of professional expertise and all of that, it's not about the professional expertise. It's people with that experience, people who knew how simple it was. And get them looking at the web, there's going to be a lot of ranting about who, like how this really unusable programming system possibly came to be, and yeah, having PhDs it just means that we hav, it just means that we have like the fancy vocabulary in which to phrase those rants.  (laugh) But like we would have given up.

[00:49:35] And at a certain point we just said, well, like we complain about this so much, somebody should just build something like Visual Basic Adelphi for the web, it would solve so many problems.

[00:49:47] And like, I still have sort of trapped in Amber, the Google Hangouts message I sent to Ian, like one, one afternoon saying, this is a thing that, that really should happen. Just got like YES. In all capitals. And so like...

[00:49:59] Jason Gauci: Amazing. 

[00:50:00] Meredydd Luff: That's how it started. It was like, once we knew it was a thing that we could do, we couldn't not do it. 

[00:50:05] Jason Gauci: Yeah. That makes sense. So you were at some point a software engineer and you were, you saw first hand how painful this was and, how did you sort of make that leap to... so actually, well, let me step back. Are you doing Anvil full-time? 

[00:50:23] Meredydd Luff: Oh yeah. This is like, it started as a project with a friend, like it's now, a startup with nine people and growing nicely, thank you very much and profitable and all that fun.

[00:50:36] Jason Gauci: Yeah. And so, how did you take that leap? I mean, it's such a leap of faith, right? To say, I'm going to, I'm going to quit my day job and we're going to build Anvil and, and obviously in hindsight, it's going amazing, but how did you kind of muster up the courage to go do that?

[00:50:54] Meredydd Luff: So, I do think one of our greatest privileges being in this industry, is that there was less courage than it would have required for bending other people. Like, I have friends who are professional actors, like that was huge courage. They're working without a net. Like fundamentally, if it turns out, if it has turned out that nobody would have been interested in Anvil, I could have gone come and knocked on the door of a bunch of employers, and got a job fairly soon. And all that would have been would be a bit of missed earnings. 

[00:51:33] I, I do think that the, I'm not sure courage quite covers it. Well, maybe it's risk doesn't cover it. As it was, I was contracting at the time, Ian was working as a PostDoc at the computer laboratory here in Cambridge. And, so we, we already, like, we would meet up and work on projects in the evenings or weekends and so on.

[00:51:54] And so Anvil just became our, yeah, project at Ian's dinner table. And as we built more and more of it, we got more and more excited about it, yes, this could be a real thing. And so eventually we started, we went down to like four and then three days a week because, because we could work part-time cause, you know, we were young, fresh out of PhDs, there's not a lot of living expenses.

[00:52:19] But then, we eventually just thought, well, this is probably good enough, to see what the world thinks. And we put it up on Reddit. And Reddit just sort of bit our hand off. And we went, ah, okay, right? People really are interested in this thing. We weren't imagining it. Okay. Well, time to jump in. 

[00:52:39] And so we, we cranked ourselves up to full-time and we were just, I think we were, we were lucky because we worked in this industry, that we had the savings. We have the ability to go to part-time work and build up the business until it could support us. 

[00:52:56] Jason Gauci: Yeah, that totally makes sense. Yeah, I think that's great. Yeah, the part about Reddit really resonates. I think one thing, a lot of people, should be more encouraged to show things off. I think a lot of people are afraid.

[00:53:07] I remember when I was in university, I had some, some side projects that were, were terrible. And so I think, I think if you Google by name there's, there's some, I don't remember if it's Reddit or some forum, but there's some forum posts where I introduced some game engine that was in hindsight, absolutely terrible.

[00:53:24] And it got completely torn up, but it was, I learned so much from that experience and to this day, I mean, we posted about Eternal Terminal on Hacker News and all of that. And I think, being in those communities is actually something we didn't mention earlier. That's another thing that I think beginners really should do, is is get kind of, you get yourself enrolled in some of these, some of these...

[00:53:47] Meredydd Luff: Oh hey! Eternal Terminal is you! That's awesome. I didn't realize that. Awesome! Really, pleased to meet you!

[00:53:56] Jason Gauci: Cool. Yeah. I I'm thinking about replacing SSH entirely, which would be adding a lot more to it, but, a lot of people, the biggest complaint is that you have to open another TCP port, so yeah. We'll see where it goes. 

[00:54:11] Meredydd Luff: Awesome. But anyway, yes. And I saw it because you put it out there. And yes. I mean, we, honestly, we should have put Anvil out there like a year sooner probably.

[00:54:20] Jason Gauci: Yeah. Yeah. It makes sense. Yeah. I think it's hard to do because, you feel like, Oh, if I, if I make a bad first impression, but no one ever says, I put it out too early and I gave up on it. You always hear, hear things in the other direction. 

[00:54:39] Meredydd Luff: Yeah. I mean, I do think. Anyone, anyone who wants not to believe that, will believe that their case is special. I think Anvil is a little bit special in, because it's a development tool, and a development tool is kind of useful for everything or useful for nothing. And so there was a minimum level that we had to get it to in all of these areas.

[00:55:03] I mean, Anvil is a massive platform. I mean, we've, we've. Haven't touched on a lot of the stuff underneath the surface, but like it's, it's a serverless app hosting environment. It's a drag and drop designer. It's a web based UI toolkit in Python. It's a Python to JavaScript compiler. It's like off the shelf, user authentication. It's got integration onto Google API, Facebook, Microsoft, what have you, Stripe. It's a task scheduler because of course you've got to be able to run 10 schedule tasks and your apps. It's got the Uplink. It's got, I mean, I'm sure I'm missing stuff out.

[00:55:36] And we had this vision for, this is like, this is the end state we want it to be. This is what an ideal platform would look like. It would have all this power and be this simple. And we sort of, we kept measuring the difference between what we had and what it could be or would be, and instead, we should have been measuring the difference between what we had and what people were struggling with already, because that would've got it out the door a lot faster, 

[00:56:01] Jason Gauci: That is, you know, such a good point. Actually, the whole logging and capturing what people want. I feel like we, we desperately need to do a show on this. You build something, all of us when we build things, we build it ultimately for other people, because there's, if a thousand people are going to use your program, 999 of them aren't you. Right?

[00:56:27] And so, so you're building an app for other people. And you're making a lot of assumptions about what they want. Right? So for example, for a Eternal Terminal, in the first versions, it, it had a way of, it basically slowed down the delivery of contents that you could hit control C. So if you goofed up and, tried to KAT a binary file or something, you could still punch out, but then it turns out people just didn't want that.

[00:56:52] And there was just a bunch of issues. A whole bunch of people were upset about it or complaining about it. And so I took it out and people are much happier. But it's, it was just a lot of kind of trial and error and listening to issues and feedback. And there really wasn't any analytics. I mean, there's nothing that reports back from Eternal Terminal.

[00:57:13] And, and I think that that is such a missed opportunity, because there's just so many things that we have to learn the hard way. 

[00:57:19] Meredydd Luff: That is a huge advantage of running a hosted service. And that's, I mean, one of, one of the many advantages, it also means you like, you can upgrade, you can ship upgrades and you can ship rollbacks very quickly.

[00:57:29] I should mention by the way that, that there are disadvantages to being a hosted service as well. And if you think, Oh yes, this would be a, this would be great, but I couldn't possibly rely on someone else's hosted services for that. Like, we've got you covered. Don't worry. The answer is PIP install Anvil app server. All of the Anvil runtime stuff is actually open source. So you can just, you can self host an app. You can, in fact, you can build an app in a text editor and self host it and never touch anything owned by us at all, if you really want to, but otherwise you can build on Anvil and you can just clone it out of our repository onto your desk and then host it locally.

[00:58:04] But yeah, so local stuff is important and I guess Eternal Terminal is one of those things that kind of, that wants to be a local application, and something like Anvil kind of wants to be a hosted application. 'Cause, again, it's all about these escape hatches, you want to have, you want to have the escape hatch so that someone who says, Oh, I'm running this on a Raspberry PI it, I work at a TV station. We need to be able to carry on broadcasting if the, if the internet goes down, this has to be running on a computer in the building. True story. That's fine. You can do that. 

[00:58:36] But the 95% use case is, I didn't want to worry about servers. I didn't want to worry about hosting. I just want to click a button and have it there. And so Anvil kind of naturally gravitates to being a hosted service. If you want to solve the problems we're solving, whereas something like Eternal Terminal gravitates to being something that's running on your own computer. And I think people's perceptions about telemetry changed drastically because it's impossible to interact with a hosted service without creating logs. And I mean, we...

[00:59:07] Jason Gauci: Yeah, that makes sense. 

[00:59:08] Meredydd Luff: We are very privacy conscious with logs, check out our privacy policy. We really do not, we really put effort into, if you looked over our shoulder and you saw everything that we could see, you would not feel violated, that's the thing that's really important to us. But the bar for people, the expectations for downloaded program is, is somewhat different, I think.

[00:59:31] Jason Gauci: Yeah, totally makes sense. Yeah. I mean, any case you need to be very diligent about anonymization and, and you're really trying to look for a macro trends. Like, everyone who creates, the button widget and Anvil, do they create it once and then never again, right? That would be a sign that either there's something wrong with it, or people just were discontent with it.

[00:59:52] And, creating that, that, that basic telemetry and, you know, in a way that preserves people's privacy. I mean that, that, that could easily be a whole show. I mean, there's, there's a lot of content there. 

[01:00:05] Meredydd Luff: Yeah, we, we started, so part of the Starting Anvil story, I kind of alighted is that, when we, when it was just the two of us, we were getting started, we actually, we were able to work out of an office, in the computer lab, which is Cambridge's computer science department.

[01:00:21] And one of the real benefits of that is being able to just walk down the corridor and ask people in the security research group about problems like this. And that's something that's really valuable to us. 

[01:00:32] Jason Gauci: Yeah. Yeah. That's awesome. I think that was good. I think the, yeah, basically the, the nutshell is, and I don't know if there's good sort of standardized libraries for this.

[01:00:42] I mean, I know there's, there's like segment and some of these things for, for collecting analytics on the web, but I don't know if there's sort of something generic there, but, but yeah, basically, you want to try and get some kind of feedback to improve, improve your app and pay attention to all the issues and all of that.

[01:01:00] I guess that's the sort of mantra. 

[01:01:01] Meredydd Luff: Yeah. I think that's fair to say,

[01:01:06] Patrick Wheeler: Hey everybody, we have a new sponsor and that is ConfigCat. And I'm going to tell you a little bit about, what ConfigCat is. It is a feature flag service. You can easily use flags in your code with  ConfigCat libraries for Python, nine other platforms; toggle your feature flags visually on the visual dashboard; hide or expose features in your application without redeploying your code; set targeting rules to allow you to control who has access to those new features. 

[01:01:33] ConfigCat allows you to get the features out faster, test in production, and do easy rollbacks with ConfigCat's simple API and clear documentation, you'll have initial proof of concept up and running in just minutes.

[01:01:46] Train new team members and minutes easily. So you don't have to pay extra for growing teams. With a simple UI, the whole team can use it effectively, whether you're an individual or a team, you can try it out with the Forever Free plan, release your features faster and with less risk with ConfigCat.

[01:02:02] Check them out today at ConfigCat.com.

[01:02:05] Jason Gauci: Cool. Yeah. For people that don't know what feature flags are, it's you imagine you have something out in production and you want to change some kind of behavior. So you might say, now use this other database, but then you do that and then it broke and now you've broken it for everybody. And that's, that's kind of a nightmare. 

[01:02:23] So, so what you want to do instead is you want to try something out on like a few people, and then slowly kind of add more and more and more people. And one way to do that is to have a feature flag, have a flag says if this is part of my test group of people, then switch to the new database, otherwise use the old database and slowly like that, if becomes true for more and more people.

[01:02:46] And so ConfigCat is a service that kind of handles a lot of that for you. So they can like handle, deciding, like who gets the feature and who doesn't, and then you can go in their UI and change all of that, and slowly, slowly get it to a hundred percent, and they take a lot of that burden off you.

[01:03:03] So check them out. They're great.

[01:03:04] Yeah. So, so let's dive into the company. So is, is the company called Anvil? 

[01:03:10] Meredydd Luff: Oh, the company, the company is called the Tuesday Project Ltd. because Ian and I used to work on weekdays, on Tuesday and we had agreed many, many, many years ago that if a startup ever came out of this, it had to be called the Tuesday Project, and so it is.  (laugh) 

[01:03:24] Jason Gauci: The Tuesday Project. Very cool. So does the Tuesday Project have, like internships, cause there's a lot of folks listening who are in the process of trying to find a place to intern at, or find a place to work at. 

[01:03:36] Meredydd Luff: So the wonderful thing about living on a startup's timeline is that if you're recording a, an episode, that's going to air in three months time, I genuinely don't know exactly what the state of our hiring is going to be at that point. 

[01:03:50] I would strongly encourage anybody who's interested to sign up. Anvil is free to use it. So freemium, if you sign up for a free account, then you get like a banner on the top of your apps. And, and basically that's it. If you sign up for an account, and if you're on our mailing list, we will mail you when we are hiring.

[01:04:08] So, that's, that's the, that is the eternally true thing that we are expanding. We are growing nicely, and very happy about it. So if you are based in the UK, and you are interested in fixing web development, and being part of the team that does that, then. do, hop along and sign up for an account, or you can also go to Anvil.work/jobs. And if we are, if we have a hiring window open at that, at that point, then you'll see that. Otherwise, sign up for free and we'll let you know. 

[01:04:43] Jason Gauci: Yeah. And so what's a day in the life of actually, how many people work on Anvil? You said it's about nine people? 

[01:04:50] Meredydd Luff: This is again, and one of those, one of those, pieces of information, that's likely to go out of date, very quickly. But yes, there's currently nine of us. We're entirely bootstrapped. So we have not, at this stage taken any venture investment. We are funded entirely by happy customers, which is a really great place to be, from the perspective of one's blood pressure level, heading into a global pandemic, for example. 

[01:05:11] Jason Gauci: Oh my goodness. Yeah. 

[01:05:12] Meredydd Luff: Turned out to be fine, actually. It turns out that a massive change of working causes a whole bunch of people to need to build new processes really, really quickly. 

[01:05:22] Jason Gauci: Yeah. Actually, maybe a bit of a bit of a tangent, but what is your take on, venture capital specifically around things like developer tools?

[01:05:35] I, I feel like in that area, I mean, I'll give you my take upfront and then we can talk about it. I feel like the market is not really known well. And so, and so it's not clear, some of the venture capitalists want, they have really, really big ambitions. And so, for developer tools that might, going to venture capitalists might be a mistake because the market might just not be that big.

[01:06:01] And then you'll end up in kind of a bad spot. 

[01:06:04] Meredydd Luff: Yeah. I don't think insufficient market sizes are a problem. There are just shy I think of 10 million Python developers out there. And, many of, most of the  web rep, sorry, many, if not, most of the rest also do web development. So I think, I think we're fairly comfortable at the problem we're solving is, is sufficiently huge.

[01:06:24] I think it changes your distribution of outcomes. Taking investment can also really help you if you are not as lucky as you and I were. And you're not able to sort of slow burn and work on this part-time until it's something that's ready to show to the world and start selling.

[01:06:45] I'm not religious about this. I don't think that venture capital is a bad thing, even for development tools. Although I think the VC ecosystem writ large has swung and missed a few times on models for developer tools. And some of them have been more successful than others. I would say, Mongo DB was a win, Docker was a miss. Despite the fact that Docker has completely transformed its target market. It's, yeah. They're open source business models there. 

[01:07:12] Jason Gauci: Yeah. I think, I think Kubernetes kind of took all the actual like economic value. 

[01:07:18] Meredydd Luff: Yeah. I mean, well, this is, okay. Tangent to the tangent. 

[01:07:22] Jason Gauci: Yeah, it's true.  (laugh) 

[01:07:24] Meredydd Luff: Okay. This is a reason that developer tools are difficult. If you're starting a company and you are thinking about releasing your company's main product open source, and developers basically demand that at some level, for a lot of the tools that they will take seriously, you have to answer the question of what do I do now, I've given my whole part is away for free? 

[01:07:48] Somebody once who, I'm blanking on his name, once said to me that if you open source, you no longer have of a product, you have two products, you have one you sell and one you give away, and make sure that one that you're selling is actually worth something.

[01:08:04] This is, this has actually worked out really well for us because we do have the two products. We have the Anvil runtime for running your applications, and we have the editor for building them. And so we have open sourced the runtime and we still, you know, we, we still have something that is worth people paying for premium features on.

[01:08:23] But I do think that from the last few years, we can take the lesson that, if you are infrastructure, that will be built on top off, you'd better have a really good story for why the fate of Docker is not going to apply to you.

[01:08:38] Jason Gauci: Yeah, that's really well said. 

[01:08:40] Meredydd Luff: Rewinding, where were we before the tangents?  (laugh) 

[01:08:42] Jason Gauci: Oh yeah. So, so, okay. So we were talking a little bit about VCs. And then I think the question I was going to lead into is, is what, what is it like to work on Anvil? Like, like, I mean, I mean, okay, we can talk, pre-COVID, right? So, so, how is it different than, people have this vision, especially folks in, in maybe university that is vision, you come into the office, there's a bunch of cubicles. Everyone just sits down and no one talks to each other. You just write code, you all go home. It's sort of like the Office Space kind of model, right? 

[01:09:14] And so one of the things we try to do is ask people, what is unique about the sort of work environment. And, and so the workplace that you've set up and, and just, make, make it a little human, for folks out there?

[01:09:30] Meredydd Luff: To be clear, we are in the middle of a pandemic. We are working entirely from home. I desperately miss the office cause I really liked the people I work with. And I like, being there to hang out and have lunch with them and have interesting conversations. 

[01:09:42] I think something that is, I suppose, two things that make working at this company to be particularly fun. One in terms of like how much I enjoy being around the people is that because we make tools for developers, everybody in the company writes code. Whether they are showing people how to use Anvil or working on the core product or both, everybody is writing code. And so everybody, we sort of speak the same language and we all understand like other sort of deep visceral level, the problems we're solving and what isn't, isn't a good solution.

[01:10:19] And so it's really great fun that, we, we pull everybody from the, you know, CEO to the newest developer advocates into the design meetings. And that's really that, that, that, that part is really fun. 

[01:10:31] Jason Gauci: Yeah. I think it's great that you all can speak the same language because at my job, half of us are speaking JavaScript, half of us are speaking C++ it's just, it's just this mess.  (laugh) 

[01:10:41] Meredydd Luff: And we all speak, of course, a bunch of our team speak JavaScript because, we build the ambulator and the runtime, which means that we spend an awful lot of time, honestly, pounding our head against the desk and saying, I am, when some corner of JavaScript or browsers or HTTP bites us, we bash our heads against the desk and say, I am doing this, so that hundreds or thousands of other people won't have to, for whatever little feature we're working on. So yeah, that, that, that part is really great. And that kind of alignment.

[01:11:15] I think also kind of, because Python has a, both Python, the language and the problem domain we're looking at. And the sorts of people who are likely to know a little bit of Python, but not much else. And they are firmly within our, our sort of targets, means that we get to interact with a really interesting variety of people. 

[01:11:40] So, talk about, people who arrived in a steaming hurry having to build something. The microbiological diagnostic unit, a unit at, in Melbourne, in Australia, suddenly, sometime around the 20, or the beginning of 2020 acquired a really, really, really urgent need for a system they can just, toss a gene sequences of viruses into, and having phylogenetic tree of like, okay, that sequence matches something that came from the other end of Australia check, where did that person come in and check that flight, trace it to other people, our infection control measures in school, working like all of this really, really cool stuff.

[01:12:21] And I got to end it. I got to talk to this bioinformaticist, at the end of the year about like, how are people doing tracing in the pandemic? I'd like you to, what is, what does he use Python for? What, what tools is he building? How does there, how has that work being changed by the fact that it's all just sequencing? And now it's all data science, it's not so much bench biology. It's toss it all into the secret sauce and throw Python at it is now how they, how that lab works. 

[01:12:50] And like that's one example of thousands where people are doing interesting things that aren't, they're a little bit off the beaten track, because if you build something that enables the people who are, for whom building a web app wasn't accessible. If you make it accessible, just a bit more accessible, you will suddenly pull in all these people who are doing all sorts of non-traditional things and you will meet them and you will have a great time doing so.

[01:13:25] You also get to pull in like non-traditional staff. So, we have everybody from like, one of our developers who's sadly just gone on, on, on maternity leave. I mean, great news for her, sad for, sad for us. She's great. Yeah. just switched careers from a financial services, because she reckoned that programming was more fun and, we hired her, I think like six, nine months out of the boot camp. And, she hadn't really written Python before she got to us and that's actually great.

[01:14:01] We love hiring people like that because those people are our customers, right? She really deeply understands what it's like to be starting out on Python and web development, because that was her very, very recently. And now she gets to be at the leading edge of like, building the developer tool that solves that problem for everybody else.

[01:14:23] Jason Gauci: Yeah. That's awesome. Yeah. I think that would be so fascinating to meet the people who are, cause it's like, the people who already have a website, they have that inertia, right? They would have to, even using the things we talked about earlier, they still would have to deconstruct to some degree their website, but it's the people who are just starting, who are looking at this whole ecosystem and saying, okay, where should my first line of code go?

[01:14:50] And so, a place like Anvil gets a lot of those people. And I think that could be so exciting to see the next generation of web developers. Right? I think that's awesome. 

[01:14:59] Meredydd Luff: Absolutely. As you said, like the number of people who type Python, Python GUI into Google, and then keep typing, like variations on that, because they've learned some Python. Everything, everything so far has been really straightforward.

[01:15:11] You know, this next step, there must be a way that's this straightforward for the next step, right? It can't possibly be this difficult. 

[01:15:19] Jason Gauci: Yeah. What about for desktop? Do you, do you have an integration with Electron or something like that? 

[01:15:24] Meredydd Luff: We don't, it's something that people have periodically talked about. It hasn't, it hasn't risen to the top of our list. It's not like the thing that, that most affects people.

[01:15:33] Going back to, these people who's awesome to meet. I will take the opportunity, I'd resisted so far to plug our podcast because what we do is...

[01:15:43] Jason Gauci: Oh, go for it. 

[01:15:44] Meredydd Luff: About once a month, we get on a phone call with somebody who does something really cool and talk to them about what they do.

[01:15:50] So we've had like interviews with like TV broadcast engineers. Because, it turns out they were, they shifted shifting to broadcasting over the internet. They needed to completely rebuild the system that, when you, when you're like, when your satellite box isn't working and you call up the, the customer service center and they go sort of tap, tap, tap, tap, tap. Ah yes, sir, it appears that that thing, it can't reach the wifi. So, let's move it to a better place with better signal, that whole system that collects and presents those diagnostics needed to be rebuilt because they were shifting to internet streaming. 

[01:16:21] And, the, the great Anvil story in this is that, a TV broadcast engineer, who's not a web developer, was able to pick up and plug a web front-end into the backend systems that run their TV broadcasts that really easily without having to, learn five different programming languages. 

[01:16:39] But the really fun story for us is that I then got to interview with him, interview him. And I got to learn about how TV broadcasting works, which is something like I hadn't encountered in a million years. 

[01:16:50] Jason Gauci: Yeah. They're real programmers, right?  (laugh) The ones who are setting up the program for tomorrow's show. 

[01:16:55] Meredydd Luff: Yeah, absolutely. So, yes, it's really, really, really great meeting this huge variety of people who do all sorts of stuff. It's pretty fun. 

[01:17:02] Jason Gauci: Yeah, this is awesome. So the, how are ways that people can kind of get ahold of you and get ahold of, or, or learn more about Anvil?

[01:17:11] Meredydd Luff: Right. Well, the first thing to do is to go to Anvil.works and hit the Build link because it's free to use. We have a bunch of tutorials, try it out and see what we mean about how our development ought to be. So that's, that's the first one, if you want to find me. I am Meredydd on Twitter. That's M E R E D Y D D.

[01:17:33] You probably want to click the link to the show notes for that one.  (laugh) 

[01:17:37] Jason Gauci: What, what nationality is that? Is this, is that Irish? 

[01:17:40] Meredydd Luff: Welsh.

[01:17:41] Jason Gauci: Oh, Welsh, okay. Got it. 

[01:17:43] Meredydd Luff: Welsh is one of these languages. It's like Polish, it's 100% completely phonetic, but you show the letters on the page to an English person, and they ever make the most basic face.

[01:17:52] Jason Gauci: Yeah. Cool. I think, is Welsh is, is, so this is going to show my total ignorance of geography here, but, but Wales, it's southwest, right? Of, of the whole UK?

[01:18:04] Meredydd Luff: Yes. Wales is, on the Southwestern end of the UK. Most people who live there, speak English, but a lot of them are also bilingual in Welsh. That includes my family. 

[01:18:15] Jason Gauci: Oh, very cool. 

[01:18:17] Meredydd Luff: I feel like I've slightly earned the right to make everyone suffer through spelling my name. 

[01:18:22] Jason Gauci: Yeah, that's right. Yeah. I think, yeah, we'll definitely put, put links to the show notes and everything. And so, definitely check out Anvil.works.

[01:18:30] Oh, one thing we didn't cover that I want to circle back to really quick is, especially for students, what is free and then what costs money?

[01:18:39] Meredydd Luff: Right. Okay. So. What is free is pretty much everything I've talked about. So the design, the hosting, the serverless Python, the Uplink, all of that stuff is free. If you're using a free account, there are two limitations. One is that you'll get a banner on the top of your app saying, made with Anvil.

[01:18:58] And the other is that, we, there are going to be some limits to the libraries you can import in the serverless environment, in your server modules. That, and this is just because we're hosting code for, from, random strangers from the internet on our servers.

[01:19:17] Jason Gauci: So you're saying I can't train my neural network. I can't train my neural network using your serverless functions, and you have you pay for it, right? 

[01:19:24] Meredydd Luff: Correct. You can't train you on your neural network on our service, but if you want to bring a book up and connect it to the Uplink and train your neural network there, you could absolutely do that on the free plan. 

[01:19:35] Jason Gauci: Oh, interesting. 

[01:19:36] Meredydd Luff: So, yeah, the idea is that you can do everything, and of course you can use the open source app server, wherever you are, whatever you're doing. So there are, you can use everything in Anvil for free. What we do offer is pay plans so that, that make life easier for you that, take some of the sting out of the hosting. 

[01:19:55] You know, if you want to run a neural network, in the, in the cloud without having to worry about, Oh, this computer with a Jupyter Notebook must stay up at all times, then, you're welcome to take out a plan with us, that kind of thing. You know, you work on a team, you want to collaborate with your colleagues, that kind of thing, we offer that. 

[01:20:11] The goal is that anyone can, anyone can use it. It's, It's a real development tool, rock up and give it a try. 

[01:20:19] Something else I should mention, by the way, for all the educators listening. If you're using Anvil to teach a school or university course, all of the features are completely free. Just drop us a line education@Anvil.works. 

[01:20:32] Jason Gauci: Very cool. Good to know. Yeah. We'll have a lot of that and we'll have students asking their teachers to do that. 

[01:20:37] Meredydd Luff: Absolutely. Well, bring it on. 

[01:20:39] Jason Gauci: Cool. So what is your, the name of your podcast? 

[01:20:42] Meredydd Luff: Oh, Stories from the Workshop. You can get it at anvil.work/podcast. 

[01:20:47] Jason Gauci: Cool, okay. So we'll have all of this in the show notes. We'll have Meredydd's Twitter, we'll  have Anvi.work's links. So check out the show notes. If you're in your car or something, wait till you get home and then check out the show notes  (laugh) but, we'll have links to everything over there. And there's a ton of information. For folks that there, if you build anything with Anvil, even if it's your first hello world, drop us a line, send us an email, programmingthrowdown@gmail, send Meredydd an email, and come back at us. Yeah. We love to see that. 

[01:21:22] It is, it is so, so satisfying to see, hear stories from people and to see the things people have built. It's, it's a, it really fills our bucket. So definitely don't hesitate to reach out. 

[01:21:34] Meredydd Luff: And again, if you are interested in jobs, careers, internship stuff, again, sign up and just say it on our newsletter. And we will let you know if as, and when we are next hiring. 

[01:21:45] Jason Gauci: Yeah. And, and in the meantime, go to check out these things like, was it Skulptor? Is that right? The, the Python thing.

[01:21:52] Meredydd Luff: Skulpt. 

[01:21:52] Jason Gauci: Yeah, check out this technology. 

[01:21:55] Meredydd Luff: If you want to survey off a Python in the browser stuff. A colleague of mine actually gave a talk at PyCon UK last year. You know, Last year the conferences were a thing. So 2019, there's a webpage writeup. We can also put it in the show notes that's like comparing Skulpts and Bryson and Transcrypt and Pyodide and Piper JS, and like why we chose what, the choices, made the choices we did for, Anvil. So you can go check that out as well.

[01:22:21] And please do check Skulpt project. We always love getting more contributors. So yeah, so check us out.

[01:22:28] Jason Gauci: Yeah. I mean, there's, there's no better signal than that, I mean the ideal interviews or someone just sits with your team for a week, that that's my take on it. And so, and so there's no better proxy for that than, than someone who, who contributes.

[01:22:43] I know personally we've hired people who have contributed to our open source projects, so, so I have firsthand experience with that and, yeah, it's super important. 

[01:22:51] Meredydd Luff: So, I said that, Bridget, one of our developers just went on maternity leave, and, her, her maternity leave cover who is now being made permanent because he's so good, is somebody who was on our forums, contributing to stuff, maintaining open source Anvil components for other people to use. 

[01:23:10] And so by the time it got to the point of hiring, we just sort of, took a look at him and went, yeah, yes, yes. We definitely want to hire him. We have worked with him. We know exactly what he can do, sold. So that's routine, and yet he was also contributing to Skulpt as well, by the end of it. He's a really good chap. 

[01:23:28] Jason Gauci: Wow. Very cool. Awesome. Hey, Meredydd this was amazing. I'm really, I'm super motivated to try this out. I actually have a, have a project that I'm, I can try it out with, even today. 

[01:23:39] Meredydd Luff: Promise me, you'll send an email with the link. I really want to see it. 

[01:23:42] Jason Gauci: Yeah, I will actually. Yeah, I, I'll definitely do that.

[01:23:45] I hope to share everyone, the next, sort of thing that I'm trying to cook up and I think, I think Anvil would be perfect for it. So thank you so much. I think that this taught me a lot. I think it taught the audience. a lot about, about the web and about this new way of programming for the web.

[01:24:03] So this is a super exciting, I really appreciate you coming on. 

[01:24:06] Meredydd Luff: Well, I had a great time chatting to you, so thank you very much. 

[01:24:09] Jason Gauci: Cool. Thanks a lot. And everyone out there, thanks a lot for all of your support on, on Patreon and by supporting us through our Audible subscriptions. And everyone stay safe out there.

[01:24:20] I think by the time this, makes it to the air or maybe we'll have like the vaccine in many people's hands. I really don't know. It's all speculation at this point.

[01:24:29] Meredydd Luff: They've already started dosing here in the UK and I cannot wait to get back in and hug people and get back in the office and stuff. 

[01:24:39] Jason Gauci: Yeah, exactly. Yeah. Well, so everyone stay safe out there and we'll catch you next episode. Thanks very much.

[01:24:47] Patrick Wheeler: Music by Eric Barndollar.

[01:24:54] Jason Gauci: Programming Throwdown is distributed under Creative Commons, Attribution ShareAlike 2.0 license. You're free to share, copy, distribute, transmit the work to remix, and adapt the work, but you must provide attribution to Patrick and I, and sharealike in kind.


7 comments:

  1. This content is simply exciting and creative. I have been deciding on a institutional move and this has helped me with one aspect. engagement rings for sale

    ReplyDelete
  2. Get Shifting/Relocation Quotation from ###Packers and Movers Delhi. Packers and Movers Delhi 100% Affordable and Reliable ***Household Shifting Services. Compare Transportation Charges and Save Time, Verified and Trusted Packers and Movers in Delhi, Cheap and Safe Local, Domestic House Shifting @ Packers And Movers Delhi

    ReplyDelete
  3. This is a very nice one and gives in-depth information. I am really happy with the quality and presentation of the article. I’d really like to appreciate the efforts you get with writing this post. Thanks for sharing.

    Java classes in Chennai

    ReplyDelete
  4. Really well written article! This blog was... how do you say it? Awesome! {I honestly think this might assist with the situation.
    You really deserve a big kiss right now.
    This site looks just like my old website.|This sure is a whole lot to try and take in and I'm not sure if I can really understand what you are trying to convey.|This really solved my question.
    I am super impressed with your writing skills.|Do you have you tube videos on the topic?|I was shopping for a real estate the other day but I still This stuff is like vitamins for my mind. And to think, I
    부산달리기


    ReplyDelete
  5. Hello my family member! I want to say that this article is awesome, great written and include almost all important infos. I’d like to see more posts like this .
    Do check
    Paypal Login
    gemini login

    ReplyDelete
  6. This is a very nice one and gives in-depth information. I am really happy with the quality and presentation of the article. I’d really like to appreciate the efforts you get with writing this post. Thanks for sharing.
    Python Training in Bangalore

    ReplyDelete
  7. This post is extremely radiant. I extremely like this post. It is outstanding amongst other posts that I ve read in quite a while. Much obliged for this better than average post. I truly value it! apps like shein

    ReplyDelete