Overview of Extension Approach

The post belongs to NectarCommerce and Extension Framework Awareness Series

  1. NectarCommerce Vision
  2. Extension Framework Game Plan
  3. Introduction to Metaprogramming
  4. Ecto Model Schema Extension
  5. Ecto Model Support Functions Extension
  6. Phoenix Router Extension
  7. Phoenix View Extension
  8. Running Multiple Elixir Apps Together
  9. Extension Approach Explained
  10. Learning from failures: First Experiment at NectarCommerce Extension Approach
  11. Developing NectarCommerce Extensions
  12. Building an exrm release including NectarCommerce

What will be NectarCommerce

Off-the-shelf Opensource E-commerce application for building an online store.

Provides an Extension Framework to support features not included in core as extensions.

Strives for unobtrusive parallel development of NectarCommerce and Extensions

NectarCommerce is committed to providing a ready-to-use e-commerce solution but the definition of 100% is different under different business domains. It aims to solve common use-cases as part of the project and relying on extension framework to tap the rest.

NectarCommerce Extension Approach

This post aims at documenting how the approach we took to make NectarCommerce extensible is structured, the order of dependencies amongst the various nuts and bolts of NectarCommerce and its extensions as implemented.

NectarCommerce can be divided in two components, both of which reside in the same umbrella application.

  1. Nectar: The phoenix project, which acts as the backbone of your E-Commerce application.
  2. Extension Manager: A plugin manager/DSL provider for Nectar. It also owns the compile time step for Nectar. We intend to make the DSL/Compiler as a separate package and make Extension Manager solely responsible for downloading and installing extensions.

Application Overview

Nectar

Nectar is a run of the mill phoenix application, with models, controllers and some conveniences built into it which makes it amenable to extension. It has no dependencies on other application in the umbrella besides worldly which once done should also be a separate package.

  1. Nectar.Extender, if any module is using this during compile time, Nectar.Extender searches for whether the module which can act as an extension to the using module has been compiled and loads the extension into it. There is a basic naming convention being followed for doing this: if Nectar.Product uses Nectar.Extender then it will search for module ExtensionsManager.ExtendProduct as the module to use for extension. This is a proof of concept implementation, which we can flesh out later to support fully name-spaced extension modules. source.

    Note: This currently limits the point of extension per module to a single module. It is by design to keep things in one place.

  2. Nectar.RouteExtender, Similar to Nectar.Extender except it is specialized for extending routes.

So any extension that needs to modify Nectar, needs to utilize the DSL provided by extension manager, we will go through this in detail when we expand on how to build an extension.

Extension Manager

This is a regular mix application that will be used to fetch the extensions and provides a thin DSL(for more details on this see our posts on Model Extension, View Extension and Router Extension) which can be used to express how changes are to made to Nectar. Also any extension that we need to install will be added here as a dependency and properly hooked into the correct modules (Please see the example implementation for one way of doing this). This module provides 3 components for building and compiling Nectar extensions.

  1. DSL : A simple DSL for declaring components that need to be injected into models/router. See our previous posts for how the DSL looks and behaves.

  2. Extension Compiler: It is a basic compile time step that marks files which are using Nectar.Extender(i.e. use Nectar.Extender) for recompilation so that they pick up any changes made to the extensions. It is currently based on how phoenix compiler works.

  3. Install: Extensions can document how they are to be installed by declaring the code using DSL inside method calls and describing how and which modules to call these methods in. These instructions are then followed to compile the injection payload. If this seems cryptic/vague, please refer to the example implementation of favorite products extensions on how the install file is structured.

Dependencies and Code loading

Extensions Manager & Nectar : Extension Manager does not depend upon Nectar directly(it may be a transitive dependency via the extensions) neither does Nectar depend upon Extension Manager. Nectar searches for modules in the umbrella via Code.ensure_loaded to find if extensions exist. While it’s not ideal and as explicit as we want it to be, it is a pragmatic solution for what it allows us to achieve which is basically a form of mutual dependency.

Extensions & Nectar: Extensions should depend upon nectar. Again this may seem counterintuitive since Nectar will be enhanced via extensions, but ultimately we will need the Nectar dependency for running tests, pattern matching on Nectar structs and models and for building exrm releases(more on this later). After we are done we can always recompile nectar to use the extensions.

This concludes our high level description of how the different parts of NectarCommerce interact with each other. Lets continue and see how we can utilize the above infrastructure for building extensions in our next post.

Our aim with these posts is to start a dialog with the Elixir community on validity and technical soundness of our approach. We would really appreciate your feedback and reviews, and any ideas/suggestions/pull requests for improvements to our current implementation or entirely different and better way to do things to achieve the goals we have set out for NectarCommerce.

Enjoy the Elixir potion !!