Conditions are the requirements to use a program, including functions and objects, as specified by the interface and documentation, collectively known as the contract. A common condition is for the arguments to be provided as a particular data structure, like an array of strings, but they can as complex as needed to satisfy the purposes of the program, especially if the program is stateful. An object might have a condition that it be configured before it is initialized, and initialized before it can be used. Conditions are imposed by the program on the programs users, called the client, who may be other programs or people.
If the conditions are not met, the program must handle the failure in some way. It is generally considered the responsibility of the user of the program to meet the conditions, so it is often best to handle the failure loadly, with a thrown or returned error. In a since, the errors that a program returns as a result of some failure on the programs user creates its own set of conditions, irrespective of the interface or documentation.
Clients may be other program, as in the case of an API, a person, as in the case of a User Interface, or both, as in the case of a Command Line Interface. An API captures its conditions in its documentation, interface, and errors. A user interface captures its conditions in the on screen instructions and input error messages. A command line interface captures its conditions in its help text, and error messages of the program. In all cases there are error messages to codify the conditions into the program itself—a necessary fallback for clients who misunderstood or outright ignored the documentation.
Strength of Conditions
Conditions may be restrictive or permissive, with advantages and disadvantages to both. Restrictive conditions require the client to operate in a specific and limited way. Conversely, premissive conditions allow the client to operate in a broad and unbounded way. Restrictive conditions make a program more reliable and flexible, wheras permissive conditions make a program more robust and reusable, as we will discuss.
Restrictive conditions make a program more reliable by limiting the number of unique situations that the developer must consider and test. A restrictive program that accounts for half the inputs of a more permissive program but with the same number of test cases will have twice as many of its use cases tested by proportion. Though this metric is nowhere near prescriptive it is illustrative of the effects of restrictive conditions.
Restrictive conditions also make a program more flexible, as they reduce the number of novel situations that the developer must consider before making a change. Hyrum’s law states that with enough clients all use-cases of your program will be utilized eventually. These clients must then either be broken, versioned, or accomidated, all of which are expencive for someone, be it the client or the developer. Consider a CLI that attempts to parse a date-time value irrespective of its format, allowing for endless use-cases. If the developer found that they needed to allow for increased percision of the time from milliseconds to nanoseconds, every format would need to be considered so as not to silently break an existing client implementation. If the program only allowed for a specific date format, however, it would be relatively easy to introduce a new format, parse the inputs to determine which format was used, and account for both the old and the new use-case.
Permissive conditions make a program more robust by expanding the number of ways in which a client may communicate information to the program. A robust program is capable of handling variable situations and environments, and so a permissive contract will create a more robust program by improving its ability to handle diverse inputs. A CLI program that is able to handle many date formats is less likely to break because of a mismatch between the expectation of the client and the reality of the programs contract. Postel, a principal architects of the internet, said that programs should be ”liberal in what they accept, and conservative in what they send.” This principle is even found in the UNIX Philosophy with the Rule of Repair, which states that programs should repair invalid inputs when possible.
Permissive conditions also make a program more reusable, for many of the same reasons that the program is more robust. A CLI program that is able to handle many date formats is compatible with more CLI programs that output dates, as it is more likely that the output program and will be included in the list of allowed inputs, enabling the two programs to work together without an intermediary to reformat the dates. In a sense, permissive conditions have the same effect of flexibility as that of restrictive conditions, but where that flexibility is targeted at the client rather than the program. A more restrictive contract allows the program to change with less consideration, whereas a more permissive contract allows the client to change with fewer issues.
User Interfaces should almost always be as permissive as possible, as advised by Robust Inputs, since a human client will be able to react to interface changes at every interaction, elliminating the breaking effect of major changes. A human requires no proactive manual labor to update their understanding of an API; they see the new interface and react accordingly. A user interface developer then does not need to worry about the issues with flexibility when designing a permissive interface.