Module Framework Development

Ported from github, originally posted by @toolbox

The Problem

As discussions have ramped up for cTAKES, telemedicine, inpatient, and analytics, it has become clear that for many of these, tools already exist that can do much of what these features require. Including these tools in openEMR presents implementation challenges, the largest of which is that several of them require non-PHP environments. Adding these to the openEMR core would add a great deal of complexity, technical debt, and attack surface. It seems reasonable to assume that integrations of this nature will be common moving forward, as it allows powerful feature additions for a low developer cost.
This issue will seek to answer two questions:

Whether modularizing some of these features, making them installable additions (which may or may not be included in by default) is a good plan

If so, what should this module framework look like?

Proposal (plenty of missing pieces to fill)

Containerization technologies seem to be a good fit for solving this set of problems, and @MatthewVita has already spent some time working on the viability of their use with cTAKES. I think a solution based on docker-compose and git submodules would allow great flexibility while keeping the core clean and secure.

In this proposal, each module would be managed as its own repository under the openemr group. Each would be added as a git submodule within the modules/ folder of OpenEMR core. This has the benefit of requiring no additional package management and allowing explicit inclusion of any and all modules.

The modules themselves would each require a DockerFile, which would automatically be built during installation. Docker-compose would be a good candidate to manage the interconnects between these modules.

The final piece of the puzzle would be how these modules connect to the interface. It seems straightforward to allow passthrough from virtual directories via apache configuration or similar. This allows for pluggable patient interfaces, fhir REST, and websocket servers. The harder problem to solve is integration with existing interfaces. This may not be deemed necessary, but would allow, for example, a module to insert links into specific existing pages. This is not yet a soled issue, but I think discussion surrounding the whole topic would be useful and simplify a couple of different projects that are going on.

Thanks so much to @robert.down or broaching many of these ideas.

1 Like

I think there are two levels of abstraction to consider. First, there are sub-systems within OpenEMR that require the core to run on. These include the CDR, Layout Engine, Forms, Patients, Facilities, Inpatient, Optometry, etc, etc, all the typical day to day usage components. Perhaps someone writes a nifty Billing Module. All of those should be easily installable through some type of click-and-install system (Or perhaps a download and install… the point is, something with a nice UI).

The second level of abstraction is parallel systems that run in tandem with OpenEMR. These are things like cTakes, Analytics, perhaps the Websocket server. I view these systems as needing the data of OpenEMR, and maybe some of the API, but for the most part they are first-class citizens. You can run Analytics without every touching anything but the database; These parallel systems should not live within the OpenEMR base; they should run, well, in parallel.

sub-system modules shouldn’t be Dockerized as they need a fully functioning OpenEMR install to work; the parallel systems however could definitely be made into containers.

I’m already fairly deep into the process of leveraging a core framework for OpenEMR modules to use. It’s been a very slow process but we are moving towards an API that allows for easier development of modules (Think inpatient). I expect the rest of this to be completed in Q4 of this year. My guess is by around Q1 of 2018 we’ll be looking at a significantly different workflow of Request/Responses inside of OpenEMR.

Let me speak briefly on the infrastructure of the sub-system modules. We recently introduced an Event Dispatcher into the system. This will allow us to create hooks for modules to interact with core elements, as well as for modules to create their own hooks for interacting with other modules. The idea is to become completely event-driven. This offers the maximum amount of flexibility, something we need given the complex nature of an EMR.

Additionally, we also recently introduced a service container level. Instead of Module A instantiating a class from Module B, Module A asks the Service Container (Available to all modules) for Module B. The Service Container has the information needed to properly instantiate Module B and give it back to A. This offers a Dependency Injection framework, which allows us to further compartmentalize our code.

Currently I’m getting the configuration layer in place so that when the core class initializes it is able to load up all the configuration files from multiple modules.

So if I wanted to setup a git submodule for say a static node instance that contained all the necessary dependencies for the ccda service, I could move in that direction?

Would that service be a sub-system or parallel system?

either way, the answer is likely use a fresh fit repo, not a sub module.

Hi,

Very nice to see active discussion on these issues. @toolbox, definitely agree with your plan for cTakes and would be a good learning case for the community to watch and build on in the future.

And I need to do some reading up on git submodules , which seems like a nice way to contain modules, albeit my initial impression is that it is always included in the codebase (ie. seems like the same thing as just plopping it in the main repo).

-brady

The notable differences between the use of submodules and just plopping code into the core is twofold:

  • These codebases would have their own repositories, with their changes not polluting core and facilitating independent development and separation of concerns
  • More importantly, they become optional. You can clone the openEMR core and omit the submodules if desired.

And this is exactly what I need. I’m looking into some of @robert.down suggestions for both my nodejs service and some dependencies that are OS specific for institutional billing. Which means I’ll probably come up with an installer class to some degree.
I’m actually kind of excited about the prospects this direction affords new project.

The part I don’t get is the optional part in git submodules. For example, with composer, it makes complete sense to me. In that case, can create a separate repo to develop in and then can decide whether to include the module(within the vendor directory) in main OpenEMR package or whether it is optional (whereby the user would then install it via composer if optional). What I am not grasping is how a end user would install a optional git submodule package?
-brady

Too me the problem with composer is relying on the originating repositories to match what the project may need. Same with npm for nodejs. With sub modules we would control the repository and we could still use composer to install. I think!

also there is grunt for nodejs setups.