Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

OpenCDS Guvnor 5.4 and DSL Best Practices

...

Change Log. 3

Introduction. 4

I.       Pot-Holes. 5

A.      Known “pot-holes” in Guvnor 5.4. 5

B.      Work-Arounds for the Pot-Holes. 7

II.      Best Practices for Writing DSLs. 12

A.      Plan the Logical Pieces of a Rule First. 12

B.      Write and Test your DSLs. 13

C.      Build the Rules using DSLs. 17

D.      Export the Package as a KnowledgeModule for OpenCDS. 17

III.         Common Patterns for OpenCDS Rules. 18

A.      Events in General 18

B.      Entities in General 19

C.      Encounters. 20

D.      AdverseEvents. 20

E.      Observations. 21

F.      Problems. 22

G.     Procedures. 23

H.      SubstanceAdministrations – Medications. 24

I.       SubstanceAdministrations – Immunizations. 25

J.       Supplies. 26

IV.         Best Practices for Creating Responses from OpenCDS. 27

A.      Use Templates for Output. 27

B.      One Inference Wrapper per KnowledgeModule. 27

C.      Include Both Coded Response and Text (if appropriate). 27

D.      Include Proposals (if appropriate). 28

E.      How to Create Return Messages from your Rules. 29

V.     Common Patterns for Creating Responses. 30

A.      Write me….. 30

 

 

 

 

 

Introduction

The objective of this document is threefold:

...

1.     No Warning on Close without Save

still an issue in 5.4

All of the “Assets” that are part of a package can be opened for editing.  They will all show a gray “X” on the right-hand side of the tab at the top of the screen when you hover your mouse over the tab.  You need to think of this “X” as meaning “revert” or “abort,” because it will happily throw away all the work you have just done on the asset, with no warning.

2.     Inconsistent Refresh of Elements on Screen

still an issue in 5.4, but improved

There are not as many cases where the screen does not match what has been saved, but there is still at least one case where this happens.  If you rename an asset such as a rule, it will remain on the screen with the former name, even though the new name has actually been saved.

3.     Possible to Add Invalid DSL to a Guided Rule

no longer an issue in 5.4

4.     Possible to Permanently Damage a Guided Rule

no longer an issue in 5.4

5.     Possible to put a Package into Inconsistent State

no longer an issue in 5.4

6.     Possible to Archive Global Area

no longer an issue in 5.4

It is possible to archive the Global Area.  If you did this in 5.3, it destroyed the Global Area, permanently.  In 5.4, it merely archives the contents of the Global Area, and the contents can be retrieved using the Administration tools, if necessary.

7.     Possible to Add an Asset to Multiple Packages

still an issue in 5.4

It is possible to create a new DSL or Enumeration (and possibly other types of assets) and have them become an unintended asset of more packages than the single package you specified when you created it.  This sometimes happens when you have more than one package open as you create the element, and other times it happens for no apparent reason.  For example, if you create a new Enumeration that you intend to be a part of a specific package, but you have the Global Area (and possibly other packages) open when you create the Enumeration, it will be added to all the other packages that are currently open.

8.     Saving the Package and Signing Out

still an issue in 5.4 (was present in 5.3, but not documented)

When you save a package and “Sign Out”, Guvnor will happily throw away all of any unsaved work you have done on any open assets within that package, with no warning. 

9.     Some Assets from Global Area Randomly Appear or Disappear from Active Package

still an issue in 5.4 (was present in 5.3, but not documented)

This may be just a different view on Problem # 7.  Although any DSL you have specifically copied from the Global Area to your current working package will remain an asset in that package, other DSLs from Global will randomly appear or disappear from the working package.  While they are present, they can be used.  If they don’t show at a particular point, they also cannot be added to a rule, and a build of the package will generate errors.

10.    Using Techniques to “refresh” Lists or Views may Refresh Modified Assets Elsewhere

new issue in 5.4

They resolved most of the issues around disparities between what is “saved” and what shows in a list of assets, or even the contents of an asset.  However, this has introduced a new problem that is apparently a side-effect of the “refresh” fixes.  A modified asset that has not been saved may get “refreshed” from disk if you do anything that causes a package list of assets to be refreshed (such as clicking on a button named “refresh list”).

11.     Enumerations Do Not Allow Comments

new issue in 5.4

