Hello everyone, thank you for having me here. It's a pleasure and honor. So we're gonna be talking a little bit about modern Python through fast API and friends. So first, a little bit about me. Who am I? I'm Sebastian Ramirez or Tiangolo. I'm in Berlin, Germany, but I'm actually from Colombia in South America. That's why the accent. You can find me on GitHub, LinkedIn and Twitter here. I'm currently a staff software engineer at Forto. Forto is doing a lot of advanced machine learning and deep learning and specific stuff for to improve the customer experience in space. And on top of that, I'm also doing some external consulting with some other things. And I created fast API, diaper and SQL model and a bunch of other officer's projects. So we're gonna be talking about modern Python. And when I say modern Python, I just mean the currently supported versions. So Python 3.6 and above, like previous versions are already reached the end of life. So this is just like the currently supported versions by Python. And that's what we're gonna talk about. We're gonna talk a little bit about f-strings, then a bunch about type annotations and then a little bit about async and away to performance and community. And we're gonna do it with a tour using fast API, diaper, SQL model and all their friends. So first, why am I giving you this keynote? I created fast API. And if you don't know fast API is a web API framework that provides high performance, easy to learn. It's fast code and it's ready for production. It currently has 35,000 GitHub stars and it's been growing about 1,000 stars per month or something like that. It's currently used by Microsoft or Netflix and a bunch of other companies. And the performance is in the top rank of what you can get with Python. And in the last official Python developer survey, fast API was the third most used Python framework right after Flask and Django, which is very cool. And in the latest Stack Overflow Developer Survey that covers a bunch of frameworks, languages and tools. It was in the category of web frameworks that includes frontend and everything. It was the third most loved technology. Right, the third most loved web framework, right on top of React and Dj, so it's super cool. A little bit about fast API and why am I talking to you here? So now let's actually start talking about modern Python. Let's talk a little bit about fStrengths. Maybe some of you already know about fStrengths. Let's just recap it quickly for those of you that haven't seen it. So we have these data structures here. We have some recipes that have some name. One is the crunchy frog and the other one is the albatross. And they have some ingredients, each one of them. And these ingredients are just some strengths. And we have a default price that is one. Now we have this function, get a recipe that will take a name, which is the name of a recipe and a quantity. And this quantity has a full value of one. So this is an optional argument. And then we just extract each specific recipe by the name and then we return that recipe. That's all we are doing. And then we are giving this message saying like, hey, this is the recipe for this thing. And we are formatting this string here saying, we put the name called braces inside of the string. Then we pass the keyword argument to format saying, hey, this is the name that should go inside of the string where that other name is there. And then the value that it's going to have is the value of this variable name that comes from the function parameter. And if we run it, then it works as we would expect. So we can get the recipe for the crunchy frog and we can see that it's a message. This is the recipe for crunchy dash frog. We have some ingredients and the total is one. And if we change the quantity, it also works. And we get the total is two. Nice, that works. But if we check it closely, we can see that the name here, this information about the name is actually duplicated. We are repeating information in the code in three places. We have name here, then also name here and then also name here. This name refers to this name here. And then this name refers to the one that comes from the parameter in the function. But actually, we can just change this string to be an F string just by putting the F before that. And now Python will know that it has to put inside of these code braces where we have this name. It would just put the variable with that same variable that is taken from outside inside of the string. So in here, it will put the name that comes from the parameter.  And that's it. And it's actually quite fast, the strings are faster. So that's very cool. And if we call it, it just works the same and if we pass the quantity, it just keeps working the same. Pretty simple, but it's nice to know. And now we can avoid having a bunch of duplicated and with stuff and we can simplify the stuff and make happiness better. Nice. Now let's actually switch to type annotations. And we're gonna talk a lot about type annotations and type hints. So what are these type hints and like, what is the deal with them? Let's say that now we don't want to print just crunchy frog and say this is the recipe for crunchy dash frog. We want to instead with a space here and we want to make this in the first C, we want it to be in capital and the F we want it to be in capital F. We want it to look like a name of a recipe, not just like an ID. But then we try to get out the completion to change this name and we don't get anything. And if you are not great at reading documentation and then memorizing each one of the possible methods. So if you are not a robot, then you will probably benefit from getting out the completion but we can't get out the completion here. The way this code is written. But we're totally fine without completion and type hints. We have lived our whole life without them. So yeah, we can deal with that, right? But we can actually change the annotation here in the function to say, to tell the editor, hey, this parameter name, this is a string. This should be a string. And that's it. This is all the change that we have to do. And now suddenly we have all the completion inside of the editor because now the editor will know that this parameter name is an actual string. So we can get out the completion for that. And because it knows that the result of name that replaces also a string, we can still get out the completion for the rest. So now we don't have to memorize or add the possible method. We can just use the auto completion to change replace the dash with a space and then make it in type of case. We don't have to remember what was the exact name. We can just use auto completion to get that. So we get auto completion and type checks by using type annotations. These type annotations or type hints are what powers auto completion and inline errors in the editor. And this is how the final title looks like. Now we put this title inside of the F string. So now when we run that code, we pass crunchy dash frog, which is the idea of the recipe. And now we get a message saying, hey, this is the recipe for crunchy frog. And this looks like a nice stack. And we use auto completion and type annotations to do that quickly and easily. Now let's say that we don't always want to have a quantity of one. Maybe someone only wants to get the recipe to not actually get one plate of this specific recipe. So let's say that we just changed the quantity to be nine. Yeah, it looks like a simple refactor. We just do that. But then if we call that function, now we certainly have an error. And the error says that we cannot multiply an integer with none. So default price was one, but now quantity is known. So we are multiplying one times none. This is an error. The annoying thing is that we have to run the program to actually see this error after the code was running. We didn't see the error where we were typing the code. We just had to run the code to see the error. But now let's say that instead of just saying quantity equals none, we tell the editor, hey, quantity is of type string. We tell the editor, what is the type of this parameter? And by default, this is none. And now, suddenly, because the editor now knows what is the type of this parameter. So the type of this variable inside of this code. Now we can get this inline error. And if we check it, it will tell us, hey, you're trying to multiply something that is a literal one. So this is an integer and none. And you cannot multiply an integer with none. So the editor is telling us right away that we have an error in the code without us having to run the code. And it's telling us exactly in the place where we have to change something. Exactly the place that has some problem. So these type annotations or type genes are protecting us from a bunch of bugs because they are detecting those bugs early. Like we, in many cases, we don't even consider them bugs because we just realize that there's an error and we just fix it even before running it for the first time. And let's see now, how can we fix that? Now that we see that there's an error, how can we improve that? So let's instead of returning the data right away, we're gonna create the result first and then we're gonna check if the quantity is none. Then we actually do the operation and we put the top out in this key. Now we are having another error here. So what's happening here? Let's check that. So the thing is that the editor is trying to be too smart and is trying to guess what is the type of these results. So the editor thinks that this result is a dictionary that has key strings like this message and ingredients and as values, the editor thinks that this dictionary has strings or lists of strings or sequences of strings. So the editor thinks that it cannot contain values that are integers because it's just trying to be too smart about it, which is normally great. But in this case, it's telling us something that is not really an error because we want a dictionary that has any type of value. So we can just tell the editor, hey, don't try to guess too hard. This is just a dictionary of anything. Don't try to guess what are the keys and where the value is, this is just a dictionary. And now the editor say like, okay, you don't want me to try to guess too hard. I'm just gonna guess that is just gonna take it as a dictionary of anything. And now we don't have the error here and we can just simply put the integer inside of this value. And let's check this with a little more detail. So the quantity is of type integer, but the full value is none. So the editor actually knows that quantity is an integer or none. And inside in this point, at this point, it is actually, it will be an integer or it will be none. But then where we are inside of the if block where we are checking quantity is not none. So inside of this if block, quantity can only be an integer because we already checked that it is not none. And the editor is smart enough to know that this is a new block checking if it is none. So the type that this can have inside of the if block has to be an integer. So it won't complain, hey, this quantity will be none or will be an integer because the editor already knows that by this point it has to be an integer. So it's actually pretty smart about this type annotations and how we use them internally. Now we are saying that quantity is an integer but by default is none. This actually doesn't make that much sense because quite quantity can also be none but we are not saying it here. So we can be a little bit more rigorous with that and more explicit and we can import front typing import optional and then we can declare quantity is an optional integer. This actually means that a quantity can be an integer or it can be none. This is what this optional thing means that it will be none. And we use it with square brackets like this ones. And this module typing, this is in the standard Python library, this is the standard way of declaring type annotations and not declaring that something will be this type or it will also be none. So nice. Now we are a little bit more explicit about what is the type of this quantity. So with type hints or type annotations we get a lot of help from the editor, other condition, in-line errors and all that stuff. And without that hints, we have just to deal with everything ourselves and wait for the errors to pop up once we are running the code. Some of the people behind these type annotations or type hints, this guy started the MyPy project and MyPy is the original language that was then converted to what was included in Python itself. So it actually started outside of Python and now it's part of Python. These type annotations started by the project that this person started. And then these other two guys have also been helping a lot with MyPy itself and also improving a lot of the type annotations in Python and how to declare more sophisticated things and how to simplify and improve how these type annotations work. And I just wanted to show you that this is just normal people behind the scenes doing a bunch of these advancements that we can then take advantage of and then we can use. Now we just talk a little bit about my Python with type annotations but now using fast API. So we are gonna have the same data structure. We have the same default price. We have the same function with type annotations but now we're gonna import from fast API. We import the fast API class and now we create an instance of this fast API class which is this app object and now we use this app to decorate the function and we are telling fast API, hey, whenever someone sends an HTTP get request so this is an HTTP get operation or get method and whenever that request goes to this specific path so it goes to slash, recipes slash and then this name, this is a path parameter. And you can see that we are using the same curly braces that we use for F strings. It's just that this one is not an extreme because we don't have an F here and because we don't have any variable name outside of it but we still use the same curly braces so we don't have to learn a new syntax. It's just the same syntax that we already use for that. But the thing is that fast API will take whatever comes at this point, at this place in the URL and this is a path parameter so it will read whatever is in here and we put it in this variable name. And then because this quantity is not part of the path fast API will read the quantity from the query parameters and it will expect to have an integer by default. It's gonna be just, no, nice. So to convert this code that we had we just added these three lines and now we have a full web API to get the recipes. So the more fast API code you write the less API code you write because most of the code will actually be about the business logic about the important parts of your application and adding fast API on top is just very little code that you have to actually write for fast API itself. And because we are using all these based on type annotations we get all the completion everywhere for everything just the same as we would with standard Python. So we can be happy as this cat without the completion. And we also get error detections or inline errors like this one. Again, because this is just based on standard type annotations. Now, if we run that application and we run that fast API web application just as I showed you the code and we go to slash docs we get this automatic interactive API documentation showing us the whole API. So we can see that we have a get request that goes to slash recipes slash and then this name is a path parameter. We can see that this name comes from the path that it's a string and that is required. And we also have the quantity which comes from the query parameters and this is an integer. And this is not required because we declare it as having by default none. And we can actually execute this request. So this is shown in the browser but we can actually execute. This is not only documenting the API this is actually interactive. We can interact with the API right from the browser. If we click execute then we're gonna get a response from the API that is running their lab. We can get the recipe for the Crunchy Frog with all the ingredients and all the stuff. So we just write some basic code and the good guy fast API will make a docs user interface for us. Now let's see, this is not only doing data documentation this is also doing data validation. So we say that quantity is an integer and comes from the query parameters. Now what happens if we pass a string like name? This is not really an integer.  But what if we try to cheat and send the request through the command line? Now we are sending hey quantity, this is nine. Now fast API will validate the data using the same standard type annotations and we're just gonna give us a nice error like this one that if we format it, it will look like this JSON. There is not only validating data and telling us hey this data is invalid is also telling us exactly how and where. So it's telling us hey in the query parameter quantity, the value is not a valid integer. So we were expecting an integer in this quantity and that's not what we received. So fast API without valid data is gonna protect our application from running within valid data. And when the data is actually valid and conforms to the shapes that we declared with these type annotations then it will all just work and just be executed right as we wrote it with the standard type annotations. So we are also getting automatic data conversion it's not only validation. If you see this quantity comes from the query parameters that means that if this is the URL slash recipes this crunchy frog, this is the path parameter that comes in here. So this crunchy frog is the one that will be in that name variable. And then this quantity, this is the query parameter that goes after the question mark. This quantity has a value of two but if you see this is a URL so this is just a very long string. Like it's naturally just a string and what is gonna be receiving server is just a long string. Fast API is gonna see that this quantity is declared as an integer and it's gonna convert the data from this string in the URL to the type that we declared in our application. So the code that we write is actually gonna receive an integer as we declared it. It's not gonna receive some string with the number two and it's gonna receive an actual integer. I can confirm that because then it's gonna execute that and it's gonna multiply by the other thing and then we get the total here. This is an integer which is what we are sending back based on the input which was also an integer. Nice, so this is all based on type hints. It's all based on the same standard type annotations or type hints. We're getting data validation, data documentation, serialization, all the stuff. And this is because Fast API is based on standards. So Fast API is based on Open API which internally is JSON schema on OAuth 2 for the authentication and all the stuff and because it's based on these standards we can get automatic API talks like this one that we see here. So this documentation is not part of Fast API itself. This is what is integrated in Fast API but this is actually provided by a tool called Swagger UI and Swagger is also based on Open API.  And because we are using standard type annotations for everything, we get automatic data conversion. Well, because we use the standard type annotations we get auto completion in the nerves and all the stuff that comes just by default in Python but then using the same standard type annotations we get automatic data conversion and data validation thanks to how Fast API works underneath and the tools that it uses underneath that we're gonna see a little bit more in a second. But now it's actually talked about more in Python with type annotations but this time with Typer. Now we're not gonna build a Web API. We're gonna build a command line interface application something to run from the command line from the shell. So now instead of importing Typer, we're gonna import, sorry, instead of importing Fast API, we're gonna import Typer. And now we create an app which is an instance of this Typer class. And now again we just decorate the function with app.command. So this is the way that we type it. Hey, whenever this app is executed in the command line this is the command I want you to run this get recipe thing. And now we are not returning something in our request so instead we're gonna print on the screen with Typer.exe. So we are just printing this result which is this JSON variable or JSON code. So we're just adding a little bit of Typer sal to the same function based on type annotations. And now if we execute it, we can just run it and then we are gonna see that we get an automatic help option that we can get, we can run to get information about this command line application that we built and we also get automatic data validation. For example, this name was required and we didn't pass it. Now if we actually pass the name, current you from, we get the response that we were expecting. And now because we declared that quantity was an optional argument, then this is gonna be interpreted as a command line option. So we can declare dash dash quantity and then pass the actual integer here. This is two and then we get the response back. So this again is all based on the same standard Python type annotations. And we also get a data validation. So if we pass quantity nine instead of two, then it's also gonna validate it and say, hey, this is an invalid value for quantity because we were expecting an integer and this is not an integer, this is just a string. So again, we get data documentation, validation and serialization all based on the same standard Python type annotations. But we also get auto completion in the terminal in the shell. If you create a package with Typer or if you use Typer CLI, which is this little tool, then you can install auto completion in the shell. And then whenever someone is running it, you can, for example, type dash dash q and then hit the tab key in the keyboard and it will auto complete what are the possible options. In this case, it's just quantity. So it's gonna auto complete quantity there. And you can get auto completion for sub commands and for arguments and options and all the stuff. And this auto completion works in bash, fish, C shell and even PowerShell which is actually quite complex to achieve. So you can get auto completion for the users of your command line interface application for features like using tech, which is very cool. So now you're building command interface applications with Typer just by using again the same standard Python type and notations. Now let's see how we can integrate it with some of the friends. So now we're gonna integrate Typer with Rich. So we import from Rich, we import the table, we also import this console class, then we create a console object and now we create a table. And then for each one of these ingredients in the recipe and all the stuff that we were wanting to do, we are gonna add a row with each grid and then we're gonna print that table using this console. And then we're just gonna print also the total that we wanted in the terminal using the same console. And now suddenly we have this very nicely formatted output shown information in the terminal just by using Rich integrated with Typer. So you can combine Typer and Rich to build very powerful command line interface applications using modern Python again. Now some of the people behind these tools, David Lord is the maintainer of click. Click is the library that does everything underneath of Typer. Typer is just a thin layer of click. It's like the actual thing that is doing all the work behind the scenes. And Rich was created by Will and Will recently decided to go full open source. So he's gonna, Will probably gonna see a lot of advancements and new features and tools from him, which is super cool. And again, as I wanted to show you, this is just normal people as always. This is just a bunch of tools built by very normal people just trying to help others. Now let's see, we can do more in Python with type annotations using fast API and now we're gonna use pydantic. So fast API is built on top of pydantic. Pydantic is the tool that does all the data validations, utilization and documentation underneath. It's all the tool that does all the data stuff underneath. So we can import from pydantic, we can import this class base model and then we can create a class that inherits from it. So we're creating a class food and then we're declaring that this has a name which is a string and then it has some ingredients which is a list of strings. Now, again, this is the standard type annotations that we will use. And if you have ever used data classes which is also part of the summer library, this is very similar, it's mainly the same syntax. This list comes from typing which is the same model that we used before. So again, this is the standard way in Python to declare that something is a list of strings. We don't have to learn some new classes from pydantic or some new types or something like that. We just use the standard Python type annotations to declare all this stuff. And then we just use this class food we put it in the parameters of the fast API function here. Now this is an HTTP POST operation or POST method and goes to slash food slash. And then we're gonna receive this parameter food which is of type food. So again, this is the standard way to declare that these parameters should be an instance of the class food. So we are telling fast API, hey, I want you to give me an instance of this class food here. And fast API will do that and will provide us an instance and will validate the data to make sure that we actually get a valid instance of this class food. And because this is an instance that we're gonna access the attributes like food.name and food.ingredients and of course get out the completion and all the stuff. So this food.name was declared here as a string and this food.ingredients was declared here as a list of strings. And if we check the interactive API documentation, it extracts the information from this pydantic mode to show us what is the example, what is the way the data that we want to receive. So name is a string and ingredients is at least a list of strings. And if we try to execute that, it's gonna actually send the data to the server. So we can say something with a name which is a string and then some ingredients and then the server is just gonna reply back and it's gonna, we're gonna interact live there from the browser with our API, which is super cool. And we also can do data validation with these pydantic modes. So let's see, this is actually valid JSON. So this is JSON, but the data is not exactly what we declared that we wanted to receive. So the name is a string, this is valid. The ingredients is a list or like a JSON array is the equivalent of a Python list. And the first item is a string. So up to here, this is valid. But then the next item, this is not a string. This is a JSON object or the equivalent in Python dictionary. So this is actually not valid. If we try to send this request, then Fast API is gonna do data validation using pydantic with that pydantic model that we declared. And it's gonna tell us exactly where the problem is saying, hey, in the body that you send in that request, inside of the body in the ingredients, the item at index one. So index zero is the first item, index one is the second item, a string type was expected and that's not what we received. So we are doing it, getting data validation even for deep nested data structures based on the pydantic model that we declared. Also notice that this is not some data shape that Fast API declared, this is a data shape that we declared, a data model that we declared with pydantic and we're getting validation for that. So what if we want to have some nested data? Now let's say that we don't want to receive a single order item, we want to receive a list of food items. So now we can put this, we can declare again, using the same standard type validation, this is the standard way to declare that something should be a list of instances of food and we're putting this in this parameter of orders. Now orders is gonna be an actual list of food instances. So we can iterate for each food instance in these orders. And then we can use that internally. So if we want to put JSON inside of JSON, we can just do that. We can build any complex arbitrary nested data structure that we want and we just use standard type notations with Python and pydantic to declare the shapes that we want to receive. And then Fast API will do all the data validation, serialization and documentation for us. And because we are using all this stuff based on the standard Python type annotations and using the standard type annotations very rigorously, we can get out the completion everywhere. So check this out. We are in a double nested for loop and inside of that we still get out the completion for each one of these ingredients. This is actually quite difficult to achieve without using standard type annotations. And this works because it knows that the ingredient is a string, but how does it know that? So it knows that orders is a list of instances of food. So for each food item in these orders, the editor will know that food is an instance of food. And then because we declared that food had some ingredients, then if we did it for each ingredient inside of this food code ingredients, the editor will know that this ingredient is also a string. And because it knows that it's a string, it can provide it to completion for strings in this ingredient. So we get out the completion even for this deeply complex nested data structures.  For our data shapes, for the shapes that we declared and that we need. We also get automatic error detection or inland errors because we are using the same type annotations. Again, this is a double nested for loop and the editor is still being able to know that, hey, you're trying to do this operation between a string and an integer and this is not valid. You have to compare one to the other or something like that. Now, some of the people behind the scenes, as I have been showing you, Fast API is built on top of by Dante for doing all the data parts and Starlet for doing all the web parts. By Dante was created by Samuel Covey, Starlet was created by Tom Christy. And also David Montaghi is another contributor to by Dante and Fast API, so the search mentions here. And again, this is just normal people, just building stuff and trying to help others. Now, please actually see how we can combine all this with SQL model. Using again type annotations with modern writing. So SQL model is a library that I released two or three weeks ago for two helping with interacting with databases using the same standard Python type annotations. So here we're creating, hey, this is a class, this is a model that is a hero model and it inherits from SQL model. And we're saying, hey, this is a table. This should be a table in the database. It has an ID, which is an integer. By default, it's known because we want the ID to be generated by the database, not by Python. And we are saying that this is a primary key. Then we also say that we have a name, which is a string. And this has to have a string. This cannot be none because this is not optional. Secret name is also a string. It has to be provided, cannot be none. Then age is an integer, but it can be none. So in the database, this can be null. Then we just create this engine. In this case, we are using SQLite. Would we could as well just use Postgres SQL or MySQL or MariaDB or anything else SQL provided by SQL Alchemy, which is what powers SQL model underneath. But I'll show you that in a bit. So we just create this engine. And then with our app, with fast API application, we use the on startup event. And in this event, we're gonna create all the data here. You could do this in a different way. For example, with migrations, but for this simple example, you can just create the database and the tables here. And then because this class that we created, this hero, the trick is that this class hero is a SQL model model. So the model built with SQL model is both a pydantic model and SQL Alchemy model. So it's a model that declares data shapes just like pydantic, but also declares the data in the database. So we can use it again here in the type annotations or here, which is the standard place where we put in fast API to say what is the shape that we're gonna return in the response. Then we can create a session here. And then because this is also a database model, we can just add it directly to the database session. Then we can commit and then we can refresh the data from the database and then we can just return that same thing. We don't even have to convert this to some other type. We can just return it. And then fast API is just gonna use that. Now, let's actually also create something to read all the possible heroes that we have in the database. We can again use the same type annotations like to describe that this is a list of heroes. This is the response model that we are using here. And this is the standard place to put it in fast API. This is not put here in the type annotations for some specific reasons that you can see in the documentation. But now we can declare that this is a list of heroes. And then we can create the session here. We can select all the heroes in the database and then we can just return those heroes. And now if we go to interactive API documentation, we can see that we have the path operation, the this route to get all the heroes and we have the one to create heroes. And because this model created with SQL model is both a Python model and a model for the database, we can again get the automatic information about the shape that we are expecting to receive. So IDs will be an integer, name is a string, secret name is a string, and H will be an integer. So we can have the database and data models without duplicating information and all based in standard Python type annotations. And because we are using these standard Python type annotations, we will get that to complete in line errors and everything in the editor. Now some of the people behind SQL models and some of the tools behind SQL models. SQL model is built on top of Pydantic and SQL alchemy. Pydantic does all the data validation, documentation and serialization and SQL alchemy does all the SQL parts. SQL alchemy is the most used library for interacting with SQL databases in Python. And SQL model just adds a thin layer on top of Pydantic and SQL alchemy. So again, this is just normal people building great tools for us all to work with. Now let's change a little bit the subject and talk a little bit about modern Python with async and await. So what is the deal with async and await? So here's the thing, Python running in the backend, running in a server is actually a very fast system.  Yes, it is slowly if you compare it to C and if you are building a kernel for an operating system, you will probably not do it in Python. But for everything else, you will probably build it with Python because Python is actually very decent for any other task. And particularly, if you are building web applications, the problem is not the server and how fast the code is. The problem is the network. Python is very fast when you compare it with the network. So if the network is super slow, how can we improve things here? So here's the first idea. What if we have one single backend in Python working with multiple clients and serving multiple clients? So that way, even though each network is super slow, at least we are serving multiple clients at the same time. And of course, this network is not related to Python. This network will be slow in any programming language. It's just how the network is. So cool, this idea sounds nice, but when we tried to use it in Python directly, the way that it would work just by default, you would actually not look that much like this. It would look more like one of these lines to paste stuff in the grocery store. So before this person here can buy their newspaper and groceries, they have to wait for this other dude to buy this drink. And this dude maybe is already a little bit drunk, so we'll take some time to get the money and we'll take some time to pay. And during all that process, in there in the front in the cashier, this dude just has to wait, wait and be waiting there because we're just all waiting for this one to finish. So it looks more or less like this. There's one client that sends one request that goes slowly through the network. Then it finally arrives to the backend. It's processed super fast in the backend. Then the response is sent through the network and it's slowly going back to the client. I know this will have to happen here before the next client can start their transaction with the database and start their request. So each client is actually waiting in line for the previous one to finish. So here's the idea. What if, well, before the API, this is what our API app has to do. It just has to be waiting for the network to receive and send all the messages. But this, now here's the idea. Well, we have a waiter that goes table to table, taking the orders, and then it goes delivering them whatever it is that they request. And it looks more or less like this. And this is where async and wait come to the, like show up in this. Let's say that each one of these claimings, it's sit in a table. So the waiter, which is just part of Python and it's just this mechanism with async and wait, the waiter will go to each one of the tables and will say, hey, what do you want to order? And then it will take the order and it will send the order, give it the order to our backend, to our code, which is our code written with async and wait. And then the code will be prepared up, but then this waiter doesn't have to wait for that to be ready to deliver the order. The waiter can already be asking the next client, what do they want? And then, for example, it will end up at this client and this might be my sister that is still deciding if she wants to eat chicken or fish and it will just take some time. So the waiter can see like, hey, you know what, just keep checking the menu. I will ask the next client. So the waiter can go to the client here and then the client can decide what they want to order and meanwhile, some of these dishes are already done. So the waiter can start sending the dishes to the clients while we are still waiting for some of them to decide what they want or because the network is very slow. So this is what async and wait provides, something like a waiter. And our application can be running all the time preparing dishes in the kitchen. Now, how this looks like in code. So in this case, we are using an example with HTTPX which is a great library for interacting with HTTP with to call other APIs. And this library, we can, well, we create the function for past API. We use now async because we want to use our wait internally and to use a wait, we need to declare the function with async and then we create this async client. And now this async client has this method.get and this will just send a get HTTP request. And then this client, the way that this method is defined in the internal code of client is that this method was defined also with async. And when it is defined with async, we have to call it with this keyword await. So to get the data from this, the result from calling this method, we have to put a wait here and then we can put the result in a variable. And this await, this is the key to everything. This await is the way that we tell that magic waiter, hey, this is a point where you might have to wait because this will be my sister deciding if she wants chicken or fish. So at this point, you might want to go and check other customers or other clients or do something else while we are waiting for this stuff to finish. So being able to define this is what allows our Python code to be executed in other different places in other functions and to be serving multiple clients, many, many clients at the same time, just by using this async and await. But of course, async and await, we need to have libraries that are compatible with this async and this await thing. For example, if we try to call a database with something that is not compatible with async and await, it will be equivalent to sending the waiter to prepare the dishes in the kitchen. That's not very efficient. So we have to be careful when we use async and await to make sure that the libraries that you use with async and await are actually compatible with async and await. But here are the good news. Fast API can be used with async and await or without async and await. So we can declare some functions like this, but then we can also, I will first, if we execute that, it will just work. We can just execute the request and then we will get the response and it will all just work just with async and await. But now we're gonna also declare some functions without async and then HTTPS is also compatible with blocking calls with non-async declarations. So in this case, we are just using get directly and then Fast API will do the smart thing and we'll actually run this stuff in a thread and everything. So the thing is that you can declare, you can write the code with just normal depth and then optimize only the things that really require the additional extra concurrency that really require to handle a lot of users of the same time and that you need it to be super fast. And then you can optimize those and put the async and await with the libraries that are compatible with async and await in those places as necessary. But then for the rest, you can just write the code very simply as this. So you can use with Fast API and HTTPS, you can just use normal depth functions or async depth and be happy. Cool, some of the people behind this async and await tools that I have been showing you. So Tom Christie is the creator of the HTTPS and Starlet and other tools. Florian Mumanca has been also commanding of HTTPS and you go doing is the author of the ASCII specification. This is the specification that Starlet and Fast API are built on top. So it's just a way to define how web servers in Python will interact using async and await. So these are like some of the people that are helping build the tools that allow these other tools and these libraries and these mechanisms to work. Now let's talk a little bit about performance with Fast API. When we talk about performance or this is talking about throughput or concurrency which is how many requests we can serve per second. So how many clients we can serve at the same time. And this is a benchmark run by Taken Power which is just a third party. They run benchmarks for a lot of programming languages and a lot of frameworks. In this case, we are filtering only by Python which are the blue lines and go lang which are the green lines. And go is a compiled language. So go has to be a lot faster than Python whenever it is used. Nevertheless, we can see that here's a block of Python frameworks for web APIs that can be faster than some of the go lang frameworks. So this is actually quite good. This is actually quite good performance and Fast API is here among this. Which one of this is the fastest? It's not necessarily that clear. This has some random noise. For example, Ubicorn is the server. This is not a framework. This is actually the server program that is running each one of those other frameworks. So Ubicorn has to be faster than anything else. So this has some random noise but still you can see that we can get on the ballpark of the best that you can get with Python. And well, Fast API is fast because it's based on top of the standard. And as you can see, we are being able to handle 15,000 requests per second, which is quite nice. So it's over 9,000 requests. Now, why is Fast API fast? Why is this performance? So Fast API doesn't really do anything fancy underneath. The Fast API is built on top of Starlet and Python. And Starlet is the web toolkit or micro framework that does all the web stuff. And Starlet is run by Ubicorn, which is the server program. And Ubicorn implements this asking specification. Starlet, of course, also implements the asking specification of Fast API because it's built on Starlet also implements the asking specification. But Ubicorn is built on top of or can be used with, by default, it uses UV loop. And UV loop is a high performance as in case you're dropping your placement. So this is a super fast way to do async and await. And UV loop is super fast because it's built on top of Python, which is a sort of compile Python language, something like that, to build C extensions for Python. Something like that. The thing is that this is a way to build super fast code that is compatible with Python and can be used from Python. Ubic loop is built using that. Ubicorn uses the UV loop and Starlet is used by Ubicorn and powers Fast API. Also, Fast API is built on top of Python. I think that was all the data validation, visualization and documentation. And Python is also built with Cython. So we get all the performance from this. So Fast API has good performance because it's built with high performance projects. And that's it.  Some of the people behind the scenes, Tom Christie again, the creator of Starlet, Ubicorn, HTTPS, and a bunch of other tools. Juni Silivano, this is the creator of UV loop. He's also the author of the async and await keywords in Python itself. And Stefan Benel is the maintainer of Cython. So this again, just normal people building a bunch of tools for us to work with. Now, a little bit about the community. As you can see, I have been showing you a lot of small pictures to show you that this is all built by normal people, mostly during free time and just trying to help others. And many of these maintainers might have hobbies, but in many cases, they just dedicate a bunch of time, a lot of time just to open source because this many cases just in free time. But you can actually help. For example, people translate the page of Fast API to help others be able to read it in a different language. Or you could review translations from others or you could answer questions from others in the issues or in Stack Overflow or things like that. Or you could even help with both some features. Or you could help with other projects with some of the projects that I showed you or maybe some of the projects that you are normally working with and using in your daily work. If you want to help Fast API, you can check this link. And if you want to help with the translations, you can check this link here. I encourage you to go and help the projects that you are working with and that you dependent because that's what these all depends on. And that's it. That's what I have for you. Thank you very much for having me. If you want to check the documentation for Fast API, you can check it here. And you can find me on github, LinkedIn, and Twitter. Now, I think we can check some questions. So, okay. So, thoughts on, actually, let me see. Can I move this over here so I can see it? Yes, nice. Thoughts on Psycho-PG3 with Fast API. So, Psycho-PG3, for those that don't know, is one of the drivers for interacting with Postgres SQL. And the author of Psycho-PG3 actually uses, actively uses Fast API, so he made sure that it works very well with Fast API, which is amazing. And Psycho-PG3 also has some improved support for async and await because there's also a async PG, which is super fast and also built with a Psython. So, yeah, it's a great tool and it's a very nice combination. So, let's see. What made you start the Fast API project? Did you have an instance where the solutions are available at the time who are looking for a task you wanted to accomplish? Yes, exactly that. If you want to read a little bit more about that in the documentation for Fast API, there's a section about alternatives and inspirations. And I tried to explain all the processes that I did. I tried to avoid building a new tool, a new framework for a long while, and I tried to use a lot of different combinations of plugins and tools. And at some point, I realized that there was none that was doing what I wanted based on type annotations, but having good performance, but having automatic integration with these standards and how all these tools put together. So I wanted to bring all the learnings from all the work that had been done by many other previous tools and many frameworks and even in all the languages and to put them together the best way that I put that. That's how I ended up building Fast API. So Fast API integrates other frameworks made by Bidantic and Starlet. Yes, that's correct. The development of Bidantic and Starlet is done separately. How do you plan to manage dependency issues in the future? So for example, Bidantic in its own test suite includes all the tests from Fast API. The author of Bidantic uses Fast API and is very involved with how these tools are integrated and they import and clone Fast API to run all the tests in Fast API to make sure that Bidantic actually works. And the author of Starlet is of course, also interested in having everything work with Fast API. And we're actually in constant communication. They are very nice people and I consider them internet friends sort of. So yeah, it's something that we are actually trying to build and to make sure that it actually works well. And of course, there's a lot of information in the Fast API documentation about how to pin versions to make sure that everything works correctly together. And Fast API has the versions very precisely defined to make sure that the dependencies are compatible and are correctly compatible, correctly having. Or you refer to a specific editor or plugin. So the good thing with actually with everything that I have been showing you is that it's all based on standard type annotations. This is all based on standard. This doesn't make anything fancy that is not just a standard Python. So all modern editors have great support for standard Python. The screen shows that I had where we PS code, but also Python has great support for standard type annotations. And in fact, the teams in PS code and in Python are like involved and interesting having great support for Fast API for these tools and have been doing a lot of work to make all these things work as best as possible. Is there any way to type annotations for our big Python projects? Are the tools to automate it? Yes, there are a couple of projects that you can run that you connect them to your application and you run them with your application and they save the types that they see that flow through your application to an internal database, to a SQLite internal database and then you can apply the type annotations from that SQLite database to the actual code. Sorry, to the actual code. So it's something a bit of a magical context but it can work in some cases probably in many cases. Of course, it depends on the project. If you have, for example, if you have a variable that you are overriding in a bunch of places and you are changing the type every time it's gonna be more difficult to annotate but it's also something that would probably be better refactor so that you are not changing the type of the same thing in multiple places. But yes, there are tools to do that and what I would recommend is to also adopt MyPy and include it in continuous integration because MyPy is the sort of the standard tool to check type annotations and it can be integrated with editors so that you can see the MyPy errors writing your editor in line. And you can configure MyPy to check Jallioli and to check some files and not others so that you can Jallioli increase the type annotations in multiple places. When integrating Fast API with ORMs wouldn't using context versus to store connection state cause a connection explosion problem since one thing can not handle thousands of requests. Was it going to start a subscription state? Yeah, well, so the thing is that with Fast API with ORMs, well, if you are using a, if you're using SQL argument or if you are using SQL or the documentation already shows you how to handle the sessions because it's better to handle the sessions a bit more explicitly unless you are an expert with context bars. I think it's easier to be explicit and to put them. And that's why Fast API dependencies work that way. And you can, I didn't show you any of the Fast API dependencies but there's a dependency injection system including Fast API that allows you handling all that in a very explicit way so that you can have a single session per request. But the session is actually not the same as a connection. For example, SQL Alchemy or SQL mode which is based on SQL Alchemy uses a connection pool and each session takes one of those connections and then returns a connection back to the pool when it's done. So you can have a controlled amount of connections to the database. But you can do all those things with Fast API dependencies in a way that is controlled and that is very explicit how you're handling it and to make sure that you're actually not stepping over different threads and things like that. How does Fast API decide whether the parameter that is not mentioned in the decorator integration should be a query parameter or something inside the payload. So if it's declared in the path parameter then it's just a path parameter. If it's not declared in the path parameter and it's a simple data type like an integer, a string, a flow or something like that then it's by default is taken from the query parameters. If it's a complex data type like a list or like a binding model then by default is taken from the body request. But you can configure all that and you can tell it exactly where do you want it to extract data and you can use that same mechanism to tell it to get data from headers, from cookies or from the query parameters or from the body explicitly. So you can also receive, for example, you can receive as a single string or a float in the body as JSON. A single float is like a single number. It's actually valid JSON data. So you could receive a single number as the body and you can declare that explicitly with Fast API. What is recommended? Mode of deployment of Fast API at separation that is for Wooski. So Wooski is a standard to define how servers, how application servers, so tools like Unicorn or Uwiski or things like that, run a piece of Python code built with a Wooski application like a Wooski application will be something like Flask or a Java. Fast API is not built on top of the Wooski standard with the ASSGI standard, which is more or less the same but using async and await. And the servers that you will use, the application servers will normally be Unicorn or Hypercorn or Daphne. And how you deploy in production, this is an interesting topic because the things that you want to make sure when you deploy in production is that the application is run automatically on startup. If you're running a single server and you start the server, you want it to be running automatically and you want to control how many processes are running at the same time. If you have four cores, you will probably want to have at least four processes to have one process running in each one of the cores. And then you also, so you want to have the replication. And you might also want to handle how much memory you are consuming. If you are doing machine learning, for example, that will consume a lot of memory so you don't want to have a lot of processes that they are all taking a lot of memory. Now, how you deploy that specifically depends on the specific architecture that you're using. If you are using something like Kubernetes, then you will probably want to run a single Uvicon container that is running a Uvicon process, a single process with Uvicon running your application and then replicate the amount of containers at the Kubernetes layer. But if you are running in a single server or in a simple deployment with Docker directly or with just Docker compose, then you can use the official FASTA API Docker image that runs Unicorn to execute the Uvicon and several processes at the same time based on the CPU that you have available. There is documentation for how to deploy a declaration or you could also use a third-party service like data or something like that. Or you could use, I don't know, serverless systems like the ones provided by Microsoft or AWS or Google or anything. There's a bunch of documentation about how to deploy this API. I have to update some of those things to clarify a little bit more, but there's already a lot of information on how to deploy a declaration. Yeah, so I think that's all, Sebastian. And that was really an amazing session and we are so honored to have you in Python India. And we really have a compliment for you, I think. So most of the folks are saying that, I don't know, you have a nice and sharp, nice thanks. It's really good to you. Thank you, thank you very much. It's been great to be here. Thank you very much for the invitation. It's amazing to be here, even if it's online. Yeah, thank you so much. Thank you.


