Why the Plugin Architecture Gives You CRAZY Flexibility

preview_player
Показать описание

By using a plugin architecture, you can create applications that are incredibly easy to extend. Add new characters or levels to your game after it's been shipped, or allow others to extend the GUI of your application dynamically, without changing a single line in the original code! In this video, I show you how to setup an architecture like this in Python in a few simple steps.

🔖 Chapters:
0:00 Intro
1:13 Explaining the example
3:22 What is the plugin architecture?
4:01 Create a factory to dynamically define game characters
9:49 Register game character classes in the factory
12:17 Dynamically insert extra code via a plugin interface
18:14 Creating a new plugin: Bard
21:56 Adding new functionality to the Bard class
23:23 Final thoughts

#arjancodes #softwaredesign #python
Рекомендации по теме
Комментарии
Автор

You can make it even more flexible by passing the factory to the 'initialize' method in the plugin from the loader. That way you don't have to import the factory. If the factory changes, you don't have to touch the plugin code at all.

enriquerodriguez
Автор

Great video as always!

Some suggestions:

1. To avoid the type ignore (15:40) I would make the PluginInterface a Protocol decorated with runtime_checkable.

2. To avoid using global objects, instead of defining the initialize as taking no arguments, I would pass an "App" object exopsing a public API of what can be changed. This may have been too much for this example but it seems like running something without parameters encourages people to use a lot of global vars and polution of the namespace

3. A more strict and parametrizable way of defining callables (5:25) is using ParamSpec or Protocols with __call__. Maybe instead of using plain dictionaries which are hard to type strictly we could have defined another Protocol called GameCharacterConfig and make GameCharacter have that as an example. That would allow dependency injection of configuration while still keeping everything type safe. When adding a new character, one should not only define a CustomCharacter class but also a CustomCharacterConfig that implements the GameConfig protocol. That way the type of that callable would be Callable[[GameCharacterConfig], GameCharacter]. If more strict typing is needed we could use a TypeVar but I believe it is not needed here.

SkielCast
Автор

This is an application of the Open/Closed Principle of SOLID.
Quoting Uncle Bob:
“Open for extension. : This means that the behavior of the module can be extended.
Closed for modification.: Extending the behavior of a module does not result in changes to the source or binary code of the module.”

thomasburette
Автор

Honestly, amazing videos! I've only seen 3 videos of yours so far and I was not expecting such great, methodical explanations followed by actual clean, useful code and advice. Moreover, spoken by a person with, what looks to be, an arsenal of experience and insight.

In the YouTube space, there is plenty of bad coding channels, which for me as a software developer is so frustrating. THIS channel is definitely one of the best I've stumbled upon.

Keep up the interesting stuff!

theRECONN
Автор

You are the man Arjan! As an intermediate hobbyist developer, your series are all super super helpful. This plugin architecture layout is beautiful.

AlphaWatt
Автор

Awesome! So far you have been choosing examples that fit well to the object oriented programming paradigm, where you got clear objects like Characters or Customers or VideoExporters. Im wondering if you can discuss and come with a counter example where you would rather not use classes but just functions separated to different files / namespaces. Thanks for great work Arjan!

deez_gainz
Автор

For complex / long typing hints, you can make custom typing definitions and use them.

susmitvengurlekar
Автор

9:30 don't mix broad exception catching for "is my factory function name in the dict" with exception catching from running the factory function itself. If the factory throws a KeyError it will get misdiagnosed as a missing character type.

JaxxedNesmith
Автор

Many classes out there but very few of them touch the architecture, and very few of those explain it that great. Great job! Thanks for the euphoria per video!

resatcanerbas
Автор

I really love how you teach an architecture!

aliabedi
Автор

About 15:40 - To force the IDE Type Checker to accept your typing, you can use `from typing import cast`.

ACAndersen
Автор

Hi Arjan, really appreciate the videos. A suggestion for a video topic is the motivation behind choosing good architecture and design patterns. I've been reading the Pragmatic Programmer and they start with a section about how all of this is motivated by a desire to increase the "ease to change" code. I see that you understand this and as you often reach the point where you say, "ah now it's very easy to change x without changing y" but your viewers may not explicitly understand this. Thanks again!

NGrimthrie
Автор

This is neat, indeed! Thank you for providing us with new tools and mental frameworks to expand our software development skills!

alessandroferrari
Автор

Hey! I've got another suggestion: Have you covered the singledispatch function from the functools package in one of your videos before? If not, I'd really recommend it! It really goes hand in hand with the plugin architecture too, since it lets you define generic functions and then the plugins can register their own versions of that function to handle the new classes they create (eg new characters in your example). I personally think it could potentially be a great topic for a future video, in case you're interested!

FabriceNormandin
Автор

This was good on Plugin dynamic loading and creating it. You explain it in very simple language. I was wondering whether you have any similar video on building python framework. Particularly on builds and distribution.

devkhire
Автор

I'm implementing something currently that uses a modified version of this to load a plugin from a file path after checking its content hash to make sure it has been validated/authorized. The idea is to make sure that only signed plugin code is run to avoid nefarious code from hijacking the application. (The plugins are actually contracts that specify correspondent time banking relationships, so there is an additional incentive for the system to be hijacked.)

kkiller
Автор

Seems interesting.
In my code, I recently needed to do the same thing (adding variations without changing the existing code).
I solved it using inheritance and reflection. I searched for all the subclasses of the base class and in every class I have the name as a static variable. Obviously the main issue is that it requires that all subclasses would be in the same module so they are loaded.

I might try to use a factory like you did, which seems much cleaner because every subclasses would be in its own module with its own imports.

sagiziv
Автор

plugin architecture is very useful to develop modular and adaptative systems.
your overview is clarifying and helped to recap it.
thanks for the video!

LucasMartins-opoq
Автор

Cool! I think i've started implementing a project with an architecture that reminds this one ... but without the importlib mechanism. Thanks!

joaopedrorocha
Автор

"Toss a plugin to your code"
👍🏼👍🏼👍🏼

Ziggity
join shbcf.ru