 Hello there, and we are back. So I hope you are enjoying the conference so far. And then, and also the keynote as well, it's amazing keynote. So yeah, now we are having our talk again. And our first speaker for this block will be Bojan. And Bojan is a good friend of mine. Hello. Hello. Where are you calling from for people who don't know? From Berlin. Oh, Berlin. Yeah. Cool stuff. And today I have a very, very special assistant. He's running all around, and his name is Frederick von Edelman. He's a puppy with a very huge name and royalty, so. Cool stuff, cool stuff. And then I hope the puppy doesn't make a debut while you're presenting. I hope he does. Oh, you want to? Okay, we'll see, we'll see. So you tell us about the dependency injection, which is a very, very interesting, interesting topic. So I'll let you take us away. Yeah, okay. Okay. So welcome everybody. And first thing I want to tell you is I love each and every one of you. And I love you so much. I actually went undercover into Java community and I managed to steal some of their secrets. And I'm going to share it today. So for you, I should suffer Java. Now, one second. Tum, tum, tum, tum. So about me. I've been doing Python development for almost a decade. I'm a very, very person, since I love unicorns and baking cakes. I work with AWS, I try designing, also the input here, but I did some Java development and even PHP did not like it. But I tried Python one day and ever since I've been only doing Python. And that's making me super happy. And somehow I also learned that as a CEO of my company. Not sure how that happened, but I'll keep you in the loop. Now, we're going to talk about Java. I know everybody has fears of Java. Myself included because there's so much code. My first experience with Java was, with Java and Python comparison was when I saw how you can easily open the file in Python. Like you just type open. And in Java, there's code and code and code and a bunch of things are happening there that you should not have. But there are some good stuff in Java that we are not using that much in Python. Mostly because you don't need them and you have the choice. They do not have the choice. So I'm going to tell you about things that we could use that gonna help us become better. Even better than all Java community. So I'm going to talk about dependency injection but let's establish some basics first. Let's have you in the current base case. So one class uses the another class. So when Unicorn makes cupcakes, he uses the oven. In this case, we can say that Unicorn class depends on the oven. Fairly simple. You're always going to have some class using another class and depending on it. Now, in some cases, Unicorn can use some fancy oven and that's going to be another dependence. Nothing to scare. Now, we're going to talk about dependency injection. The injection part, basically you can make a Unicorn class. So when you call a constructed Unicorn class goes and sets up its own oven and then it works with it. Fairly simple stuff. We do it all the time. But the injection part is what's interesting. You can create the object of the oven class then just pass it to Unicorn. And Unicorn doesn't have to set up a whole oven in order to bake some cakes. We can even preheat the oven and Unicorn can do that without any problems. So as I mentioned here, very nice thing to do. And it can sell you a bunch of stuff especially with something that you want to have a singleton for example, I don't know why but let's say we want to depends injection to the rescue. Now, in Python, we have many ways of doing this. The simplest way to do it is to just extend the constructor. Say, okay, instead of initializing a cooking machine to be an oven in the constructor, we're just going to pass it and that's it. The whole thingy few lines of code has everything we had to call in Python. Now, here, we introduce some difficulties. Right now, we have to first create an oven and then the Unicorn class. A bit of extra work, but I'll show you very, very quickly why this is going to pay off. Now, here's the stuff that Java people can do. We can create a Unicorn class and then during the run time, we can just assign it an attribute cooking on. Now, word of advice. If you're going to do this approach, never, ever, ever just assign stuff. Always declare the attribute in the initialization like it's here, see, self cooking machine. Because if you don't do it like this, you, when it starts working in the class, you're never going to know what are the attributes of my class and that requires chasing down all the usages in the code and figuring out, okay, here I get this attribute, here I get this other attribute and you do not want to do that. In Java, they try to simulate this to get their insiders, but because we're the cool kids, we can just take instance, slap one nice attribute, object, whatever you want to do with it. We got freedom. Now, in Java world, things get super scary in us. Like, they don't do testing like we do. We can basically just grab, buy test, monkey patch, change stuff without any problem, but then that's a bit difficult because everything's statically typed. You cannot easily overwrite functions in code. So what they do is they take stuff and make it depend on interfaces. And then you have, for example, database interface. One of the classes is for testing that is going to be basically mock class. Another one is actual class that's connecting to the database. In Python, you don't have to do that. You can just intest or write a function that connects database and say, tell it, oh, use this mock object that I created. But there is logic to what they are doing. Since they are telling compiler in advance, what type of dependency it is, they are going to notice errors much sooner than we do. I know from my experience when I'm monkey patching stuff and mocking stuff, usually I need to run tests a couple of times before I make sure that everything is done perfectly and nice. So, type hints are gonna help us to get better in Python without using Java. MyPy is absolutely amazing tool to use. And also beside the MyPy, I'm the PyCharm user. I love it. As soon as you add type hints, you're going to get notifications and warnings about all the stuff that you forgot to use. And since we're working with interfaces in Python, we're also going to notice if we did something wrong. Now, everybody knows two dots and the type of the object. Very simple and it works beautifully. If we try to give unicorn some strings, say this is instead of cooking machine, we give it a string that says this is a cooking machine. MyPy is going to complain, PyCharm is going to complain. So, type hints, super awesome. Now, one reason I wanna mention here is while we're using abstract classes in Python to accomplish this, it's basically just to create an interface. It's not, we're gonna define this class and it's gonna get inherited and stuff like that. No, we're just telling, this is a lightweight abstract class and it has this and this methods. For example, when I'm working with AWS, I might have a adapter class that has upload file, get file URL. That's all there is to it. Initialization and stuff like that. Somebody else is going to handle it. Some other part of the code. But when I'm creating mocks and other stuff, I know how this class is going to be used by the rest of the system. So, abstract classes are super nice in Python. We just don't use them that much. Now, dependency injection is super cool because we can create a configuration file. In that configuration file, you can say, okay, I'm gonna use this class for this and this and this and this. Basically, make a list of classes that are used by your project. And when you are testing, you just give it another configuration file. Django does this quite nicely with his settings file. Just write strings. If you wanna use, for example, Redis for caching, you just add that. If you wanna use something else for caching, for example, main cache, you just add that. And once the application starts up, it looks at the configuration, sees, uh-huh, these are the things I need to do and just passes it to the main class. Everything works perfectly and nicely. And because they have the common interface, which we already declared, there is absolutely no problem. And when we can easily add our own code and functions and objects, because we just have to inherit that absolute class and in my case, PyCharm, it's going to complain, okay, you need to declare these methods. I can declare them, they can do some nonsense, but the code is not going to crash because they know what they need to add. Now, writing mocks is very, very easy when you're working with interfaces because you know exactly what you need to move. Without mocks, as I mentioned, it tends to get more, let me make a change, let me try stuff as it happens. And afterwards, I'm going to figure this out. With dependency injection and interfaces, it's super, super, super easy. It's very hard to mess up, you're in for me and I mess up a lot. So, mocks help you write better tests. Of course, if you can just rewrite some parts of the object, then you don't need the interface. This is just to tell you, okay, there is alternative to just monkey-patching connections and stuff like that. Bigger decoupling. Now, this is the good stuff. Basically, where I use dependency injection, that's on the domain borders. If I have some piece of code communicating with another independent part of the code, I'm just going to put dependency injection in there. Basically an interface, for me, using them as adapters is extremely powerful, especially when working with clouds. For example, as I mentioned, you might use one cloud provider to upload files. You write a function for it. Now, the client might demand the multi-cloud. It happens, they do. And then you have to rewrite the code, okay. So if I pass through to this object, it's going to initialize AWS data storage class. However, if I pass this false, this, then it will initiate Azure class, for storing stuff, which is pretty acceptable. But once you start to keep adding flags and flags, it's getting very, very messy. So because I don't like messy code and because I'm very, very forgetful, I like to keep my code base as simple as possible. So in your code, you can just declare the interface and then based on the configuration, your worker can just read that configuration file and then work. It is also super nice when you are doing some testing. For example, I wanna do some stress testing to see maybe I can use RabbitMQ and see how things work out for my worker and microservices or I can just try AWS SQS or maybe some third solution. I could probably use maybe Redis and stuff like that. And the good thing here is that I just need to implement that interface and change configuration file. The rest of the code is already tested and it will not be broken. So if there's some bugs in there, it's probably in the new code added. So that way I can get nice little fences about all the integrations and craziness that I'm going to do and protect the rest of the code. It saves me a lot of debug. As I mentioned, easier error detection. First of all, as mentioned here, before I end the code because my pie chart, probably VS code, I did not work that much in that. They are very good at dealing with the type hints. So they are gonna complain and you're going to notice right away. This is good because without them, I usually notice it in runtime. And on days when clients is very, very busy and some change needs to be deployed extremely urgently. Right at the moment, for example, for Christmas website needs to have this very second snowflake swelling and it's mission critical. If you don't even want to test the code, you just deploy it because that's snowflakes. Here, your compiler is gonna protect you from yourself. You don't have to deploy to production to find out what went wrong if it's working. Disclaimer, do not generate snowflakes in Python. That's usually JavaScript's job. Now, the downside, there is a more code as you have seen earlier when we use a constructor-based approach. Suddenly, things that were very super, is it basically calling a unicorn constructor, become much, much harder. Since now, okay, before I call the unicorn constructor, I need to call this class and then this class and then this class and then pass them into constructor. Things tend to get pretty heavy. But the benefits on the other hand are all 10 things to mention. However, you can very easily create a wrapper around it. A system is going to read the configuration, see what classes go there and then just initialize the class for you. So it's more code, but you get cool stuff. Abstract classes, best thing ever. Now, I see this with bias because I was coming from Java and it was always super, super difficult to get my hand around Liberty in Python. My first two months, I spent them basically trying to write Java in Python. So once I stopped doing that, I had a mild aversion to the Java way of doing things. So I didn't use abstract classes for a long time, but then when I started using them, I started using them probably way too much. Now, for those of you who are still learning Python and all its charms, abstract classes class that you cannot initialize, it's there just for inheritance. So, and you don't have to declare a bunch of methods. You can just use one method, for example, upload file. And that tells you that any class that inherits that class needs to have an upload file method, easy piece. Now, I'm super efficient. I get to talk now about all the cool stuff I use this. Now, as I mentioned, I use this all the time when I'm working with different cloud providers. And for example, working with China, gonna use Tencent, AliCloud and stuff like that. When you're working with AWS, AWS stuff. And if you're working in France, they have their own cloud provider. And I just let people write the code for them. And that's it. Main logic, the core of your business, the most mission critical stuff is completely isolated from the other stuff. You can even outsource that stuff thanks to your interfaces and they're gonna do that stuff for you. Meanwhile, you're focusing on the core of your business. Which is pretty good because we do not want to write the code we don't have to. So dependency injection must again help us be like this. And that's pretty much everything. Now, question. Yeah, I think we just won a pro. Do you set that like now it's the Q&A time? Yes. Yes, of course. So people don't wish I'm, please ask in the chat in the matrix. And hello there. There isn't a lot of question at the moment. Someone's typing. So that's really a good talk. And, oh no, someone posed a picture of the puppy. So yeah, like, may I ask like what is the, what advice will you give to people who may be like doing the same thing? Like, could you sum up like maybe free advice that you can give people? Yes. First advice interfaces. Interfaces are very good. And they are a bit hard to wrap our hands around because in Python, they don't come naturally. In statically type languages, there's something that you can't work without them. Especially unit testing. I think we underestimate how pie tests and the whole testing suit that this is in Python is making our life easier. When you see all the things that you need to do around them in order to make your code testable, you can't do it without dependency injection. So be very happy because we have pie tests and give those developers some money. Don't eat stuff to them because they did magic for us. That's the first one. Third one is try to know your domains in the business. What's your core domain? What's the third party stuff? Something that's not so important, but you can outsource it. And basically on the borders, that's where you're most likely to encounter dependency injections. That's where I allow you to integrate one thing with another. Now the third advice is breakings. I use this all the time to do some weird stuff because AWS does not crash when I want it to crash, only when I don't. So I basically create a bunch of classes that are just drawing exceptions and doing crazy stuff. And I use dependency injection in testing to see how breaking AWS is going to break my code. And answer is a lot. But thanks to this, I can detect it quite early. It's much nicer when your development, I think the IDE tells you something is broken than when your client calls you in the middle of the night with toast, I think it's broken. Yeah, absolutely. So there is a question actually now that do you use this kind of DI in small projects too? Yes. Basically, since I work a lot with cloud providers and the code for small projects, okay, I need some IPA gateway, write me a Lambda here. I love using dependency injection in there because there are a bunch of stuff that's interquering. Even though it's a small piece of the code, it's very easy to make mistakes. And testing Lambda is not easy. Also testing on this without creating huge field is not easy. So I use this all the time, but it depends on the domain. If you're writing some simple app, if it doesn't use any third party dependency, it does not work with file system. It's not communicate with message queue and stuff like that. You don't need dependency injection. Yeah, cool. That's good. And then there's another question. So we have time. I love question. Yes, please ask more questions, people. Yes. So what about typing packages? Actually, there's two questions. So are there advantages to use this over abstract classes? You can try and do them without any problems. I just prefer using abstract classes. My cup of tea. Yeah. So what would be the difference? Like, why can't I use, like, you know, I can use it. I can still use it for abstract classes, right? Or is it like a, you know, or I should not do it? Or what's your thought? Yeah. My thought is basically, Python gives us a bunch of liberties. So write like this and then write abstract classes. Maybe you can use the mix of them, but for me, I just go full abstract classes and work with that. That's the stuff I understand. However, this thing with typing packages can also work. So it's different approaches, but they are not mutually exclusive. Personal preference. It's the important stuff is to actually just isolate stuff, decouple them. The way you do that, it's up to you. Yeah. So, oh, someone already commented. Abstract class will carry more intention about the usage. Oh, if only from the name of the code I gave to it, then bear stuff from the typing packages. Any thoughts on that? Do you agree or? No? Well. Can you put that here? I agree. Abstract classes do carry more weight. Yeah. Yeah. I think it's really up to you. Then it's really like take your own risk, I would guess. Yeah. I mean, that's what I always tell people. Break things. Try them. Break them. That's how I learned the Linux administration. I deleted the server in production. And then I have to bring it up in 10 minutes. I learned so many things, so. Break them. Try them. See what works for you. Don't be afraid of the breaking stuff. That's the thing as programmers. We're afraid to break things. You can do a machine. Try everything and see what makes you feel happy. Python is one of those languages where you know how code is bad because it's not beautiful. First thing, if code is beautiful, then it's good. If it makes you happy, then it's even better code. That's the standard for Python. Try things, see what makes you happy, go with it. You can go wrong. Yeah. Yeah, that's true. That's true. I think it's a really good advice, actually. Break things and don't be afraid of breaking things. Someone already said that like, yeah, third advice, break things. Which is very true, I guess. So, yeah, I think it's just the end of this section. And then we are ready to welcome the next speaker. So thank you so much, Bo Yan. Yeah.