Thank you once again as unfortunately, South Africans are protected as consumers or as housing consumers. Let me put it that way. Let me start with what we do as Master Builders South Africa together with our Master Builders Association. Every contractor that comes to Master Builders Association wants to be a member. There's a process in terms of which that contractor or that home builder, if you like, has got to subscribe to a particular code of conduct, the manner in which that person carries him or herself with his clients. Secondly, there's the aspect of quality. Our members are expected to be able to offer a certain type of quality before we can actually take them as our members. So there and there, as a housing consumer, you already have assurance that this person affiliates to this particular body. Therefore, as a result of that, I am likely to get a person that subscribed to a particular way of doing things and over and above that this person is a person that is able to do what he says he is going to do. Another point that I need to make, we also deal with dispute resolution. Dispute resolution that also protects housing consumers as well. If you come to your local Master Builders Association and say, this is your member and these are the challenges that we have in terms of the contract. We are able to look at the contract and find ways in which we can assist you to deal with the problem. Let me go to the legal protection, which is in terms of the Housing Consumer Protection Measures Act of 1998, if my memory serves me well. That is an act of parliament that protects housing consumers against housing defect. But the protection only happens if you have appointed a builder that is registered with the NSBRC. If that builder as well has actually enrolled your house before the house is being built. So NSBRC has got its processes of making sure that the people that are registered as home builders and the people that are enrolling homes of housing consumers are actually in a position to discharge their role. So if it happens or should it happen that the house is not of good quality, you are able to go to NSBRC and make a claim so that contractor will be required to make good the defect. In the event that the contractor will not be able to do so, NSBRC assures you that quality. They come in and correct the defect on your house. So those are some of the protection that South African law offers to housing consumers. So that is there, it has already been there. We urge housing consumers to make sure that before their homes are being built, those homes are enrolled and those homes that are registered with NSBRC as well.


