Scripting Best Practices

Functions are the key to any program! Within the Translator, they become even more important because of how Iguana’s annotation blocks track their usage.

General Rules

For purposes of readability, every significant code block should be set up as a function. This technique has several advantages:

  • It makes the main function easier to read
  • It makes tracking logic paths within the annotation blocks much easier
  • It is easier to maintain
  • It is easier to modify
  • It imakes production message management much easier

Naming Conventions

When choosing function names, follow the same rules as when naming variables:

  • Names should express what the function will do (intuitive)
  • Names should maximize auto-completion by using meaningful prefixes
  • Function names should be longer than variable names

Passing Parameters

Stringing a long number of parameters into a function call will restrict the amount of space available to the annotation block. This negatively impacts readability. To address this, when passing more than three or four parameters, it may be useful to use a table construct: simply place the values into a Lua table and pass the table. This also make future maintenance easier!

Creating Custom Help

Anytime you create user-facing functions, you should define custom help functions for them. For an example of how this works, check out the sample provided in our Module section.

Returning Values

Functions fall into two categories: calculation or processing:

  • Calculation functions are functions that perform logical calculations on input parameters, then return a/some value(s) that it computes. Examples are sine(), stripNulls(), or removeCR(). Normally, calculating functions return only a single or small number of values. These are pretty well understood and are fairly good at self-documenting, as long as the naming is intuitive and useful.
  • Processing functions (or workflow functions) manage programmatically built tasks or workflows. Examples are patient.addReport or emr.createBilling. These tend to be more complex. They also tend to fail! When using these functions, we strongly suggest that you perform the following:
    • Report the activity and status as a string in the return statement rather than a simple ‘OK’ (i.e. return blah, blah, blah, ‘Billing invoice submitted’)
    • Report the activity and status as a iguana.logdebug entry that can be turned on if there are problems

Logic-Enabled Functions

Scripts often include loops or conditional statements. In both cases, the repeating or conditional logic should surround the function and not the other way around:

for k,v in impairs(patientTable) do 
 validateValue(v)
end

function validateValue(x)
if x == nil then error ‘Null value found’ end
end -- function

The above example is obviously more readable and more expandable than the following:

validateValue(patientTable)

function validateValue(t) 

for k,v in impairs(t) do 

if v == nil then error ‘Null value found’ end

end -- for
end-- function

Performance vs. Readability

In long loops, we recommend that you assign a function to a local variable (as the local function will run about 30% faster):

-- Global function
for i= 1, 1000000 do
local x = math.sin(i)
end

-- Local Function use
local sin = math.sin
for i= 1, 1000000 do
local x = sin(i)
end

In this case, we sacrifice a bit of readability in favour of performance. This should be a case-by-case decision.

Tagged: