These days, software development usually begins with a specification. This gathers together the requirements that the software must meet later on. Anyone who tries to acquire an in-depth understanding of what a specification should look like and who has also been involved in a number of projects will quickly become confused. Ultimately, anything from user stories on sticky notes to pseudo-code written in specially created formal languages can be considered a specification.
If one turns to the IREB (the International Requirements Engineering Board) with this question, the only answer seems to be that what is useful for a specification, what it covers, and how it should be formulated depends on the context. This is probably the case, and we cannot expect to find the same degree of formality and uniformity in specifications that we are already familiar with in program code.
Nevertheless, some points can be made about specifications and their relationship to finished code that are context-independent. This blog post elaborates on some of these points with a particular focus on the implications for the roles of specifiers (i.e., requirements engineers, business analysts, etc.) and developers, as well as their relationship to one other.
Specifications and the solution space
How are specification and implementation related? Simply put, the implementation provides functionality that meets the requirements in the specification. However, this does not make the relationship between specification and implementation clear. The requirements of one and the same specification can be met by different implementations. For this reason, there are several possible implementations for a specification. Below we will call the set of all possible implementations for a specification the solution space for a specification.
Solution spaces for different specifications can be of different sizes (i.e., include different numbers of possible implementations). Let's consider an example. Suppose our specification requires that a set of packets be sorted in ascending order according to each packet's index number. The solution space for this specification therefore includes all sorting algorithms, e.g. well-known implementations such as Bubble Sort, Merge Sort, Insertion Sort, and Heap Sort. If we extend our specification to include the requirement that very large numbers of packets should also be sorted without a quadratic increase in the duration of sorting, the solution space decreases.
In the worst case (that is, simply put, when the initial set of packets is as unsorted as possible), the duration of the sorting process increases quadratically to the set of packets to be sorted in the case of the Bubble Sort and Insertion Sort implementations. If this is supported by another requirement, such as when it is excluded by a specification of the allowed duration, the solution space is reduced and does not include the two implementations Bubble Sort and Insertion Sort.
Thus, the specification as a set of requirements decides on the implementations that are included in the solution space and thus also determines its size. Below we will discuss some of the disadvantages of solution spaces that are either too small or too large.
Disadvantages of having too large a solution space
If details are omitted from the specification or if the requirements are rather vague, the solution space is often too large. This scenario bears the risk that the specification does not contain all of the customer's actual requirements. As a result, the solution space will also contain implementations that are not suitable for the desired software.
Furthermore, this situation poses certain risks for the role of the specifier. First, there is a risk that the specifier will be demoted to RE monkey. In this role, the specifier is not involved in any conceptual work, but primarily logs stakeholder statements. There is no comparison with the previous infrastructure (previous implementations, peripheral systems, business processes, etc.); instead, requirements are adopted uncritically and without any reflection.
Secondly, this causes the specifier to be far removed from the actual implementation, and thus removed from the software. The non-specific specification is submitted and the developer is entrusted to select a suitable implementation from the immense solution space. Ultimately, however, the specifier has no understanding of how the identified requirements were implemented in the software. This may technically work, but at the very least it is degrading to the role of the specifier.
The first problem with a solution space that is too small is that the specification has excluded solutions from the solution space that are potentially better. It is not uncommon for an experienced developer to use more sophisticated (so, for example, shorter or easier to expand/maintain) implementations in a solution space than a specifier. However, if we assume that the developer adheres to the specification, this is no longer possible in this case. If the developer decides against the specification, then one needs to ask if the specification still fulfills any purpose at all.
A second problem can arise if the specification is not formulated in pseudo-code, but is still overly specific. Since the solution space is very small, the developer may have a hard time finding an implementation that is actually still contained within it. If the specification were to be formulated more openly and the solution space became larger as a result, it would also be easier to find suitable implementations.
A final problem concerns the status of the developer in the development of software with a solution space that is too small. If the solution space is too large, the specifier becomes the RE monkey; if the solution space is too small, the developer becomes the code monkey. Their main task is no longer to understand the requirements and find an adequate solution, but to translate pseudo-code into the code of the desired programming language. In the worst case, their tasks can also be handled by a code generator.
Another consequence of this problem is that the developer no longer has a real understanding of the software being developed. If you only type pseudo-code, you don't understand what the software actually does and why it solves certain problems in a certain way. Similarly, there is a lack of understanding of how new problems or changing requirements can be implemented in the system.
Instead of looking for the perfect solution space size before the actual development, here's a better and easier way.... It is easier to restrict a solution space that is too large afterwards than to re-expand one that is too small. Additional requirements or a more detailed formulation on existing requirements can still be added during the development process. In fact, the necessity of some details in the requirements can only be determined during the development process. If, on the other hand, a specification with pseudo-code exists, for example, it is extremely difficult to derive business requirements from it.
Since the subsequent restriction of the solution space is easier, one should get in the habit of writing specifications that allow for such a large solution space. But how then can the problems of a solution space that is too large - such as those described above - be solved without restricting it too much in advance? So that no one becomes a monkey (RE monkey or code monkey), one should abandon the idea that the task of the specifier is completed with the submission of the specification document to the developer.
Instead, the two must communicate with each other afterwards. The developer must understand the business requirements and the specifier must at least understand the approach to the technical implementation so that both can find a solution together. At the same time, each has their special areas. The specifier knows the requirements and the technical background better, the developer, on the other hand, has a better understanding of the details of the previous architecture, subtleties of frameworks, etc.
Professionalism and technical implementation can be understood as being at the extremes of a continuum. The two endpoints are the business end user on the one hand and the system architecture on the other. Sometimes one gets the impression that specifier and developer each understand each other at an outer point of this continuum and their responsibilities only in a short section. In fact, however, the two should approach each other in order to establish a common basis for communication. The specifier should have a basic understanding of the technical implementation in order to understand how the developer is trying to implement the business requirements that they understand. The developer should have a basic understanding of the domain and use cases in order to be familiar with the solution space in the first place and to be able to select one of the best solutions.
It's not about everyone being at the level of a senior developer and a professional employee. Both should have their specialized knowledge and immersions. A specifier does not need to know different ways to compare objects in Java, and the developer does not need to know that waiting times for health insurance are regulated across tariffs in the model conditions (MB/KK). But a specifier should know what an object and OOP are, and a developer should know what waiting times are (assuming that we are building software for health insurance companies). This allows them to define the solution space together, build great software, and no one becomes a monkey.
Would you like to learn how the software from adesso insurance solutions helps insurance companies to digitalize? Then please contact our expert Karsten Schmitt, Head of Business Development.
Do you have any questions or comments? Then please leave us a comment.