Selamat tinggal, saya ialah Michael. Saya adalah... Seperti yang saya katakan, saya seorang perempuan sg. Sebenarnya... Saya akan berkongsi sedikit tentang apa yang kita lakukan. Satu-satunya perkara yang kita lakukan untuk ini. Sg Engeniasa adalah website yang mengenai perangkat yang berlaku di Singapura. Jadi, kita mengenai video yang kita gunakan online. Anda dapat periksa sg. Tapi hari ini, saya akan berkongsi sedikit tentang... ...berkongsi perangkat anda di permulaan. Jadi, saya belum membuat periksaan. Saya hanya mempunyai Google Doc dan saya harap anda dapat melihatnya... ...dan melihat note saya dari sana. Jadi, kenapa anda mahu melakukan perangkat di permulaan... ...semasa ada banyak pilihan di cloud? Sebenarnya, beberapa sebab saya telah melihat dalam masa lalu. Sebenarnya, beberapa sebab saya telah melihat di permulaan. Sebenarnya, yang pertama adalah sebab sekuriti. Sebenarnya, seseorang berkata, Hey, anda harus melihat... ...saya harus melihat informasi yang terkenal di permulaan. Dan tidak hanya informasi yang terkenal... ...saya dapat melihat di cloud. Jadi, bagaimanapun, di Singapura... ...saya mempunyai perangkat yang tidak terkenal... ...dan kelihatan, dan kelihatan. Jadi, bagi beberapa kelihatan sekuriti... ...saya juga mempunyai perangkatan... ...atau bagaimana anda dapat meletakkan informasi. Apabila anda melakukannya dengan data bank... ...data Banking, apabila banyak informasi pengguna... ...saya mungkin ingin melakukannya di permulaan... ...sebelum melakukannya di public cloud. Atau ia boleh menjadi kelihatan regulasi. Ada beberapa kelihatan dari... ...kalau ada bank... ...mungkin ada beberapa kelihatan monitor... ...atau anda perlu melakukannya di permulaan... ...dan anda dapat melakukannya di perangkat... ...dan sebagainya. Di perangkat, ia adalah perkara lain. Kadang-kadang, anda hanya ingin melakukannya... ...dan anda ingin melakukannya di permulaan... ...untuk memastikan tidak ada yang dapat melakukannya. Kadang-kadang, anda tidak ingin melakukannya di public cloud... ...atau di Heroku. Kadang-kadang, apabila anda melakukannya di public cloud... ...saya boleh menjadi lebih kelihatan. Apabila anda melakukannya di CPU... ...atau per jam, per minit... ...atau sebagainya. Apabila anda melakukannya di serverless... ...teknologi, anda boleh melakukannya per kedua... ...tapi secara kelihatan, anda melakukannya banyak. Apabila anda melakukannya dengan mempunyai data centre... ...atau di data centre, ia adalah sebuah kursus. Anda membuat kursus yang tersebut. Anda membuang masin ini dan... ...tidak ada kursus yang tidak ada diambil... ...sebelum elektrisiti. Apabila anda melakukannya di public cloud... ...atau anda melakukannya di dalam... ...selepas sejauh, anda melakukannya lebih... ...di public cloud dan membeli servis fisikal. Sebabnya, sebabnya anda mungkin mempunyai... ...atau di perusahaan saya yang tersebut... ...saya sudah mempunyai data centre sendiri. Dan mereka akan mempunyai data centre sendiri. Bagaimana anda membuat kursus di public cloud? Ya. Kadang-kadang, anda akan mengatakan... ...bukan pasti ia akan berjaya. Ada beberapa orang akan mengatakan... ...tapi public cloud... ...tapi kenapa anda membuat kursus ini? Dan kita dapat memperlukan banyak duit... ...untuk membuat kursus di public cloud. Jadi, ia ada beberapa sebab yang saya telah melihat. Saya tidak pasti jika anda telah melihat sebuah sebab lain... ...tapi ini adalah sebuah yang saya telah melihat. Jadi, jika anda membuat kursus di public cloud... ...di perusahaan... ...saya akan tanya kepada kami... ...berapa serius anda? Maksud saya, anda hanya... ...menjelaskan dan menjelaskan? Atau anda... ...atau anda sudah mempunyai idea... ...atau anda sudah menjelaskan... ...atau anda pasti anda ingin melakukan ini... ...dan ini adalah data produksi... ...tapi anda ingin memprodukkan. Jadi, hari ini... ...saya akan mengatakan lebih banyak... ...sebahagian eksperimen... ...sebab ia lebih banyak... ...tapi sebahagian lain... ...saya akan memperkenalkan Ruby dan Rails... ...untuk perusahaan anda atau perusahaan anda... ...untuk pertama kali... ...dan anda tidak mempunyai banyak pengalaman... ...atau anda hanya ingin membuat... ...memperkenalkan dan memperkenalkan MVP. Mereka ingin memperkenalkan sesuatu yang mudah... ...yang dapat memperkenalkan idea anda... ...dan kemudian untuk memberitahui... ...pengalaman yang anda dapat... ...memperkenalkan sesuatu yang mudah di Rails... ...dan orang dapat menggunakan itu. Jadi, ia adalah idea itu. Jadi, ya... ...atau di syarikat yang saya dulu... ...masukkan... ...Ruby... ...saya merupakan perkara eksperimen... ...sebab kita tidak mempunyai... ...saya memperkenalkan... ...saya memperkenalkan perkara... ...memperkenalkan perkara ini... ...punyai Pivotal Cloud Foundry... ...yang adalah... ...platform-platform-platform... ...tetika sebelum kita memperkenalkan... ...platform-platform-platform... ...kita mahu memperkenalkan... ...yang dapat kita membangun... ...masukkan aplikasi yang mudah... ...dan memperkenalkan bagaimana... ...mereka memperkenalkan itu. Jadi, ya... ...biasanya ketika anda memperkenalkan pemeriksaan... ...yang tidak ada cloud... ...tidak ada cloud... ...tidak ada cloud... ...berkawasan data yang anda dapat melalui... ...tidak ada auto-deployment... ...sebagainya. Jadi, terutama anda perlu membawanya sebagainya... ...tidak ada cloud... ...tidak perlu mengawal, bahawa anda tidak mempunyai cloud. Bagi ini... ...kalau anda melihat... ...berkenalkan reka... ...tidak ada pemeriksaan. Fika saya mengapa... bagaimana perkara lain yang memutuskan saya untuk melakukan yang terbaik sehingga saya dapat di sini. Kita sangat menggunakan perkara seperti GitHub, dan keadaan CII, atau CIRCL, dan keadaan perkara lain, semua keadaan, dan sebagainya. Kita akan mengambil semua perkara yang telah digunakan, sebabnya ia sangat mudah menggunakan. Tetapi pada perkembangan, kita menggunakan banyak perkara sendiri. Kamu perlu melakukan banyak perkara sendiri. Selepas itu, kenapa perkembangan kamu berada di perkembangan? Pertanyaan adalah, kamu menggunakan perkembangan virtual? Atau kamu perlu menggunakan perkembangan bagi perkembangan? Perkembangan perkembangan adalah sebagainya seperti perkembangan fisikal yang kamu perlu menggunakan untuk menggunakan perkembangan O.S. untuk menjadikannya dan sebagainya. Jadi, kamu perlu menggunakan perkembangan virtual. Kemudian, perkembangan adalah bagaimana kamu dapat mendapat keadaan? Bagaimana kamu menghubungi keadaan? Dan bagaimana kamu berguna menggunakan perkembangan virtual untuk kamu? Kamu perlu menggunakan perkembangan virtual dengan perkembangan IT untuk menggunakan perkembangan virtual. Kamu mungkin mahu mempunyai perkembangan fisikal. Kamu mahu mempunyai perkembangan virtual untuk membuat perkembangan virtual. Jadi, kamu dapat mengubah keadaan. Dan bahkan sebuah leon yang penuh berkuali dengan nama domain yang boleh kamu berusahkan. Jadi, secara dalam, kamu boleh mixedgurkan ke Keramu, memetik URL atau kamu dapat melihat ke dalam. Sebalik lagi, apa perkembangan operation? Apakah perkembangan operation yang kamu gunakan? Saya k sergeman itu mengenali bagaimana kamu akan melepaskan ruangan perkembangan danetician di sebuah mesin. So in many cases if it's a Linux server running Ubuntu or maybe Red Hat and you probably have a few things you can do. Next thing in mind is do you have internet connectivity. So for example if you're doing this on premise and your your machines have full access to the internet. So that means things like bundle install will come quite easily. Because as you're building an application on Ruby and on Rails you probably need to download a lot of gems. Ruby gems and stuff. So you probably need to you want to be able to have internet connection. And sometimes so you don't have direct internet connection you probably will have a proxy server. So if you have a fault proxy then you probably need to set some environment variables like say HTTP proc. Oops, what did I do? So HTTP proxy. So this is probably important to set up or HTTPS. So these are probably two things you want to set up in your environment so that you can actually go online. So let me just format this. Next thing you want to ask yourself, do you have root access? Do you have root access to the machine? Because in the server you probably need to install a fair bit of software. So you probably want to ask and make sure that you have some form of root access. Or maybe at least some sudo access so they can install software packages. Because a lot of Ruby packages, Ruby gems will probably require some native libraries. So you want to make sure that you have some form of access to be able to download or install additional packages that's needed. Like say if you're on red hat, you won't be able to do some RPM install or YUM install to install additional packages that's needed by some native packages needed for the gems. Next question in my mind would be do you have a budget? Do you have a budget? Is that a small claims purchase you need to do? Or is it some internal transfer of money so you can actually go about getting all this done? So up here are all the really administrative things you probably need to get clear before you want to jump into this. Next thing to do is probably if you're given a VM, it probably will be a Linux VM. So you probably want to find out how much you know about Linux server admin. So you probably need to figure out how to actually login using SSH and then change to the sudo user to do the install and packages. So as one website that I used to go to is called How to Forge. So How to Forge is quite helpful.  And you'll see a lot of fabulous instructions on how to do stuff. So I recommend checking it out if you're really total nuked with managing your own Linux servers so that you can at least get some experience with that. Otherwise, you'll probably have to rely on some DevOps folks that can help you, who can sit with you and probably give you some advice on how to do stuff. So you've got your server, you've got your server figure out, you've got to use a VM, and you've picked up some basic Linux server admin commands. So next thing you want to do is now to actually start installing Ruby on this server. First up, you want to make sure you can install Ruby. And there are many ways to do it installing Ruby. Like how we do this on the local develop environment, we want to have some form of version management of Ruby. So you can also do the same thing with RVM. RVM has a package called Ubuntu RVM, which lets you install, it's like an installer.  So the instructions here are quite straightforward. As long as you have sudo access, you probably can install, you need to install some additional packages, and then you can do the RVM install. Once you have this installed, then you have Ruby in your machine. If you don't like RVM and you're not familiar with how to use RVM, there's also RVM. So you can use RVM to do the installation. So with RVM, there is an RVM installer package as well. So you can install both RVM installer and RVM doktor. So it's kind of both. And both of this does require you to have Git installed on the machine. So that's probably one of the first dependency to do, to install Git on the server that you're using. So you can just use Git straight up to just install RVM. So once you have RVM installed, you can switch to the user and then you can do stuff. There might be a situation where your DevOps folks or even your IT operations folks will tell you, hey, we only support Java on our server. Or you can only install Java there. So for those folks, you can actually try using JRuby. JRuby is basically Ruby running on the Java virtual machine. So Java runtime. What I like about JRuby is that it's just one single file. It's one single file you just need to download. And once you have this binary downloaded and put in the correct folder, you can basically start using JRuby. And I think the latest version supports up to Ruby 2.5, which is 5.5x, which is kind of nice. So yeah, so I've used this in one of my previous clients place. So basically, it's also quite a lockdown environment. And they basically have to... So the only thing you could install there was a Ruby package. And then we basically found that you could use JRuby. So another question you might also have is, what if you don't really have a Linux server, you only have a Windows server? So this is where it gets a bit trickier. So if you're on a Windows server, there are also some options you can try. As one is a Ruby installer for Windows. So you can use Ruby installer to kind of like... This is a package provided by the Ruby language maintainers. So you can use this to install Ruby on Windows. And then you can basically start running this on your Windows server. For example, if you are only given a virtual machine that runs Windows Server 2008 or something. So you probably want to use something like this. Of course, in a more modern system, you can also try and get the Windows sub-system for Linux installed as well. So I'll share this... Wait, let me share this Google Doc. If you can... Let me try and share this Google Doc with you guys so we can actually go in there and see. Right, there's also another document which I prepared some time ago for this thing called Tech Ladies. So we did Tech Ladies Bootcamp and we have some of our participants who are only running Windows. So this is basically the setup that we use. Basically, you first have to turn on developer mode in Windows. Then you enable the sub-systems and you set up bash on Ubuntu. So there's a few simple steps. So in any case... Right, so that's all there is to the installing Ruby. So once you have Ruby in there, so the next... Ya, I will definitely put all this information into GitHub issue as well. So I will add the link to the GitHub issue. Anyway, right, so you now have all this... Ya, I have Ruby installed on your machine. Great, there's a virtual machine. So what's next? So up next are some of the considerations when developing your application for on-premise. First up is what kind of databases are you going to use, right? So your server actually support that database that you want, say you're using Postgres, MariahDB, or SQLite. So if you really want something really simple and you're just experimenting, you might just want to install SQLite so that you can basically do this without installing additional stuff.   You might even want to go with you don't even need a server at all just run everything in memory. So there will be another option. There's an API server. You want to test something or JSON. So you can basically spin up an API server using real status API and even turn off the active record. So you don't need to even bother with the database. Just deal with Ruby objects running around. Next question in my mind is how do you actually have access to the internet to do bundle install? So something to think about running things on premise already doing developing in Ruby on Rails, you want to do bundle install and you download the whole internet for all the gems that you need. Usually you will need to have access to Ruby gems website so they can actually do to get the actual packages that you need. But in cases where you don't have actual internet access on the virtual machine what you could do is use environment your development laptop. I'm sure I assume your dev laptop has at least some internet connection on the dev laptop. What you do is do a bundle install first and then you do this package called bundle package. So bundle has a way of downloading all your gems and putting them into a folder called vendor cache. So it means you basically can download all the gems that you need and put it into a cache folder and you need and then you basically check in this folder into your Git repo and when you check out the folder on the server, you just type bundle install dash dash local. So what this will do is refer to the vendor cache folder and just install the gems on your local machine rather than going to the internet and downloading it. So it's quite convenient so next the next question is do you have Node.js on the server as well because i think right now nowadays we use webpack and even the old sprockets as a compilation you need some form of java on the javascript environment so for example in some of the older Rails apps you can use Exact.js Recently I've been using something called Mini I think it's MiniRacer MiniRacer, RubyRacer So these are the few you can use to basically also run and compile your assets on the server itself but even in a situation where you really can't get javascript or Exact.js or anything on the server side what you can do is pre-compilation on your local machine public assets folder and we check in the folder and you don't need to do the asset compilation on the server side So these are some of the considerations you should take note of when developing for an on-premise environment Next thing is now you've written your app you've developed your app, you're ready to go Next question is how you deploy it so you don't have a Git server where you can do a Git pull from you can just simply zip up the folder and SCP the file onto the server or if you have Git, that is very much easier so just make your server you can just lock in there and just do a Git clone or Git pull so you just get the latest copy of the changes here there's even a more advanced way where you can set up your virtual machine as a Git server so you just push the folder in the server so there's a bit more advanced but i'll probably try and find the tutorial and share that and running your app on the server is also there's some considerations first up you can run your Rails server just by typing bundle exact Rails Rails S and what you do is oh i've left out something, bundle exact Rails server just do simple bundle exact Rails server which basically starts up your Puma server and because you want to run this in production mode you basically put in the Rails end so tell it that i'm running this in production mode bundle exact Rails server and you do a dash D to kind of make it go into daemon mode so once you run this, you basically go into the background so you don't need to have your SSH session on all the timer what nothing you want to do is also bind it to a public IP so on the server itself, you bind it to the local IP which is <IP_ADDRESS> but you're running this on the server side you probably want to bind it to the network port to the network card which is attached to the public so that you can actually open on your browser, on your local machine and then view the files there so as a rule you bind it to <IP_ADDRESS> which means you bind to any port any IP that the virtual machine has access to or if you're really kind of locked down you probably want to then bind it to a specific IP address in my case in this case i'm also pointing it to port 3000 so it's a default port so if you run some Rails server it will open up in port 3000 but you want to host this from port 80 you can do that as well you can do this in port 80 so it opens up as a default default port but then again it depends a lot a lot of this depends on what your firewall rules on your virtual machine so you probably need to check out what kind of ports are open for you from the firewall on your local server and another thing about on Linux servers if you try to host something in port 80 you need to be rude you need to be a pseudo user so suddenly take a lot of people doing this so usually i'll just go 3000 and then i can just see everything on port 3000 so basically once i run this line i should be able to see my app running on port 3000 from the URL which is given to me so if your server itself for example is running so it's an example if you're using it you have the IP address 123.2.2 for example you know the IP address you can just go straight to it or you already have a fully qualified domain which is attached to the thing like for example rails experiment for example you have something like this then you can probably use this as a way of reaching that server and of course port 3000 so this will be probably something you want to ask your ops team what have they given you or what IP address they've assigned to the server so that you can basically kit it now a few things you want to take note of when you're running this on your local on the virtual machine is that there's a couple of rails environment environment variables you want to set up when you're running in production mode you want to set up the secret key base i think a lot of us will redo stuff in hero cool we don't actually need to care about the secret key base because it's also generated for us but if you're running this on premise you probably need to be mindful of this one which is a secret key you need to set up rails will just blow up if you don't have this have this environment variable set up and also you want to turn this on in rails 5 onwards you set this environment variable your real set will then be able to serve all your static assets so do be mindful of that another thing you want to take note of is this thing called asset host so in your production.rb you probably can see this so it is helpful for setting up like cdn so for example you will testing your assets on a different server from your real server so you can actually set this up separately so these are 3 notable environment variables you want to set up maybe you might also want to use something like .m so if you use .m to kind of manage your environment variables all you need to do is to place all the in a file called .emv so once you have the .emv file it's a lot easier to manage it so otherwise you need to figure out how to actually update the batch RSE or some other thing in your server so they have all these environment variables available so it's probably not that easy and straightforward if you're not experienced in managing the servers so you can use something like this and all you need to do is save a .emv file and then you basically have access to your rails set up and you have all the environment variables that you need let me just include this link here so you can use this let me just include this link okay so let's running your rails app just simply using the railserver you can just use 4man so using 4man you can run multiple processes in 4man so you can run your railserver and your sidekick background worker and all from one command line and all you need to do is keep a file called proc file so it starts the main main process and opens up a few other processes so you can run the railserver plus your sidekick or if you're using some chronos for your scheduled jobs you can actually run all 3 process from one place okay don't start doing this or rather really no frills way of doing this is to basically first of all access into the remote server so it's a teamwork session which is a dinox multiplexing so basically we can think of it as tap browsing on the terminal so you just run teamwork and running teamwork into the shell and basically you start the process basically type 4man start in the folder and then what you do is you exit or detach from the teamwork session so you always have a terminal session running there in the background and you have 4man running as well if you're a bit more experienced managing servers, you can always use 4man and use that to export into something like upstart or systemd these are kind of like process initializers think of it as startup scripts that run when your server starts up so you can use this for example in the case of 4man you can do an export and you can export into either upstart or into i think you can also do is it here upstart so you can look at the man page you can export into systemd so we should basically it shows you how to you export some into the operating system to tell it how to start up this process as the server starts up or if you're using another version of Ubuntu you probably want something upstart for that and a few others here you can try so this is another way of running your server using 4man so these are all the examples that you roll your own you roll everything you basically install ruby you install you install ruby on your own you think about how to develop your app such that you have to roll everything on your own how to deploy it, you do everything on your own you learn how to actually start the server start the real server on your own so it's a lot of this roll your own stuff but there's also an option which can make things a bit easier which is to have a fake cloud fake cloud basically in form of cloud-like things for yourself for example, we can roll your own using docker community addition so basically install docker on the server itself and then use things like docker compose to start up your Rails app along with supporting services like Postgres, Redis and a few other things you can use docker compose to start it all up if you also want something simple, you can also use doku doku is a very nice it's a mini platform and a service so think of it as Heroku, but on premise but very small scale so you can actually run it on one single node and it's based on docker as well so basically what you do is once you have this installed you just need to do a git push to the server and you basically spin up like Heroku, you spin up an application using build packs which is a lot easier so this is another option you can use to make things a lot easier so what about Kubernetes? if you're just experimenting you ain't going to need it that's what yakni is you are not going to need it so you ain't going to need it so don't use it, please even just experimenting because you don't want to kill yourself with all the manifest configuration so if you do want to go with a fake cloud which is to have docker containers and also have some form or like supporting services that spin up together with your Rails app and I guess a lot of tutorials out there to teach you how to actually bundle or package your Rails application as a docker container so when you do that probably will be a lot easier to do all this using you can use things like docker so yeah so that's all I have for the experimental part so what about productionizing so I think we already use up 20-30 plus minutes so I think I can do the production part as a part 2 so in the future we can do another session and share a bit more about that and that's all I have any questions? okay I didn't know if you have any questions but you are a bit shy to ask you can ask in the GitHub issue or in the Ruby set channel cool okay thank you Michael for the talk okay so