Morphological Invariant

Lets say my software is configurable, and one of the configuration options requires that a user provide a list of strings with a specific order. All strings must have a place in this order, no two strings can occupy the same place, and this order must be free of circular references. The easiest way to ensure that this order will be achieved is to ask for an array of strings.

Arrays already require an order to their elements. By asking for an array, I convey all of these requirements to the user without spelling them out. I also gain access to validation for free; whichever language is used to write the configuration file likely already has some built in array syntax, and will report a problem with the array if the user wrote it out wrong. It is actually not possible to provide me with a botched array, so I can avoid validating some aspects of the data, like proper sequencing.

I refer to these requirements as Morphological Invariant's—[[Invariant]]'s that are made impossible by the structure of the data. They are often not even referred to as Invariant's, as we tend to reserve that term for data requirements that prompt a manual check. I prefer to keep these Invariant's in mind, however. There are other concerns which can influence the structure of data, like performance. If I am forced to change my configuration from an array to a map of key-value pairs to satisfy some performance metric, I need to realize that I must now check the order of the values manually. My Morphological Invariant has become a regular Invariant. It already existed, but now it isn't being handled by the nature of an array, and must be handed in my code.

A Morphological Invariant could help you mutate data without creating errors. An array makes inserting values into the existing order easier, but if insertions and deletions never occur, an array might not be necessary. Say you need to track the order in which objects were created. You could just track the order by assigning all new objects a number from an incremental counter. Insertions wouldn't exist, as new objects would never need to receive a number before an existing one. You could also delete objects without updating any other objects numbers. That objects number just wouldn't exist anymore, but the order of remaining objects would be maintained. You could put your objects in an array, but you don't need to for validity. The lack of mutations in the order means that an array isn't necessary to ensure that the order of objects remains correct.