In Guvnor 5.3 it was possible to imbed comments in Enumeration assets.  In Guvnor 5.4, this will cause the enumerations to fail, except in one specific structure:  You can add a block comment to the last line of the enumeration (e.g., /* comment… */ ).  A comment in any other location will cause the enumeration to fail to be processed at all by Guvnor.  Since OpenCDS has a tool to export enumerations which placed a comment at the beginning of the enumeration list, this will have to be removed, or your enumerations will not show up in DSLs.
 

...

The following approaches can help you avoid the pot-holes, or recover from falling into them.  Of course, it is always better to avoid them in the first place…  J

1.     Develop Habit of Save before Changing to a Different Tab EVERY TIME

Before you click on another tab, use the File menu, and select “Save changes.”  Some things you do in another tab can cause the screen to be refreshed from the last saved value, thereby losing all your updates in any open tabs.

2.     Develop Habit of Save before Close EVERY TIME

Instead of using that “X” to close the asset, use the File menu, and select “Save and Close.”  Developing that habit will avoid a lot of lost work. 

...

NOTE:  We maintain a text copy of all the import statements for vMR version 1.0 in the OpenCDS Maven project, as a text resource in the vMR internal module.  In most cases, you can probably use that list without changes.

3.     Develop Habit of Exporting the Guvnor Repository FREQUENTLY

Because it is possible to get Guvnor packages and rules into inconsistent or “locked” and unopenable states, it is critical to export the package to create backups.  You will avoid a lot of grief if you make it a habit to always do an export frequently and especially before you do any of the following:

  • Rename anything

  • Remove a DSL or an Enumeration (no longer      as big an issue as it was in 5.3, but still a good idea)

  • Import an updated Model

4.     Techniques to Refresh Screen

There are three common techniques to refresh the screen.  These were more useful in 5.3 than they are in 5.4, which is a lot better about refreshing the screen.  Note that all of these techniques may refresh assets that have been changed, thereby losing any changes you have not saved.  Save First!

  • Click the “Refresh List”      button in the Assets view of the package.       This will often make an asset that you just created appear in the      list, or an asset that you just deleted/archived disappear from the list.

  • Click the icons which      change the view of Knowledge Base Packages from nested to listed.  This will close the group of package      listings and reopen them, and tends to refresh all the lists in all      packages.

  • When all else fails, and      you know that you have something saved in the package, but it doesn’t      appear appropriately (or the contents seem to be from the previous      version), you can refresh everything, including the element lists that      show when you are adding things to a Guided Rule, by logging out and      logging back in. 

  • NOTE:  All of the above methods may refresh      assets that are currently open (and possibly have changes!).  Save all your changes first!

5.     Avoid Damaging a Guided Rule

Guvnor 5.4 no longer appears to have a problem with “damaged rules,” but the following suggestions are still probably good ones…

...

TIP:  Put a comment at the end of your DSLs which includes the name of the DSL, and references all of the Enumerations in the DSL.  Then, in the event of a problem, looking at a Source | View Source on a Guided Rule which has this comment imbedded in the source code, will show where you have a bad DSL or a missing Enumeration.  For Example:

Image Added

                                       

                Note that the two comments highlighted above (one at the end of the [when] clause, and the other at the end of the [then] clause) will show in the generated source code, and the macro replacement of the DSL will include the selected drop-down value of the Enumeration named “VMRTemplateConcept.determinationMethodCode”.  If the displayed source simply shows X=={X}, then the enumeration was not selected, or there was no Enumeration list by that name.

TIP:  You can look for Enumerations all in one place by opening the package and clicking on the Edit tab.  Then select the URL for package source, and save the source to an editor such as Notepad++.  You can then use the search facilities in the editor to look for the Enumeration names.  If you followed the previous TIP about putting a comment in the DSL with the name of the DSL, you will know exactly which DSL is referencing the Enumeration.

6.     Recovering from a Single Damaged Rule

This information no longer seems to be pertinent in Guvnor 5.4, but is kept here “just in case.”

...

  • Archive and Restore      the package.  Select the package,      and select File | Archive.  Go to      Administration | Archives and delete the damaged rule.  Restore the entire remaining      package.  Go to the package and      recreate the rule, fixing the bad DSL or Enumeration before you save the new      rule.

  • The Nuclear option:  import a backup of the repository.  Go to Administration : Import – Export,      and import your most recent backup (Guvnor is nice enough to number      them).  NOTE:  this will destroy all the work you have      done since you exported the backup.       You did backup frequently, didn’t you?  J

7.     Recovering from an Inconsistent Package

I haven’t seen this happen in Guvnor 5.4.  But if it does, here are some things to try.

...

In the worst cases, your only choice is the nuclear option.  This will lose all of the work you have done in all packages since you last made a useable backup.  Which option you choose will partly depend on how recently you created a backup.  Having a recent backup is always a good thing…  J

8.     Recovering from Archived Global Area

It was impossible to recover from an archived global area in Guvnor 5.3, but is relatively simple to do in Guvnor 5.4.  Unlike Guvnor 5.3, Guvnor 5.4 archives the assets in the Global Area, but not the Global Area itself.  Simply go to Administration | Archive, and restore the assets.

9.     Recovering from Assets that Appear in Wrong Package

This will still sometimes happen in Guvnor 5.4, and if it does, here is what I found that sometimes would resolve it in Guvnor 5.3:

...

Another technique to fix the problem is to manually update the asset using a text editor or Eclipse.  Access the source code file by connecting to Guvnor’s working version of the repository using webdav (http://localhost:8080/drools-guvnor/org.drools.guvnor.Guvnor/webdav/  -- substitute the hostname and port of your Guvnor installation, and add the package and filename that you need to mess with, e.g.: globalarea/AssertionDsl.dsl ).

10.     Recovering from Unintended Refresh

Unsaved changes are gone.  There is no recovery.

11.     Recovering from Non-Functioning Enumerations

Remove all comments from the Enumeration file.
 

...

Best Practices for Writing DSLs

The following suggestions represent the approach that we have learned to use in writing Guided Rules using DSLs for Guvnor.  Although we write most of our rules in Guvnor, the same general steps probably apply to writing technical rules, and developing rules in Eclipse.  Please add (or let us know about) any further suggestions or comments that you come up with as you work with OpenCDS and Guvnor DSLs.

...

Plan the Logical Pieces of a Rule First

Use a whiteboard, or Notepad, or scratch paper to think about the different logical pieces that you need to complete the rule.  It may be helpful to build a flowchart.  If you plan to use Drools Flow / BPMN2 / Oryx for your rules, then you can use this tool to build the flowchart.   Stay in this process until you can isolate elements that you need in the LHS of a rule, and elements that you need in the RHS of a rule.  You should probably stay in this process until you have a first-cut idea of how many rules you need, and what each rule should do.

1.     Think in Terms of Concepts, rather than Data

In all stages of this process you should be thinking in terms of “concepts” about the data, and not in terms of specific values or codes within the data.  This means that you think about the disease, problem, medication as a concept, such as “diabetes mellitus, asthma, hypertension, ACE inhibitor, NSAID, specified age group, etc.

2.     Develop the Structure to Map Concepts to Data

This process is described in a separate document named “Using OpenCDS Concepts.doc.”  You will need to begin the process of creating concept instances before you start writing DSLs.  These concept instances that you identify will have a name in an Enumeration that you will need to create before you can write your DSLs. 

...

You will not normally need to worry about the actual mapping of data values to the concept instances until you are ready to deploy the rules in OpenCDS and do the final integration testing.

3.     Create Enumerations in Guvnor

You will need to have defined and named “Concept instances” that are in your Enumerations before you start writing DSLs.

...

These enumerations are the “concept instances” against which you will write your DSLs and your rules. 

...

Write and Test your DSLs

Before you start writing your final rules, develop re-useable Domain Specific Language (DSL) elements for as much of them as possible. 

These DSLs should be written in terms of “concepts”, so that they are abstracting actual data and code values.  For example, write your rules against a concept of “asthma”, instead of writing your rules against an ICD9 or SNOMED code that represents asthma.  OpenCDS is designed to support the flexible mapping of codes at run-time to the logical concepts that you use to write the rules.

1.     Start a DSL as a SandBox rule

A single named DSL can have zero to many [when] clauses (aka the left-hand-side or LHS of a rule), and zero to many [then] clauses (aka the right-hand-side or RHS of a rule).  The purpose of the multiple elements is that each individual element is optional, and can be individually chosen or rejected when you build the rules.  Until you are adept at creating DSLs, it is probably a good idea to keep your DSL simple, and avoid multiple elements.

...

Repeat this process in the sandbox rule until it both validates, and includes the logical element of a rule that you want to turn into a DSL.  Here is an example of a sandbox rule with the logic that you might want to turn into a DSL:

 Image Added

Go to the Source | View Source tab, and view the text of the generated sandbox rule.  This text is going to become your DSL:

Image Added

                

Create a new DSL, and copy and paste the text from the [when] clause of the generated sandbox rule into the new DSL.  Since there are two lines in the [when] clause, and Drools implies an “and” connection between separate lines in the LHS of a rule, we will need to insert an “and” between the two lines, and put them all on one line.  We will also parenthesize the entire thing.

Our first effort might look like this (and it is all on one logical line):

($encTypeConcept : EncounterTypeConcept( openCdsConceptCode == "C44" ) and $encEvent : EncounterEvent( id == $encTypeConcept.conceptTargetId, subjectIsFocalPerson == true, encounterEventTime.high < evalTime ))

If we then clean up the variable names (the elements beginning with “$”) to make them globally unique in a long and complex rule with many DSLs, this text might look like this (and it is still all on one line):

($PatientEncounterEventDsl_encounterConcept_OutpatientEncounter : EncounterTypeConcept(openCdsConceptCode == "C44") and EncounterEvent(id == $PatientEncounterEventDsl_encounterConcept_OutpatientEncounter.conceptTargetId, subjectIsFocalPerson == true, encounterEventTime.getHigh()< $evalTime ))

This is now a working DSL, but it only knows how to do the one thing you hard-coded into it.  You are going to do several more steps to turn this text into a very useful and re-useable DSL:

  1.  Write Write a clear plain-language statement of      what the DSL is supposed to describe, follow it by an equal-sign (“=”) and      place it in front of the text you copied from the sandbox rule.  This might be something like
    Patient has previously had an outpatient encounter =

 followed           followed by the text of the rule that you wrote to implement this, as shown above. 

...

 Abstract out the concept      instances into enumerations that you identify by {X} – any variable name      surrounded by curly braces, and with some additional information that will      be demonstrated in examples below.

 

Also abstract out any quantities you might want to change into variables that you identify by {n} – any variable name surrounded by curly braces.

...

Patient has previously had a {X:ENUM:EncounterTypeConcept.openCdsConceptCode} =

  1. Replace the specific      concept on the right-hand side of the = with the variable name[s] in curly      braces, and you get this for the entire DSL:

Patient has previously had a {X:ENUM:EncounterTypeConcept.openCdsConceptCode} = ($PatientEncounterEventDsl_encounterConcept_{X} : EncounterTypeConcept(openCdsConceptCode == "{X}") and EncounterEvent(id == $PatientEncounterEventDsl_encounterConcept_{X}.conceptTargetId, subjectIsFocalPerson == true, encounterEventTime.getHigh()< $evalTime ))

  1. Finally clean it up by      adding a list name at the beginning, and a comment at the end. 

The list name is the first thing you will see in the Guvnor list of elements that you can add to a Guided Rule, and helps you choose the right rule.  It does not become a part of the final source code for the rule. 

...

If we look at the Source | view Source, the source will look like this (and you can see the comment at the end of the DSL has been populated with the selected concept instance ID for “Outpatient encounter” that we selected in the drop-down):

 

 

2.     Study the Sample Rules Provided

They include examples of more complicated rules that combine multiple concepts and settable values in useful and re-useable ways.

 

3.     Test your Sandbox Rule with just One DSL in it

Make sure your sandbox rule validates, and save it.

...

Test each DSL you create in this same way before you start putting them in a rule you want to keep.

4.     Use Meaningful Names for Variables

You may have noticed that the example rule we built above has variable names that can be quite long.  The variable “$PatientEncounterEventDsl_encounterConcept_{X}”  would work in a simple rule if it was only “$x1”. 

...

Date

Author

Notes

12-14-2011

David   Shields

Initial   document without best practices section

12-15-2011

David   Shields

Finished   first draft of best practices section

12-20-2011

Ken   Kawamoto

Minor   edits

12-20-2011

David   Shields

Added   screen shots that were omitted earlier

1-12-2012

David   Shields

Added   one new “pot-hole” and work-around / fix

6-28-2012

David   Shields

Edited   for Drools Guvnor v5.4

7-5-2012

David   Shields

Added   more “pot-holes”, worked on DSL Patterns