Git Product home page Git Product logo

pluggable's Introduction

What is pluggable

Pluggable is a nano framework (<70 lines of code) implementing a plugin architecture for Clojure(Script) applications.

Pluggable is very general. It supports the creation of plugin architectures, but there is little imposed in how to actually do it. The only requirement is that a plugin is a map with a key ‘id’ and, optionally, a key ‘loader’ pointing to a function that can load other plugins later in the list of plugins. A plugin can optionally refer to dependencies to other plugins (:deps), which then are loaded before the plugin that defines the dependency (but only once). Circular dependencies are automatically detected.

Plugins can define “extensions”: new keys with arbitrary meanings, which are available to plugins loaded afterwards. An application built in this style is simply a collection of plugins, each one having access to the functionality of the plugins defined beforehand and defining new functionality and extension points for the plugins loaded afterwards.

There is a special plugin (root-plugin) which is loaded by default and offers some standard functionality, as the ability to define extension points.

A plugin architecture allow for the initialization code to be completely declarative, rather than imperative. By standardizing how the initialization of the application code is done, it becomes much easier to reuse code between applications.

Plugin based architectures don’t make sense in very small applications. Also, it’s impossible to understand how this library can be used in practice without a good example, which must be realistic. The two previous facts mean that in order to give a meaningful example of how to use the library, a non trivial application should be used. I plan to write a realistic mid-size application using this library as an example of how this approach can be used in real world scenarios.

To get a taste of how a plugin for a part of an application can look like when using this library, we can see an example. This is a plugin definition for a router plugin for SPAs:

(def plugin
  {:id         ::routing
   :beans      {:main-component [vector current-page ::router :ui-page-template]
                ::router        {:constructor [create-router]
                                 :mutators    [[init-router ::routes]]}
   :extensions [{:key     ::home-page
                 :handler ext-handler-home-page
                 :doc     "Defines the home page (route) of the application,
                           replacing any previously defined home page"}
                {:key     ::routes
                 :handler ext-handler-routes
                 :doc     "Adds the given list of routes to the routes of the application"}]
   ::routes    [["/about"
                 {:name ::about-page
                  :view about-page}]]
   ::home-page ui-home-page})

This plugin defines two extension points (::routes and ::home-page) and defines default values for them (a plugin can already use its own extensions). Other plugins can use these extension points to overwrite the home page or add other routes to the application. The code that process this extension points is defined in the ext-handler-home-page and ext-handler-routes functions (code not shown here).

If you wonder what the :beans key means, this is a key defined by another plugin not shown here that defines these extension points to allow plugins to define ‘beans’ to be processed by the Injectable library. That library is not a requirement for Pluggable, but I personally use the two together.

Why

Because it’s a lot of fun to develop applications as a series of plugins.

From a less subjective point of view, we have seen repeatedly than, sooner than later, an application incurres on a “growing tax”, where adding new functionality becomes increasingly costly and working with that codebase is painful.

The standard strategy to deal with this problem is to change projects, jobs or career paths. That works for individuals, but normally not for projects or organisations. These usually follow the strategy to adopt modularity. A plugin architecture is a form of modularity optimised for making application extensivility easy.

I became familiarized with this style of development when launching the project Monodevelop, which started as a port of the #Develop IDE to Linux. The plugin architecture of #Develop made the port easy to do, one module at a time, and the code easier to understand.

All big commercial applications use some kind of plugin architecture. The main reason is to allow third party developers to add functionality to the platform even without access to the source code. But open source software also usually embraces that style, in some cases in a radical style where all the functionality of the application is implemented via plugins (e.g. Eclipse).

My main reason to adopt this style of development is that it’s a lot of fun to develop like this.

How

This technique comes from the object oriented world, even if it can be applied with a functional flavor. The object orientation of the philosophy is not bad in itself:

https://www.youtube.com/watch?v=HSk5fdKbd3o

Pluggable targets the set up of the application state/configuration and stops there. It is therefore purely functional. Nevertheless, the constructed state/configuration can be arbitrarily rich and contain any kind of elements.

This nano framework consists in one function, that takes an initial value for the map and a list of plugins and returns the transformed map. Conceptually, Pluggable is a function ‘f’ which takes a collection and an initial state and applies each of the plugins to transform the state:

(f state plugins) -> state

This means that Pluggable is a simply a reducer.

Its power comes from the fact that every plugin can define its own extension points so other plugins can tap into them and also define their own extension points. But that a story for another day.

pluggable's People

Contributors

pedroabelleira avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.