Choosing the right name for something (variables, functions, templates, etc.) is
extremely important. A function named computeIt
doesn’really communicate
much meaning. If we decide to call it computeTaxForCustomer
, its intent is much
clearer. Naming matters.
Here are some comprehensibility measures with regards to naming:
Don’t be shy of using long and descriptive names. We’re a long way from computer languages that forbid names longer than 8 or 16 characters. Most IDEs support you by providing pop-up lists of names to choose from if you want to refer to a variable, function or template (and even if not we have copy/paste!).
Use descriptive names. This is the absolute winner in making code self-documenting. For instance:
<xsl:variable name="f" as="xs:double" select="($c - 32) * 0.5556"/>
It takes a comment to tell the reader that this converts a temperature in Celsius to Fahrenheit. But if the variable names were chosen more wisely this is no longer necessary:
<xsl:variable name="temperature-in-fahrenheit" as="xs:double" select="($temperature-in-celsius - 32) * 0.5556"/>
Or even better: break out such an expression in a function:
<xsl:function name="mod:celsius-to-fahrenheit" as="xs:double"> <xsl:param name="temperature-in-celsius" as="xs:double"/> <xsl:sequence select="($temperature-in-celsius - 32) * 0.5556"/> </xsl:function>
Break a long and complicated expression into smaller parts using aptly named variables. For instance:
if (($status eq $status-success) or (($amount ge $amount-limit) and (not($special-account-type)))) then …
We can make its intent more clear if we rewrite it to:
let $successful-attempt as xs:boolean := $status eq $status-success let $large-withdrawal-permitted as xs:boolean := ($amount ge $amount-limit) and (not($special-account-type)) return if ($successful-attempt or $large-withdrawal-permitted) then …
Don’t worry: only in very rare circumstances you have to be concerned about the performance impact creating a bunch of additional variables. And probably, the compiler will optimize them away for you.
If something is in a certain unit (meters, inches, kilograms, dollars, zorkian foepies), stick the unit to the name. For an example see the Celsius to Fahrenheit conversion above.
I specifically mention this because of a bug classic: a software mismatch between the metric system and the English measurement system caused the NASA Mars Climate Orbiter to crash in 1998, at the cost of $125 million (https://www.simscale.com/blog/2017/12/nasa-mars-climate-orbiter-metric/).
Magic values, numeric and string constants with special meanings, should be given a name. Declaring such magic values centralizes their definition, which makes them easier to lookup and/or change and prevents bugs caused by mistyping a value. A good name clearly communicates the intent of the value.
Here’s a classic example:
<xsl:for-each select="1 to 12">
Why 12? Ah, this is better:
<xsl:for-each select="1 to $months-per-year">
It’s not that I expect that the number of months in a year is going to change anytime soon. This is about communicating the intent: we’re iterating over months here…
Sometimes there is grumbling (me included) about having to create long and boring lists of magic name declarations, like this:
declare variable $mod:status-error as xs:string := 'error'; declare variable $mod:status-warning as xs:string := 'warning'; …
That looks superfluous, until you make a hard to spot “typo” bug:
if ($status eq 'errror') then …
A convention for building the names is also good. Things like:
Which abbreviations can be used (max
, min
,
ptr
, etc.)
Use something like object-action (file-read
,
status-get
, etc.) or action-object (read-file
,
get-status
, etc.)
Special prefixes for booleans (is-…
, do-…
).
If you declare something, make that declaration as complete as you
possibly can. For a variable or parameter, always
specify it’s type. For a function, always specify the return value’s type.
Even XSLT named templates can declare a return type (in an as
attribute);
specifying this is unusual but definitely not wrong!
Always specifying datatypes has double benefits. It tells you more about the declaration, increasing its comprehensibility. It will also cause a whole bunch of errors to surface sooner if you make mistakes.