Keywords

1 Introduction

In the mid-nineties, Gamma, Helm, Johnson and Vlissides introduced the Gang of Four (GoF) patterns catalog [8]. The GoF catalog documents reusable object-oriented solutions to common development problems. The authors employ a unified form for the specification of the patterns. A pattern specification includes the name of the pattern, the intent of the pattern, a motivating scenario, a discussion of the pattern applicability, a diagrammatic description of the pattern structure, the responsibilities of the participants (i.e., classes or interfaces) involved in the pattern structure, a description of how the participants collaborate to carry out their responsibilities, the consequences of the pattern, implementation guidelines, sample code, known uses of the pattern, and, a discussion concerning other related patterns. The patterns are divided in three different categories: creational patterns that deal with the creation of objects, structural patterns that concern the composition of classes or objects and behavioral patterns that focus on the interaction between objects and the distribution of responsibilities.

Nowadays, the GoF catalog is a significant part of object-oriented design theory and practice. Many people like students, junior developers and more experienced developers search on the Web for information about the GoF patterns, for a variety of reasons. Popular Web sites provide definitions of the patterns and examples that illustrate instances of the patterns in specific contexts. The patterns definitions range from brief statements of the patterns intent to more detailed ones that specify the patterns structure and other details.

The story behind this paper starts a couple of years ago, when an undergraduate student came to complain about his grade on a software engineering quiz. Specifically, the student claimed that his answer to a question about a design pattern was correct. While discussing the issue, the student said that he had studied the pattern very well and that he had also used in his study additional sources that he found on a Web site. When we looked again at the information given about the pattern on that site we found out that both the definition and the examples of the pattern deviated from the original GoF pattern definition. In fact, we discovered that several examples were entirely wrong!

So, sometimes the information we find on the Web about the GoF patterns deviates from the original definitions of the patterns that are given in the GoF catalog.

This observation is the main motivation of this paper. The overall research goal of the paper is to assess the compliance of pattern definitions and examples that we find on the Web to the original GoF pattern definitions. To this end, we study a corpus of pattern definitions and examples, gathered from four different well-known Web sites. At first, we identify the kinds of deviations that occur in the pattern definitions and examples. To highlight the issues that arise from the different kinds of deviations, we discuss in detail characteristic examples. Then, we study the amount of deviations, the percentage of deviating definitions and examples, and the density of deviations in the patterns definitions and examples. Finally, we discuss the implications of our findings for the developers who seek information about GoF patterns on the Web.

The rest of this paper is structured as follows. In Sect. 2 we discuss related work. In Sect. 3 we provide details regarding the setup of this study. In Sect. 4, we report the different kinds of deviations that occur in pattern definitions and examples. In Sect. 5, we assess the compliance of the pattern definitions and examples to the original GoF patterns. In Sect. 6, we conclude with the practical implications of our findings.

2 Related Work

Design patterns have been an active area of research and practice for decades. The state of the art is vast with dedicated communities and venues for researchers and practitionersFootnote 1\(^,\)Footnote 2. An interesting systematic mapping of the state of the art is provided by Mayvan et al. [10]. According to this study, research efforts in the area of design patterns can be divided in 5 major sub-areas that concern pattern development, specification, usage, mining, and quality evaluation.

Our study falls in the area of pattern quality evaluation. This area includes efforts that investigate the impact of pattern usage on software quality and efforts that assess the soundness of pattern instances.

The impact of design pattern usage in software quality has been the subject of several interesting empirical studies. For instance, Prechelt et al. [12] found that the use of design patterns provides flexibility, which facilitates maintenance. In another study, Prechelt et al. [11] observed that the use of design patterns, along with specialized comments related to these patterns is helpful towards performing maintenance tasks. According to Vokac [14], the use of patterns by itself does not guarantee few defects. Bieman et al. [4] observed that pattern classes are prone to changes. Aversano et al. [3] observed that pattern classes are more prone to changes than classes that depend on the pattern classes. Walter and Alkhaeir [15] and Alfadel et al. [1] observed that classes participating to design patterns are less prone to code smells than classes not participating to design patterns. A detailed systematic literature review of works that concern the relation between design patterns and code smells has been performed by Almadi et al. [2].

Regarding the soundness of design patterns, Izurieta and Bieman [9] introduced the notions of design pattern rot and grime. Design rot is the breakdown of the structural integrity of a design pattern instance, as a result of changes in subsequent software releases. Design pattern grime is a decay due to unrelated features added in classes that participate in a design pattern instance. These features do not jeopardize the intent of the pattern. In a study of 3 software systems, Izurieta and Bieman did not find evidence of design rot. However, they found evidence of design pattern grime. In further studies, Dale and Izurieta [5] observed that certain kinds of design grim results in higher technical debt, while Reimanis and Izurieta [13] investigated possible correlations between different kinds of grime. In a study of five software systems, Feitosa et al. [7] found a linear accumulation of design grime that depends on the design patterns and the developers, while in a subsequent study [6] the same authors observed correlations between the accumulation of grime and decreased performance, security and correctness.

Still, regarding the soundness of design patterns, Zarras [17] observed frequent mistakes in the usage of the Command pattern, during the project of a software engineering course. The observed mistakes concern the configuration of command objects and invalidate the benefits of the Command pattern. The author further introduced a pattern for the proper configuration of command objects. In a similar effort, Zarras [16] reported mistakes in the usage of Strategy pattern and introduced respective solutions in the form of patterns.

Going beyond the state of the art, this paper evaluates the compliance of patterns definitions and examples found on the Web to the original GoF pattern definitions in a study that involves a large number of definitions and examples gathered from different sites.

3 Setup of the Study

Our study considers four popular Web sites that provide information for several software development topics like refactoring, UML, design principles and patterns. In particular, we focus on pattern definitions and examples from Source MakingFootnote 3, Refactoring GuruFootnote 4, Tutorials PointFootnote 5 and Java T PointFootnote 6.

Table 1. Corpus of patterns definitions and examples.

During the data-gathering process we visited each Web site. For each GoF pattern, we looked for the pattern definition and examples that illustrate the usage of the pattern. We downloaded local copies of the pattern definition and examples. At the end of the gathering process, we reviewed the retrieved definitions and examples to make sure that we did not omit any relevant definitions and examples.

The corpus of our study consists of 90 pattern definitions and 409 examples that concern a variety of programming languages. The corpus and the raw data of the compliance evaluation are available onlineFootnote 7

Table 1 provides further details concerning the corpus. More specifically, Source Making provides definitions for all of the GoF patterns and a total number of 144 examples. There is at least one example for every GoF pattern. Most of the examples are in Java and C++. However, there are also several examples in Delphi, PhP and Python. Refactoring Guru covers all, but the Interpreter pattern. Therefore the corpus includes 22 definitions and 220 examples. The examples are in Pseudo code, Java, C#, C++, PhP, Python, Ruby, Swift, Typescript, and Go. Tutorials Point and Java T Point focus only on Java. Tutorials Point covers all of the GoF patterns, while Java T Point covers all but the Visitor pattern. Thus, Tutorials Point and Java T Point add 23 and 22 patterns definitions and examples to the corpus, respectively.

To assess the compliance of a set of pattern definitions (respectively examples) to the original GoF pattern definitions we rely on three basic statistics:

  • The number of deviations that occur in the examined set.

  • The percentage of deviating pattern definitions (respectively, examples) in the examined set.

  • The density of deviations in the examined set, defined as the number of deviations, over the cardinality of the examined set.

In all our deliberations, the diagrams that we use are made by us, for copyright purposes, with respect to the diagrams that accompany the GoF pattern definitions, the diagrams that accompany the pattern definitions of the sites and the source code of the pattern examples given in the sites.

The deviation analysis that concerns pattern definitions relies on the combination of text and diagrams of the site contrasted to the GoF definition text and diagrams. The comparison protocol involves the following sequence of checks:

  • The first check concerns whether the intent of the pattern definition given in the site is inline with the intent of the GoF pattern definition.

  • The second check concerns whether the participants specified in the GoF pattern definition are present in the pattern definition of the site.

  • The third check concerns whether the participants specified in the pattern definition of the site provide the methods of the corresponding participants of the GoF pattern definition.

The deviation analysis that concerns the pattern examples is based on the text and the source code of the pattern examples given in the sites, contrasted to the GoF definition text and diagrams. The comparison protocol involves the following steps:

  • The first check concerns whether the participants specified in the GoF pattern definition are present in the pattern example.

  • The second check concerns whether the participants in the pattern example provide the methods of the corresponding participants of the GoF pattern definition.

  • The third check concerns whether the implementation of the participants in the pattern example is inline with the behavior of the corresponding participants of the GoF pattern definition.

4 Kinds of Deviations

In the corpus, we identified four different kinds of deviations. Specifically, we found intent deviations, missing participants, incomplete participants and erroneous participants. In the rest of this section, we discuss each kind of deviations in more detail, along with respective examples.

Table 2. Intent deviations found in the corpus.

4.1 Intent Deviations

In the corpus, we identified certain pattern definitions that do not reflect the purpose of the corresponding patterns, as specified in the GoF catalog. Hereafter, we call these issues, intent deviations. Obviously an intent deviation is very important, as it always results in an incorrect definition. Table 2, illustrates the deviating pattern definitions that we found in the corpus. Specifically, the table gives the Web site that provides each pattern definition, the deviating intent of the pattern, and the original intent of the pattern, as specified in the GoF catalog.

At a glance, in Tutorials Point the intent of Abstract Factory is defined quite differently from the original definition of the pattern. According to the original GoF definition, an abstract factory is an interface that defines methods for creating families of related objects, without having to specify their concrete classes, while according to the Tutorials Point definition the abstract factory is an interface that defines methods for creating other factories.

Fig. 1.
figure 1

Command structure, as defined in the GoF catalog.

In the Tutorials Point definition of Builder, the main issue is that there is absolutely no mention of the separation between the construction process of a complex object and the different representations of the object, which is the key benefit of the pattern. The intent of Visitor in the Tutorials Point definition is also very different from the original definition. According to the Tutorials Point definition, the purpose of a visitor class is to change the algorithm of another class, while in the latter the focus is on extensibility, and specifically the addition of new operations that operate on an hierarchy of objects, without having to change this hierarchy. Finally, in the Java T Point definition of Observer the intent of the pattern is incorrect as it refers to one-to-one, instead of one-to-many, dependencies between subscribers and observers.

4.2 Missing Participants

In the corpus, we encountered pattern definitions and examples that do not include all the participants, specified in the structure of the original pattern definitions. Hereon, we use the term missing participants to refer to these participants. The criticality of missing participants depends on the pattern and on who these participants are. In some cases, missing participants may result in incorrect pattern definitions and examples. In other cases, missing participants may result in incomplete pattern definitions and examples that partially illustrate the original pattern concepts.

Fig. 2.
figure 2

Command structure, as defined in Source Making.

Figure 1, gives the structure of the Command pattern, as specified in the GoF patterns catalog. The intent of Command is to “encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations”. Command defines a common interface for executing different commands. ConcreteCommand1 and ConcreteCommand2 are different classes that implement the Command interface. Client creates Command objects that belong to the different implementation classes. Invoker is parameterized with Command objects. To execute a command, Invoker invokes the execute() method on a particular Command object.

Figure 2, gives the structure of the Command pattern, as defined in Source Making. In particular, Client, CallbackInterface, CallbackOne and CallbackTwo, correspond to Client, Command, ConcreteCommand1 and ConcreteCommand2, in the original pattern structure, respectively. Apparently, in the Source Making definition, the Invoker participant is missing. The Client participant creates Command objects and invokes the execute() method to execute the corresponding commands. The lack of Invoker is important here because the pattern definition does not reflect the concept of parameterization of objects with different commands.

4.3 Incomplete Participants

The corpus includes patterns definitions and examples involving incomplete participants that do not provide a complete and exact set of methods, as they should according to the original pattern definitions. Specifically, some methods may be missing, or some methods may be merged with others in larger methods that have more responsibilities than they should.

Fig. 3.
figure 3

Composite structure, as defined in the GoF catalog.

The impact of incomplete participants depends on the methods that are actually missing. In some cases, the lack of certain methods is very important (e.g. the lack of certain creation methods in creational patterns), resulting in incorrect pattern definitions and examples, while in other cases the missing methods result in incomplete definitions and examples that partially illustrate the concepts of the original pattern.

Fig. 4.
figure 4

Example of Composite from Source Making.

Figure 3, shows the original structure of the Composite pattern. The purpose of the pattern is to “compose objects into tree structures to represent part-whole hierarchies”. Component is a class that defines a uniform interface for both primitive and composite objects. The interface includes domain-specific methods (like operation()) and methods for managing the structure of composite objects. Specifically, add() serves for adding a Component object to a Composite object, while remove() allows removing a Component object from the Composite object. The getChild() method allows retrieving a Component object that is part of the Composite object, based on a given index. The interesting point in the pattern is that Component not only defines the uniform interface, but also provides default implementations for the defined methods. Leaf represents primitive objects that do not consist of other objects. Leaf provides its own implementations for the domain-specific methods and inherits the default implementations of the structure management methods, defined in Component. Composite represents composite objects. It provides implementations for both the domain-specific methods and the structure management methods, defined in Component. Client manipulates objects that conform with the aforementioned composite structure, via the uniform Component interface.

Fig. 5.
figure 5

Builder structure, as defined in the GoF catalog.

Figure 4, gives an example of Composite from Source Making. AbstractFile, File and Directory, correspond to Component, Leaf and Composite. Directory is an incomplete participant because it does not provide methods for the removal and the retrieval of AbstractFile objects.

4.4 Erroneous Participants

In the corpus, we also found erroneous participants that do not behave as dictated in the original definitions of the patterns. Typically, the deviations of the participants’ behaviors are such that they jeopardize the intent of the pattern. We observed erroneous participants only in the pattern examples. Erroneous participants have a direct impact on the correctness of the examples in which they appear. In all cases, the examples are wrong.

Fig. 6.
figure 6

Example of Builder from Refactoring Guru.

Figure 5 gives the original structure of Builder. The intent of this pattern is to “separate the construction of a complex object from its representation so that the same construction process can create different representations”. Consequently, the same construction process can be reused to create objects with different internal representations. Builder, defines an interface that provides operations for the creation of the constituents parts of a Product object. ConcreteBuilder, is an implementation of the Builder interface that constructs and assembles the parts of the Product object. In general, Builder can have different alternative implementations that correspond to different internal Product object representations. ConcreteBuilder further provides a method for retrieving the resulting Product object. Director, realizes the overall Product object construction process, by invoking methods of the Builder interface.

Figure 6 details an example of Builder from Refactoring Guru. In the example, the Builder interface has two alternative implementations, namely, CarBuilder and ManualCarBuilder. The products of CarBuilder and ManualCarBuilder are Car and Manual objects, respectively. The constituent parts of Car and Manual objects are Engine, Transmission, TripComputer and GPSNavigator objects. Director realizes the object construction process. However, the Director class is not correct with respect to the pattern specification. The main problem is that the Director class implements three different construction processes, instead of one. The different construction processes are similar, in fact they are code clones, and depend on the internal representation of the objects under construction.

Table 3. Assessing the compliance of pattern definitions.

The two classes that implement the Builder interface are also incorrect. In particular, the two classes do not construct the parts of the resulting objects, as dictated by the pattern. Instead, Director constructs the parts and gives them to the Builder implementation classes as parameters of respective methods. Consequently, Director is not independent from the internal representation of the objects under construction. Overall, the example fails to communicate the intent of the Builder pattern.

5 Compliance of Pattern Definitions and Examples

In this section, we assess the compliance of pattern definitions and examples to the original GoF pattern definitions.

We begin our assessment from the pattern definitions that we consider in this study. Table 3, summarizes the results of the assessment. Specifically, for each site the table provides (1) the number of deviations that we observed in the definition of each pattern, and in total, (2) the density of deviations in the pattern definitions, defined as the total number of deviations in pattern definitions, divided by the number of pattern definitions, and (3) the percentage of patterns with deviating definitions. The empty cells in the table concern patterns for which there are no definitions in the respective sites.

Overall, we observe that patterns with deviating definitions do not occur very often. In the sites that we examined, the percentage of patterns with deviating definitions varies from 9.09% to 30.43%. The density of deviations in the pattern definitions is low, ranging from 0.05 deviations per definition to 0.35 deviations per definition. In practice, this means that most definitions adhere to the original GoF definitions. In Source Making we observe the highest density of deviations, followed by Refactoring Guru, Tutorials Point and Java T Point. In all sites, there are eleven patterns with deviation-free definitions.

Next, we investigate the compliance of the pattern definitions that we consider in our study, in relation to the different kinds of deviations that occur in the definitions. To this end, for each site, Table 4 gives the number of deviations of each kind that occur in the definitions, and the density of the deviations of each kind.

Table 4. Compliance of pattern definitions for the different kinds of deviations.

In the results, we observe a low density of intent deviations in the patterns definitions. In Source Making and Refactoring Guru, there are no intent deviations. In Source Making and Refactoring Guru, the density of missing participants is higher than the density of incomplete participants. The cells that concern missing and incomplete participants in Tutorials Point and Java T Point are empty because the pattern definitions in these sites are very brief, consisting only of the intent of the patterns. The structure of the patterns is not part of the provided definitions. The brevity of the definitions is also the reason for the relatively small number of deviations and the respective low deviation density values in Tutorials Point and Java T Point. Despite the low deviation density values, in these two sites we observe the only occurrences of intent deviations, which result in entirely incorrect pattern definitions. Moreover, 3 of the 11 occurrences of missing participants also result in incorrect pattern definitions that do not reflect the original purpose of the patterns. The rest of the deviations, result in incomplete definitions that partially specify the structure of the original GoF patterns.

