How can we integrate an plugin architecture in to a web application?

Problem: I get different customer requirements for a business application that has many common modules. So I decided to develop an minimal application that can take functionalities as plugins. Whenever I get a new requirement I will be developing new plugin instead of editing the entire application. How can I implement this plugin architecture?

Programming language : Python

Start a personal dev blog on your domain for free and grow your readership.

3.4K+ developers have started their personal blogs on Hashnode in the last one month.

Write in Markdown 路 Publish articles on custom domain 路 Gain readership on day zero 路 Automatic GitHub backup and more

Jake Foraker's photo

Lucky for you, its already built into Python... pip is a dream to work with...

packaging.python.org/guides/creating-and-di..

Also, for my own curiosity I spent minimal time googling and found this: github.com/mitsuhiko/pluginbase

lkubuntu.wordpress.com/2012/10/02/writing-a..

This is not an uncommon problem, as Django and Flask were developed with this exact situation in mind.

jalpesh vadgama's photo

I would suggest to create reusable component which can be used in any application. For example login component which can be work with any project. Same way for server side code create small micro services which can be reused within another application also.

Vikrant Singh Chauhan's photo

You can build one simply by utilizing importlib.

  1. Get all .py files in your plugins directory ie. with os.walk.
  2. Import them with import_module().
Mev-Rael's photo

You never edit entire application when you add a new functionality, this is just a nonsense.

Use A) 3-tier architecture, B) composition over inheritance and C) Dependency Injection

A) Model-View-Controller (3-tier architecture)

You just write an application same way using 3-tier architecture pattern. Most common is MVC. When you have a new functionality you just write a small new controller, add view, model and that's it. You can group controllers into groups and create parent abstract controllers sometimes like AdminController.

B) Composition over inheritance

Composition over inheritance ("Lego principle") means instead of having a huge hierarchy of classes and using extend so often you create small independent:

  1. Abstract components for bigger components/controllers - mixins in Python, traits in PHP, etc. You create a mixin with a common functionality you would like to easily activate (as a switch on/off) in controllers, models, etc. For example, you might have a mixin which will add file upload functionality to a Model and you will have few new methods and might listen for main events when model is created/updated and process file uploading automatically and all what you will need to do next time you have a such model - is just to add one line of code in the Model.
  2. Components (helpers/libraries/services) you need to use across many controllers. For example, you might need to use Payment API across many places in your architecture. You just create a one new service for all payments and use this class/component from controllers. Or you might have a basic helper function to send notifications to slack with one line of code from any part of your app. Whatever.

C) Dependency Injection

Dependency Injection means components of your architecture are not tightly coupled (directly linked, glued) to each other. From previous example with Payment APIs, you have a service/class for payments you call from controllers with one line of code, while the main implementation and 3rd party API usage is done in this Payment class itself and when in the future you would like to switch to another Payment API, you don't need to rewrite many controllers (you also never change code you do not own, you do not change old Payment class because you might break something). All what you you need is to write/extend your base abstract Payment service, change few lines, implement/import another API and "inject" (replace) your new class into Container. From controllers you get your service from this Container and not import Payment class directly. Finally you might have a helper function or use a Facade pattern which will give you the right instance of the right class in your controllers automatically. It could be a simple function as app('payment') which will return a new instance of current (active) Payment class from your container/config.

Summary

Controllers in MVC always should be very basic and contain only minimum amount of new code needed for specific business case. Common parts which are not directly connected to this specific use case should come from mixins and helpers/services/smaller components.

Do not change the code you do not own. Instead create an own implementation and inject (replace) it with the original.

Never waste time on thinking about a perfect architecture or optimization at the beginning. Just write a code, keep writing everything in one file, keep writing bad code in one controller. When in the future you will see that you started using copy-paste, then it is a signal for you that it is time to separate the code and extract it into a mixin or a helper/service.

Jan Vladimir Mostert's photo

Just build modules, then when you need those features, just include those modules.