Table of Contents
Uniformity Principle (UP)
Variants and Alternative Names
Solve similar problems in the same way.
Software design comprises many similar tasks. There are plenty of design decisions that are similar to ones taken before. UP tells that a design is good when similar design problems are solved the same way. UP can be applied to a large variety of problems: naming identifiers, ordering parameters, deciding upon framework or library usage, etc.
Striving for consistency and always using the same solutions also means that it can be a good idea to apply a “bad” or less-well suited solution for the sake of consistency. If for example a bad naming scheme is used throughout the whole project, it is advisable not to break it as an inconsistency in the naming scheme would be worse than applying the bad naming scheme everywhere.
For documentation UP means to have a consistent documentation structure such that a certain piece of information can be found easily. Furthermore uniformity in naming schemes is especially important for documentation. When referring to the same concept the same word has to be used. Synonyms are a source of misunderstanding.
Following UP reduces the number of different solutions. There are fewer concepts to learn, fewer problems to solve and fewer kinds of defects that can occur. So the developers, whether the original ones or the maintainers, have an easier task in creating, understanding, and maintaining the software. By reducing variety in the design, the software becomes simpler (see KISS).
Documentation which follows a fixed structure helps you find a certain piece of information faster because as soon as you have understood the structure you know where to look.
- Use the same naming scheme everywhere
- Use the same techniques, mechanisms, libraries, and frameworks everywhere
- In similar methods use the same order of parameters
UP demands solving similar problems in the same way and not just in a similar way. This is crucial as subtle differences can be dangerous. These small differences are created easily. Sometimes it is impossible to do two things exactly the same way. And also over time two modules may slowly diverge. So it is sometimes better to have two modules work completely differently than to allow for these subtle differences as they easily lead to misconceptions and mistakes (see ML).
See also section contrary principles.
This principle is newly proposed here. Nevertheless the idea is not new and should be pretty intuitive to every developer.
Relations to Other Principles
- Murphy's Law (ML): A typical source of mistakes are differences. If similar things work similarly, they are more understandable. But if there are subtle differences in how things work, it is likely that someone will make the mistake to mix this up.
Note that UP can be contrary to virtually every other principle as it demands neglecting other principles in favor of uniformity.
- Keep It Simple Stupid (KISS): Although UP normally reduces complexity, sometimes UP demands more complex solutions because they are already applied elsewhere and for the sake of uniformity shall also be applied in simpler contexts where they would not be necessary.
- More Is More Complex (MIMC): Documenting something because of UP may result in unnecessary documentation. There may be more concise ways of documentation.
- Model Principle (MP): UP may demand adhering to a certain naming scheme, which may not be best with respect to MP. See example 1: naming schemes.
- Principle of Least Surprise (PLS): When applying UP, PLS should also be considered for naming modules. See example 1: naming schemes.
Example 1: Naming Schemes
A typical example of the application of UP is the naming of method identifiers for common container classes like stacks or queues. This also shows that there are several ways to apply this principle.
Stacks typically have the methods
peek (sometimes also called
push puts an item onto the stack,
pop removes the top most item and
peek retrieves the value of the top most item without removing it from the stack. This is how the common stack model describes this data structure (see MP). Applying UP to this naming decision means that the methods should be named precisely as they are named everywhere else also. So a developer knowing the model or other implementations of the model will immediately know how to use this module as well. In this case MP and UP demand the same thing. PLS is satisfied here as well as a developer knowing stacks will expect exactly that.
Queues on the other hand typically have the methods
first or the like). MP would demand naming the operations of a
Queue module exactly that way. But there are several ways Up can be applied here. The one way is to apply the principle just like above. Resulting in methods
dequeue. This is how it is done in .NET1). The other way is to consider the method identifiers of the
Stack module. A possible application of UP could be to demand naming the queue methods just like the stack methods, meaning also
peek. This is the naming scheme which was chosen in the Delphi RTL2). Here MP and UP are contrary. A further downside of this approach is that
push methods might be surprising for a queue class. So PLS would oppose this solution.
A third possibility is to find a common abstraction and to apply a very general naming scheme to all descendant classes (stack classes, queue classes and others). This is the way it is done in Eiffel3). Here there the method names are
item regardless of the concrete data structure. This is contrary to MP but creates a uniform naming scheme throughout the API. So there is less uniformity across APIs but stronger uniformity within the API. MP and UP are here contrary too. For PLS this means that a developer who is used to this philosophy is never surprised by having these methods. But developers new to it might be nevertheless.
Example 2: This Wiki
This wiki has a certain structure which is uniform across all principles. Each principle description has the same sections with the same kind of information. This makes looking up principles much easier because one can directly jump to those sections containing the needed information. To mitigate the problem of unnecessary documentation (i.e. MIMC violations) sections without additional information are left blank instead of describing something obvious.
Discuss this wiki article and the principle on the corresponding talk page.