Table 5. Assessing the compliance of pattern examples.

We move on to the assessment of the pattern examples that we consider in our study. The results of the assessment are given in Table 5. In particular, for each site the table reports (1) the number of examples for each pattern, (2) the number of deviations that we observed in the examples, (3) the density of deviations in the examples, defined as the total number of deviations, divided by the number of pattern examples, and (4) the percentage of patterns with deviating examples. The empty cells in the table signify the lack of pattern examples in the corresponding sites.

Table 6. Compliance of pattern examples for the different kinds of deviations.

In the results, we observe that patterns with deviating examples are quite frequent. Specifically the percentage of patterns with deviating examples in the examined sites ranges from 50% to 86.6%. The density of deviating examples is medium-high, varying from 0.47 to 1.09 deviations per example. In all sites, there are only three patterns with deviation-free examples. In three out of the four sites, the density of deviations in the examples is greater than 0.9. Practically this means that in many pattern examples we have multiple deviations. Among the sites, Source Making is the one with the highest density of deviations, followed by Java T Point, Refactoring Guru and Tutorials Point. In all sites, the percentage of patterns with deviating examples is higher than the percentage of patterns with deviating definitions.

Regarding the different kinds of deviations, Table 6 gives the number of deviations of each kind that occur in the examples, and the density of deviations of each kind. Among the different kinds of deviations, missing participants are the ones that occur more often, followed by incomplete participants and erroneous participants. In all sites, the number and the density of missing participants is high. On the other hand, the numbers and the densities of incomplete and erroneous participants are low. Overall, 60 of the 186 occurrences of missing participants and 20 of the 82 occurrences of incomplete participants, result in incorrect examples. The same holds for all the occurrences of erroneous participants. The rest of the deviations, result in examples that partially illustrate the structure of the original GoF patterns.

Threats to Validity: The retrieval of the examined definitions and examples has been done manually. The identification of deviations and the compliance assessment of the retrieved pattern definitions and examples has also been done manually. This is a possible threat to the construct validity of the study. To mitigate this risk and reduce the probability of human mistakes the gathering and the assessment of the data have been done in multiple iterations. Internal validity, is not an issue in our study because we do not attempt to establish any particular cause-effect relationships regarding the deviations that occur in the examined pattern definitions and examples. Regarding external validity, the scope of our study is pattern definitions and examples that we find on the Web. In this context, we studied pattern definitions and examples gathered from four well-known sites. Therefore, we are confident that our findings are representative of the scope of the study.

6 Takeaway Messages for the Developers

In this paper, we assessed the compliance of the pattern definitions and examples that we find on the Web, to the original GoF pattern definitions. Our study brought out the following key messages for the developers:

  • The developers should know that the definitions and examples that we find on the Web deviate from the original definitions.

  • The pattern definitions that we find on the Web may involve intent deviations, missing participants and incomplete participants, while the pattern examples may involve missing participants, incomplete participants and erroneous participants.

  • The impact of the different kinds of deviations to the correctness of the pattern definition and examples varies. Intent deviations and erroneous participants always result in incorrect definitions and examples. Missing participants and incomplete participants may also result in incorrect pattern definitions and examples. However, most of these deviations do not entirely jeopardize the involved pattern definitions and examples. Typically, these deviations result in definitions and examples that partially illustrate the original pattern concepts.

  • The developers should be more concerned about deviating examples than deviating definitions, since the frequency of the former is much higher than the frequency of the latter.

  • Finally, the developers should be aware that the choice of the site in which they seek information about GoF patterns is important. Certain sites appear more suitable for developers who are looking for pattern definitions and examples that fully comply to the original GoF pattern definitions, while other sites may be more appropriate for developers looking for simplified pattern variants. In any case, the developers should be very careful and crosscheck the information they find on the Web with the original Gof pattern information.

Besides the aforementioned takeaway messages, our study opens up a number of directions for future research. Specifically, a more detailed analysis of the specific deviations that occur in the definitions and the examples of each pattern would be interesting for the developers who seek information about specific patterns. Additional studies that involve the assessment of further sites and pattern collections would also be interesting. Finally, another issue worth investigating in the future is the (semi)automated validation of pattern definitions and examples that we find on the Web.