Managing App Definitions and Extensions in OpenMRS

I was recently making few changes(adding new fields) in OpenMRS Register Patient form found in registrationapp module. I was literally annoyed the route I had to take to get the requirements implemented:

  1. In order to add UI elements I had make some changes in registrationapp module (adding new fields)
  2. Configure refapp_registrationapp_app.json located in referenceapplication module to work with the sections/fields added in the above step
  3. Compile and deploy both the modules

The above process proves to be hectic and leads to difficulty in code management. I’ve witnessed a similar problem while making amendments to other parts of application as well:

  1. Capture Vitals function implemented in coreapps module whereas it app configurations implemented in referenceapplication module
  2. Relationships function implemented in coreapps module whereas it app configurations implemented in referenceapplication module

I’ve noticed a similar pattern for htmlforms as well:

  1. Various forms like Vitals, Visit Note, etc. placed in referenceapplication module whereas their back-end implemented in modules like coreapps

Is there a specific reason behind following the above approach??

Will it not be a good idea to keep configurations and implementations pertaining to certain module under that modules itself. (for example: define registrationapp.registerPatient.json under apps package in registrationapp module itself and not in referenceapplication module)

The idea is exactly what you are stumbling upon: the Reference Application module is a configuration module that consumes what all the other modules have to provide.

I think if you were to create a new module to add on top of the Reference Application distro, you would have to not only make it bring its actual functionality (widgets, apps, API… etc) but also make sure that it is auto-configured with sensible defaults. In order to make it useable right out of the box basically. But the point is that implementers leverage the Reference Application module (or any other module that replaces or overrides it) to override other modules’ default configurations.

Now if a module is too high in the chain of dependencies, and that might be the case of the Registration App module for instance, it may not come auto-configured out of the box because it was assumed that a configuration module would anyway be added downstream (= the Reference Application module). What you see happening between the Registration App and Core Apps modules and the Reference Application module is exactly that.

I agree that things are not always consistent and lead to confusion. I would have also preferred to have the Registration App module to ship with a sample/default registration app configured ; and then the Ref App module overriding it (or not) for the sake of the Reference Application distro.

I agree with you @mksd. The confusion arises because only a few apps from Reference Application and Bundled modules are defined in referenceapplication module JSON app definitions.

@ssmusoke as the reference application development lead, i hope you are following this. :smile:

@dkayiwa I am following it

I have opened to cater for this as an improvement

Note that there is a difference between extension points and the actual extensions to them, extensions must be implemented in the module that has the functionality/page that needs to be extended while the extensions live in another module. It would be pointless If they both lived in the same module since one could as well just copy the extension’s code fragment right into the host gsp of the extension point.

The other thing is that semantics dictate where something belongs, reference application is more like a core module, where as coreapps can be optional, features like capture vitals or relationships are good to have but not must haves to run the reference application since there can be alternatives to them hence the reason why they are in the coreapps module. Basically, the coreapps module was meant to provide nice to have features out of the box but not must haves.

Although I find capture vitals a little strange, both the extension point and the pages/forms are in the ref app module, but the extension is in coreapps. I think we need to get rid of the extension from coreapps module and just add the button directly to the home.gsp, the only argument may be to keep it as an extension even after moving it to ref app module is so that one can still disable if necessary.

Philosophically, the approach I took in the beginning was that (a) underlying functionality is defined in underlying modules, and (b) it’s attached to the UI via apps in the referenceapplication module (or else you can fork referenceapplication and do your own custom config).

We did not completely follow this philosophy, because were also thinking of the OpenMRS 1.x way where you add a module, and its functionality just appears. Therefore we did also define some apps/extensions in modules like coreapps (and this leads to @themoonraker13’s confusion).

So, the “correct” way to be consistent with our original philosophy would be to remove all definitions of apps and extensions from registrationapp, coreapps, etc, and put them in the referenceapplication module.

Later, Bahmni appeared and took a different approach, which is that instead of a “configuration module” (e.g. referenceapplication or a fork) you would have configuration files.

The Bahmni approach is actually better for our typical OpenMRS use case, because “modify the default configuration json files” is much more approachable for a typical implementer than “fork a module and edit its activator”. And you can still version the configuration files in source control.

Actually shifting to this approach would require some analysis. Now might be a good time to consider it, as we’re working on making the patient summary more configurable.

I agree @darius. As referenceapplication is a flavor of OpenMRS and the referenceapplication module controls the other modules(new UI and not legacy UI), we should bring all the configurations at one place. i.e. the reference application module.

Note: At least we can migrate app definitions of bundled modules that come up with reference application release