Identifying Architectural Bad Smells

10
Identifying Architectural Bad Smells Joshua Garcia, Daniel Popescu, George Edwards and Nenad Medvidovic Computer Science Department University of Southern California Los Angeles, CA 90089-0781, USA {joshuaga,dpopescu,gedwards,neno}@usc.edu Abstract Certain design fragments in software architectures can have a negative impact on system maintainability. Exam- ples of such fragments include applying a design solution in an inappropriate context, mixing design fragments that have undesirable emergent behaviors, and applying design abstractions at the wrong level of granularity. In this pa- per, we introduce the concept of architectural “bad smells,” which are frequently recurring software designs that can have non-obvious and significant detrimental effects on sys- tem lifecycle properties, such as understandability, testa- bility, extensibility, and reusability. We define architectural smells and differentiate them from related concepts, such as architectural antipatterns and code smells. We also de- scribe in detail a set of four representative architectural smells we encountered in the context of reverse-engineering and re-engineering two large industrial systems and from our search through case studies in research literature. For each of these architectural smells, we provide illustrative examples and demonstrate the impact on system lifecycle properties. 1 Introduction As the cost of developing software increases, so does the incentive to evolve and adapt existing systems to meet new requirements, rather than building entirely new systems. Today, it is not uncommon for a software application family to be maintained and upgraded over a span of five years, ten years, or longer. However, in order to successfully modify a legacy application to support new functionality, run on new platforms, or integrate with new systems, evolution must be carefully managed and executed. Frequently, it is necessary to refactor [20], or restructure the design of a system, so that new requirements can be supported in an efficient and reliable manner. Refactoring helps to control both evolution that has al- ready occurred and evolution that is planned for the future. First, if a system has already undergone some evolution, refactoring may remove undesirable characteristics intro- duced by the changes. System modifications that are rel- atively small tend to be applied in an incremental, ad-hoc fashion. Over time, this frequently results in architectural erosion, which is a divergence of a system’s implementa- tion from its intended design. One result of architectural erosion is that upgrades and bug fixes become successively more expensive to implement. In this situation, refactoring restores a system to a coherent and documented design, al- lowing evolution to proceed more easily. Second, if the fun- damental requirements of a system change, refactoring may be carried out in preparation for large-scale modifications. For example, refactoring may be performed to modularize functionality within a monolithic application, allowing it to be transformed into a product-line architecture, or to ab- stract platform-dependent code from core business logic, al- lowing the system to be ported to new a operating system or hardware platform. The most commonly used way to determine how to refactor is to identify code bad smells [5][20]. Code smells are implementation structures that negatively affect sys- tem lifecycle properties, such as understandability, testabil- ity, extensibility, and reusability; that is, code smells ulti- mately result in maintainability problems. Common exam- ples of code smells include very long parameter lists and duplicated code (i.e., clones). Code smells are defined in terms of implementation-level constructs, such as methods, classes, parameters, and statements. Consequently, refac- toring methods to correct code smells also operate at the implementation level (e.g., moving a method from one class to another, adding a new class, or altering the class inheri- tance hierarchy). While detection and correction of code smells is one way to improve system maintainability, many maintainability is- sues originate from poor use of software architecture-level abstractions — components, connectors, styles, and so on — rather than implementation constructs. In the course of

Transcript of Identifying Architectural Bad Smells

Identifying Architectural Bad Smells

Joshua Garcia, Daniel Popescu, George Edwards and Nenad MedvidovicComputer Science Department

University of Southern CaliforniaLos Angeles, CA 90089-0781, USA

{joshuaga,dpopescu,gedwards,neno}@usc.edu

Abstract

Certain design fragments in software architectures canhave a negative impact on system maintainability. Exam-ples of such fragments include applying a design solutionin an inappropriate context, mixing design fragments thathave undesirable emergent behaviors, and applying designabstractions at the wrong level of granularity. In this pa-per, we introduce the concept of architectural “bad smells,”which are frequently recurring software designs that canhave non-obvious and significant detrimental effects on sys-tem lifecycle properties, such as understandability, testa-bility, extensibility, and reusability. We define architecturalsmells and differentiate them from related concepts, suchas architectural antipatterns and code smells. We also de-scribe in detail a set of four representative architecturalsmells we encountered in the context of reverse-engineeringand re-engineering two large industrial systems and fromour search through case studies in research literature. Foreach of these architectural smells, we provide illustrativeexamples and demonstrate the impact on system lifecycleproperties.

1 Introduction

As the cost of developing software increases, so does theincentive to evolve and adapt existing systems to meet newrequirements, rather than building entirely new systems.Today, it is not uncommon for a software application familyto be maintained and upgraded over a span of five years, tenyears, or longer. However, in order to successfully modify alegacy application to support new functionality, run on newplatforms, or integrate with new systems, evolution must becarefully managed and executed. Frequently, it is necessaryto refactor [20], or restructure the design of a system, sothat new requirements can be supported in an efficient andreliable manner.

Refactoring helps to control both evolution that has al-

ready occurred and evolution that is planned for the future.First, if a system has already undergone some evolution,refactoring may remove undesirable characteristics intro-duced by the changes. System modifications that are rel-atively small tend to be applied in an incremental, ad-hocfashion. Over time, this frequently results in architecturalerosion, which is a divergence of a system’s implementa-tion from its intended design. One result of architecturalerosion is that upgrades and bug fixes become successivelymore expensive to implement. In this situation, refactoringrestores a system to a coherent and documented design, al-lowing evolution to proceed more easily. Second, if the fun-damental requirements of a system change, refactoring maybe carried out in preparation for large-scale modifications.For example, refactoring may be performed to modularizefunctionality within a monolithic application, allowing it tobe transformed into a product-line architecture, or to ab-stract platform-dependent code from core business logic, al-lowing the system to be ported to new a operating system orhardware platform.

The most commonly used way to determine how torefactor is to identify code bad smells [5] [20]. Code smellsare implementation structures that negatively affect sys-tem lifecycle properties, such as understandability, testabil-ity, extensibility, and reusability; that is, code smells ulti-mately result in maintainability problems. Common exam-ples of code smells include very long parameter lists andduplicated code (i.e., clones). Code smells are defined interms of implementation-level constructs, such as methods,classes, parameters, and statements. Consequently, refac-toring methods to correct code smells also operate at theimplementation level (e.g., moving a method from one classto another, adding a new class, or altering the class inheri-tance hierarchy).

While detection and correction of code smells is one wayto improve system maintainability, many maintainability is-sues originate from poor use of software architecture-levelabstractions — components, connectors, styles, and so on— rather than implementation constructs. In the course of

various architectural recovery [2] [17] and industrial main-tenance efforts, we noticed frequently recurring design frag-ments that have non-obvious and significant detrimental im-pacts on maintainability. We term these architectural badsmells because they are analogous to code smells: they rep-resent common “solutions” that are not necessarily faultyor errant, but still negatively impact software quality. In thesame way that identification of code smells and methodsfor addressing them have proven quite useful to softwareengineers [5], we posit that clearly codifying architecturalsmells will allow engineers to avoid and correct commondesign pitfalls.

The research contribution of this paper is two-fold. First,we introduce the notion of architectural smells, define thecharacteristics of architectural smells, and discuss how theyare different from related concepts, such as architecturalantipatterns. We believe this work lays the foundation forfurther exploration and utilization of the architectural smellconcept. Second, we describe in detail four architecturalsmells selected from a larger set that we discovered duringour architectural recovery and refactoring projects. Thesefour smells constitute a sufficiently representative subset ofarchitectural smells, and by focusing on a small number inthis paper, we are able to explain each in detail, provide anillustrative example from an industrial system, and demon-strate the impact on system lifecycle properties.

The remainder of this paper is organized as follows. Sec-tion 2 explains the characteristics and significance of archi-tectural smells. Section 3 summarizes research efforts inrelated topics. Section 4 introduces two long-term softwaremaintenance efforts on industrial systems and case studiesfrom research literature that motivated this work. Section 5describes four architectural smells in detail, and illustratesthe impact of each smell through concrete examples drawnfrom the systems mentioned in Section 4. Finally, Section 6provides closing discussion and insights.

2 Definition

In this section, we define what constitutes an architec-tural smell and discuss the important properties of architec-tural smells.

We define a software system’s architecture as “the set ofprincipal design decisions governing a system” [26]. Thesystem stakeholders determine which aspects are deemed tobe “principal.” In practice, this usually includes (but is notlimited to) how the system is organized into subsystems andcomponents, how functionality is allocated to components,and how components interact with each other and their exe-cution environment. An architectural smell is a commonly(although not always intentionally) used architectural de-cision that negatively impacts system quality. Architec-tural smells may be caused by applying a design solution

in an inappropriate context, mixing design fragments thathave undesirable emergent behaviors, or applying designabstractions at the wrong level of granularity. Architecturalsmells most directly affect lifecycle properties, such as un-derstandability, testability, extensibility, and reusability, butthey may have harmful side effects on other quality prop-erties like performance and reliability. Architectural smellsare remedied by altering the internal structure of the sys-tem and the behaviors of internal system elements withoutchanging the external behavior of the system.

We capture architectural smells as design instances thatare independent from the engineering processes that createdthe design. That is, human organizations and processes areorthogonal to the definition and impact of a specific archi-tectural smell. In practical terms, this means that the detec-tion and correction of architectural smells is not dependenton an understanding of the history of a software system.For example, an independent analyst should be able to au-dit a documented architecture and indicate possible smellswithout knowing about the development organization, man-agement, or processes.

We do not differentiate between architectural smells thatare part of an intended design (e.g., a set of UML specifi-cations for a system that has not yet been built) as opposedto an implemented design (e.g., the implicit architecture ofan executing system). Furthermore, we do not consider thenon-conformance of an implemented architecture to an in-tended architecture, by itself, to be an architectural smell.For example, it is possible for an intended architecture ofa system to include poor design elements, while the (non-conforming) implemented architecture replaces those ele-ments with better solutions.

In many contexts, a design that exhibits a smell will bejustified by other concerns. Architectural smells always in-volve a trade-off between different properties, and the sys-tem architects must determine whether action to correct thesmell will result in a net benefit. Furthermore, refactoring toreduce or eliminate an architectural smell may involve riskand almost always requires investment of developer effort.Architectural smells do, however, indicate that in the ma-jority of cases an architectural refactoring will improve thesystem quality.

We attempt to facilitate the detection of architecturalsmells through specific, concrete definitions captured interms of standard architectural building blocks — com-ponents, connectors, interfaces, and configurations. In-creasingly, software engineers reason about their systems interms of these concepts, so in order to be readily applicableand maximally effective, our architectural smell definitionssimilarly utilize these abstractions (see Section 5).

3 Related Work

In this section, we provide an overview of four topicsthat are directly related to architectural smells: code smells,architectural antipatterns, architectural mismatches, and de-fects.

The term bad smells (or code smells) was introduced byBeck and Fowler [5] for code structures that intuitively ap-pear as bad solutions and indicate possibilities for code im-provements. For most code smells, refactoring solutionsthat result in higher quality software are known. Althoughbad smells were originally based on subjective intuitions ofbad code practice, recent work has developed ways to detectcode smells based on metrics [15] and has investigated theimpact of bad smells using historical information [13]. Asnoted in Section 1, code smells only apply to implementa-tion issues (e.g., a class with too many or too few methods),and do not guide software architects towards higher-leveldesign improvements.

Closely related to code smells are antipatterns [3]. Anantipattern describes a recurring situation that has a negativeimpact on a software project. Antipatterns include wide-ranging concerns related to project management, architec-ture, and development, and generally indicate organiza-tional and processes difficulties (e.g., design-by-committee)rather than design problems. Antipatterns that specificallypertain to architectural issues only capture the causes andcharacteristics of poor design from a system-wide view-point (e.g., stove-piped systems). Architectural smells, onthe other hand, focus on design problems that are indepen-dent from process and organizational concerns, and con-cretely address the internal structure and behavior of sys-tems.

Another related concept that attempts to identify a kindof problem that occurs in software architecture is architec-tural mismatch [7]. Architectural mismatch is the set ofconflicting assumptions architectural elements may makeabout the system in which they are used. In turn, theseconflicting assumptions may prevent the integration of anarchitectural element into a system. Work conducted in [6]and [1] has resulted in a set of conceptual features used todefine architectural designs in order to detect architecturalmismatch. While instructive to our work, architectural mis-match research has focused heavily on the functional prop-erties of a system without considering the effects on lifecy-cle properties.

Finally, defects are similar to architectural smells, butdiffer in severity. A defect is a manifestation of an error ina system [22]. An error is a mental mistake made by a de-signer or developer [22]. In other words, a defect is an errorthat is manifested in either a requirements, design, or imple-mented system that is undesired or unintended [12]. Defectsare never desirable in a software system, while smells may

be desirable if a designer or developer prefers the reductionin certain lifecycle properties for a gain in other properties,such as performance.

4 Motivation

Our experience with two long-term software projectsbrought us to the realization that some commonly-used de-sign structures adversely affect system maintainability. Inthis section, we introduce these projects by summarizingtheir context and objectives. Later in the paper, we utilizespecific examples from these projects to illustrate the im-pact of architectural bad smells.

Maintenance of large-scale software systems includesboth architectural recovery and refactoring activities. Ar-chitectural recovery is necessary when a system’s architec-ture is not known, either because it has drifted away fromthe original, documented architecture or because the archi-tecture was never documented in the first place. Architec-tural refactoring is required when a system’s architecture isdetermined to be unsatisfactory and must be altered, eitherbecause the system’s requirements changed or the originalarchitecture was poorly designed. We discovered architec-tural bad smells during both an architectural recovery effort(summarized in Section 4.1) and an architectural refactoringeffort (summarized in Section 4.2). To substantiate our ob-servations, we found further examples of architectural badsmells that appear in recovery and refactoring efforts pub-lished in the research literature.

4.1 Grid Architecture Recovery

An extensive study of grid system [4] implementationscontributed to our collection and insights of architecturalsmells. Grid technologies allow heterogeneous organiza-tions to solve complex problems using shared computingresources. Four years ago, we conducted a pilot study [16]in which we extracted and studied the architecture of fivewidely-used grid technologies and compared their architec-tures to the published grid reference architecture [4]. Wesubsequently completed a more comprehensive grid archi-tecture recovery project and recently published a report [17]on the architectures of eighteen grid technologies, includinga new reference architecture for the grid. The examined gridsystems were developed in C, C++, or Java and containedup to 2.2 million SLOC. Many of these systems includedsimilar design elements that have a negative effect on qual-ity properties.

Figure 1 shows the identified reference architecture forthe grid. A grid system is composed of four subsystems:Application, Collective, Resource, and Fabric. Each sub-system is usually instantiated multiple times. An Appli-cation can be any client that needs grid services and is

Resource Node

Resource Node

Fabric

ResourceResource

Fabric

Application

other grid nodes

Client/Server Interactions

job execution/(m

eta-)data query

1...* grid nodes (typically 1 per organization)

1...* resource nodes

Collective

Layered Interactions

Notification interactions

Resource Utilization Balancing

Data Exchange

RequestInteractions

P2P interactions

Figure 1. Structural View of the Grid Refer-ence Architecture

able to use an API that interfaces with Collective or Re-source components. The components in the Collective sub-system are used to orchestrate and distribute data and gridjobs to the various available resources in a manner con-sistent with the security and trust policies specified by theinstitutions within a grid system (i.e., the virtual organiza-tion). The Resource subsystem contains components thatperform individual operations required by a grid system byleveraging available lower-level Fabric components. Fabriccomponents offer access capabilities to computational anddata resources on an individual node (e.g., access to file-system operations). Each subsystem uses different inter-action mechanisms to communicate with other subsystems,as noted in Figure 1. The interaction mechanisms are de-scribed in [17].

4.2 MIDAS Architecture Refactoring

In collaboration with an industrial partner, for the lastthree years we have been developing a lightweight middle-ware platform, called MIDAS, for distributed sensor ap-plications [14] [23]. Over ten software engineers in threegeographically distributed locations contributed to MIDASin multiple development cycles to address changing andgrowing requirements. In its current version, MIDAS im-plements many high-level services (e.g., transparent fault-

tolerance through component replication) that were not an-ticipated at the commencement of the project. Addition-ally, MIDAS was ported to a new operating system (Linux)and programming language (C++), and capabilities tailoredfor a new domain (mobile robotics) were added. As a con-sequence, the MIDAS architecture was forced to evolve inunanticipated ways, and the system’s complexity grew sub-stantially. In its current version, the MIDAS middlewareplatform consists of approximately 100 KSLOC in C++and Java. The iterative development of MIDAS eventuallycaused several architectural elements to lose conceptual co-herence (e.g., by providing multiple services). As a con-sequence, we recently spent three person-months refactor-ing the system to achieve better modularity, understandabil-ity, and adaptability. While performing the refactoring, weagain encountered architectural structures that negativelyaffected system lifecycle properties.

Figure 2 shows a layered view of the MIDAS middle-ware platform. The bottom of the MIDAS architecture isa virtual machine layer that allows the middleware to bedeployed on heterogeneous OS and hardware platforms ef-ficiently. The host abstraction facilities provided by the vir-tual machine are leveraged by the middleware’s architec-tural constructs at the layer above. These architectural con-structs enable a software organization to directly map itssystem’s architecture to the system’s implementation. Fi-nally, these constructs are used to implement advanced dis-tributed services such as fault-tolerance and resource dis-covery.

Figure 2. System Stack Layers in MIDAS

4.3 Studies from Research Literature

Given the above experiences, we examined the work inarchitectural recovery and refactoring published in researchliterature [2] [8] [9] [27]. Several available case studies that

involved recovering widely-used systems helped us to un-derstand architectural design challenges and common badsmells. In this paper, we refer to examples from a case studythat extracted and analyzed the architecture of Linux [2]. Inthis study, Bowman et al. created a conceptual architec-ture of the Linux kernel based on available documentationand then extracted the architectural dependencies within thekernel source code (800 KSLOC). They concluded that thekernel contained a number of design problems, such as un-necessary and unintended dependencies.

5 Architectural Smells

This section describes four architectural smells in de-tail. We define each architectural smell in terms of partic-ipating architectural elements — components, connectors,interfaces, and configurations. Components are computa-tional elements that implement application functionality ina software system [24]. Connectors provide application-independent interaction facilities, such as transfer of dataand control [19]. Interfaces are the interaction points be-tween components and connectors. Finally, configura-tions represent the set of associations and relationships be-tween components and/or connectors. We provide a genericschematic view of each smell captured in one or more UMLdiagrams. Architects can use diagrams such as these to in-spect their own designs for architectural smells.

5.1 Connector Envy

Description. Components with Connector Envy encom-pass extensive interaction-related functionality that shouldbe delegated to a connector. Connectors provide the fol-lowing types of interaction services: communication, coor-dination, conversion, and facilitation [19]. Communicationconcerns the transfer of data (e.g., messages, computationalresults, etc.) between architectural elements. Coordinationconcerns the transfer of control (e.g., the passing of threadexecution) between architectural elements. Conversion isconcerned with the translation of differing interaction ser-vices between architectural elements (e.g., conversion ofdata formats, types, protocols, etc). Facilitation describesthe mediation, optimization, and streamlining of interac-tion (e.g., load balancing, monitoring, and fault tolerance).Components that extensively utilize functionality from oneor more of these four categories suffer from the ConnectorEnvy smell.

Figure 3a shows a schematic view of one ConnectorEnvy smell, where ComponentA implements communica-tion and facilitation services. ComponentA imports a com-munication library, which implies that it manages the low-level networking facilities used to implement remote com-munication. The naming, delivery and routing services han-

ComponentA

Communication Library

<<import>>

ProcessingInterfaceA

ProcessingInterfaceB

ComponentB

process+ process(Type P)- convert(Type P)

PublicInterface

process(Type P){ b = new CoreClassB(); b.processCoreConcern (convert(P));}

+ processCoreConcern (ConcernType P)

CoreClassB

a

b

Figure 3. The top diagram depicts Connec-tor Envy involving communication and facil-itation services. The bottom diagram showsConnector Envy involving a conversion ser-vice.

dled by remote communication are a type of facilitation ser-vice.

Figure 3b depicts another Connector Envy smell, whereComponentB performs a conversion as part of its process-ing. The interface of ComponentB called process is imple-mented by the PublicInterface class of ComponentB. Pub-licInterface implements its process method by calling a con-version method that transforms a parameter of type Typeinto a ConcernType.

Quality Impact and Trade-offs. Coupling connectorcapabilities with component functionality reduces reusabil-ity, understandability, and testability. Reusability is reducedby the creation of dependencies between interaction ser-vices and application-specific services, which make it dif-ficult to reuse either type of service without including theother. The overall understandability of the component de-creases because disparate concerns are commingled. Lastly,testability is affected by Connector Envy, as any given testfailure could be the result of a fault in either the interactionfunctionality or the application logic. As a result, softwaredevelopers have to investigate two possible sources for theerror instead of just one.

As an example, consider a MapDisplay component thatdraws a map of the route followed by a robot through its en-

vironment. The component expects position data to arriveas Cartesian coordinates and converts that data to a screencoordinate system that uses only positive x and y values.The MapDisplay suffers from Connector Envy because itperforms conversion of data formats between the robot con-troller and the user interface. If the MapDisplay is usedin a new, simulated robot whose controller represents theworld in screen coordinates, the conversion mechanism be-comes superfluous, yet the MapDisplay cannot be reusedintact without it. Errors in the displayed location of therobot could arise from incorrect data conversion or someother part of the MapDisplay, yet the encapsulation of theadapter within the MapDisplay makes it difficult to test andverify in isolation.

In cases where efficiency is of greater concern thanmaintainability, the Connector Envy smell may be accept-able. More specifically, explicitly separating the interac-tion mechanism from the application-specific code createsan extra level of indirection. In some cases, it may also re-quire the creation of additional threads or processes. Highlyresource-constrained applications that use simple interac-tion mechanisms without rich semantics have a strong jus-tification for incorporating these mechanisms directly incomponents and tolerating the Connector Envy smell. How-ever, making such a trade-off simply for efficiency reasons,without considering the maintainability implications of thesmell, can have a disastrous cumulative effect as multipleincompatible connector types are placed within multiplecomponents that are used in the same system.

Example from Industrial Systems. The Gfarm Filesys-tem Daemon (gfsd) from a grid technology called GridDatafarm [25] is a concrete example of a component withConnector Envy that follows the form described in Figure 3.The gfsd is a Resource component and runs on a Resourcenode as depicted in Figure 1. The gfsd imports a library thatis used to build the lightweight remote procedure call (RPC)protocol within the gfsd. This built-in RPC mechanism pro-vides no interfaces to other components and, thus, is usedsolely by the gfsd. While the general schematic in Figure 3shows only an instance of communication and facilitation,this instance of the smell also introduces coordination ser-vices by implementing a procedure call mechanism. The in-terfaces of the gfsd provide remote file operations, file repli-cation, user authentication and node resource status moni-toring. These interfaces and the gfsd’s RPC mechanism en-able the notification, request, and P2P interactions shownin Figure 1 that occur across Resource nodes in Grid Data-farm.

Reusability, modifiability, and understandability are ad-versely affected by the Connector Envy smell in the gfsd.The reusability effects of Connector Envy can be seen in asituation where a new Resource component, called Gfarmworkflow system daemon (gwsd), that provides workflow-

based services is added to Grid Datafarm. The RPC mech-anism is built within the gfsd without interfaces that can bemade available to other components, hence the RPC mecha-nism cannot be used with the gwsd. Understandability is re-duced by the unnecessary dependencies between the gfsd’sapplication-specific functionality (e.g., file replication, localfile operations, etc.) and RPC mechanism. The combinationof application-specific functionality and interaction mecha-nisms throughout the functions of the gfsd enlarge the com-ponent in terms of function size, number of functions, andshared variables. Both modifiability and understandabilityare adversely affected by having the overwhelming major-ity of the gfsd’s functions involve the use or construction ofGrid Datafarm’s RPC mechanism.

It is possible that since grid technologies need to be effi-cient, the creators of Grid Datafarm may have intentionallybuilt a gfsd with Connector Envy in order to avoid the per-formance effects of the indirection required for a fully sepa-rated connector. Another fact to consider is that Grid Data-farm has been in use for at least seven years and has under-gone significant amounts of updates that have expanded thegfsd’s functionality. This has resulted in further commin-gling of connector-functionality with application-specificfunctionality.

5.2 Scattered Parasitic Functionality

Description. Scattered Parasitic Functionality describesa system where multiple components are responsible for re-alizing the same high-level concern and, additionally, someof those components are responsible for orthogonal con-cerns. This smell violates the principle of separation of con-cerns in two ways. First, this smell scatters a single concernacross multiple components. Secondly, at least one com-ponent addresses multiple orthogonal concerns. In otherwords, the scattered concern infects a component with an-other orthogonal concern, akin to a parasite. Combiningall components involved creates a large component that en-compasses orthogonal concerns. Scattered Parasitic Func-tionality may be caused by cross-cutting concerns that arenot addressed properly. Note that, while similar on thesurface, this architectural smell differs from the shotgunsurgery code smell [5] because the code smell is agnosticto orthogonal concerns.

Figure 4 depicts three components that are each respon-sible for the same high-level concern called SharedCon-cern, while ComponentB and ComponentC are responsi-ble for orthogonal concerns. The three components in Fig-ure 4 cannot be combined without creating a component thatdeals with more than one clearly-defined concern. Compo-nentB and ComponentC violate the principle of separationof concerns since they are both responsible for multiple or-thogonal concerns.

ComponentA

ComponentB

+ SharedConcernClassA

+ SharedConcern+ ConcernB

ClassB

ComponentC

+ SharedConcern+ ConcernC

ClassC

access

Figure 4. The Scattered Parasitic Functional-ity occurring across three components.

Quality Impact and Trade-offs. The Scattered Para-sitic Functionality smell adversely affects modifiability, un-derstandability, testability, and reusability. Using the con-crete illustration from Figure 4, modifiability, testability,and understandability of the system are reduced becausewhen SharedConcern needs to be changed, there are threepossible places where SharedConcern can be updated andtested. Another facet reducing understandability is that bothComponentB and ComponentC also deal with orthogonalconcerns. Designers cannot reuse the implementation ofSharedConcern depicted in Figure 4 without using all threecomponents in the figure.

One situation where scattered functionality is acceptableis when the SharedConcern needs to be provided by multi-ple off-the-shelf (OTS) components whose internals are notavailable for modification.

Example from Industrial Systems. Bowman et al.’sstudy [2] illustrates an occurrence of Scattered ParasiticFunctionality in the widely used Linux operating system.The case study reveals that Linux’s status reporting of ex-ecution processes is actually implemented throughout thekernel, even though Linux’s conceptual architecture indi-cates that status reporting should be implemented in thePROC file system component. Consequently, the status re-porting functionality is scattered across components in thesystem. This instance of the smell resulted in two unin-tended dependencies on the PROC file system, namely, theNetwork Interface and Process Scheduler components be-came dependent on the PROC file system.

The PROC file system example suffers from the samediminished lifecycle properties as the notional system de-scribed in the schematic in Figure 4. Modifiability andtestability are reduced because updates to status reporting

functionality result in multiple places throughout the kernelthat can be tested or changed. Furthermore, understandabil-ity is decreased by the additional associations created byScattered Parasitic Functionality among components.

The developers of Linux may have implemented the op-erating system in this manner since status reporting of dif-ferent components may be assigned to each one of thosecomponents. Although it may at first glance make senseto distribute such functionality across components, moremaintainable solutions exist, such as implementing a moni-toring connector to exchange status reporting data or creat-ing an aspect [11] for status reporting.

5.3 Ambiguous Interfaces

Description. Ambiguous Interfaces are interfaces thatoffer only a single, general entry-point into a compo-nent. This smell appears especially in event-based publish-subscribe systems, where interactions are not explicitlymodeled and multiple components exchange event mes-sages via a shared event bus. In this class of systems,Ambiguous Interfaces undermine static dependency analy-sis for determining execution flows among the components.They also appear in systems where components use generaltypes such as strings or integers to perform dynamic dis-patch.

Two criteria define the Ambiguous Interface smell de-picted in Figure 5. First, an Ambiguous Interface offersonly one public service or method, although its componentoffers and processes multiple services. The component ac-cepts all invocation requests through this single entry-pointand internally dispatches to other services or methods. Sec-ond, since the interface only offers one entry-point, the ac-

ComponentA

process+ process(GeneralType P)

PublicInterface

process(GeneralType P){ if (P == A) {...} if (P == B) {...} ...

Figure 5. An Ambiguous Interface is imple-mented using a single public method with ageneric type as a parameter.

cepted type is consequently overly general. Therefore, acomponent implementing this interface claims to handlemore types of parameters than it will actually process by ac-cepting the parameter P of generic type GeneralType. Thedecision whether the component filters or accepts an incom-ing event is part of the component implementation and usu-ally hidden to other elements in the system.

Quality Impact and Trade-offs. Ambiguous Interfacesreduce a system’s analyzability and understandability be-cause an Ambiguous Interface does not reveal which ser-vices a component is offering. A user of this componenthas to inspect the component’s implementation before usingits services. Additionally, in an event-based system, Am-biguous Interfaces cause a static analysis to over-generalizepotential dependencies. They indicate that all subscribersattached to an event bus are dependent on all publishers at-tached to that same bus. Therefore, the system seems tobe more widely coupled than what is actually manifested atrun-time.

The following example helps to illustrate the negative ef-fect of the wide coupling. Consider an event-based systemcontaining n components, where all components are con-nected to a shared event bus. Each component can publishevents and subscribes to all events. A change to one pub-lisher service of a component could impact (n − 1) com-ponents, since all components appear to be subscribed tothe event, even if they immediately discard this event. Amore precise interface would increase understandability bynarrowing the number of possible subscribers to the pub-lishing service. Continuing with the above example, if eachcomponent would list its detailed subscriptions, a mainte-nance engineer could see which m components (m ≤ n)would be affected by changing the specific publisher ser-vice. Therefore, the engineer would only have to inspectthe change effect on m components instead of n − 1. Of-ten times, components exchange events in long interactionssequences; in these cases, the Ambiguous Interface smellforces an architect to repeatedly determine component de-pendencies for each step in the interaction sequence.

Example from Industrial Systems. A significant num-ber of event-based middleware systems suffer from the formof Ambiguous Interface smell depicted in Figure 5. An ex-ample of a widely used system that follows this design isthe Java Messaging Service (JMS) [10]. Consumers in JMSreceive generic Message objects through a single receivemethod. The message objects are typically cast to specificmessage types before any one of them is to be processed.Another event-based system that acts in this manner is theInformation Bus [21]. In this system, publishers mark theevents they send with subjects and consumers can subscribeto a particular subject. Consumers may subscribe to eventsusing a partially specified subject or through wild-cards,which encourage programmers to subscribe to more events

then they actually process.The event-based mechanism used by MIDAS conforms

to the diagram in Figure 5. In the manner describedabove, MIDAS is able to easily achieve dynamic adapta-tion. Through the use of DLLs, MIDAS can add, remove,and replace components during run-time, even in a highlyresource-constrained sensor network system. As mentionedin Section 4.2, we have recently spent three person-monthsrefactoring the system to achieve better modularity, under-standability, and adaptability. During the refactoring, deter-mining dependencies and causality of events in the systemwas difficult due to the issues of over-generalized potentialdependencies described above. An extensive amount of re-covery needed to be done to determine which dependenciesoccur in what context.

5.4 Extraneous Adjacent Connector

Description. The Extraneous Adjacent Connector smelloccurs when two connectors of different types are used tolink a pair of components. Eight types of connectors havebeen identified and classified in the literature [19]. In thispaper, we focus primarily on the impact of combining twoparticular types of connectors, procedure call and event con-nectors, but this smell applies to other connector types aswell. Figure 6 shows a schematic view of two componentsthat communicate using both a procedure call connector andan event-based connector.

ComponentA

send

<<Connector>>SoftwareEventBus

receive

ComponentB

sendreceive

+ operation()

ClassA

+ operation()

ClassB

...a = new ClassA();a.operation();...

<<call>>

Figure 6. The connector SoftwareEventBus isaccompanied by a direct method invocationbetween two components.

In an event-based communication model, componentstransmit messages, called events, to other components asyn-chronously and possibly anonymously. In Figure 6, Compo-nentA and ComponentB communicate by sending events tothe SoftwareEventBus, which dispatches the event to the re-cipient. Procedure calls transfer data and control throughthe direct invocation of a service interface provided by acomponent. As shown in Figure 6, an object of type ClassBin ComponentB communicates with ComponentA using adirect method call.

Quality Impact and Trade-offs. An architect’s choiceof connector types may affect particular lifecycle proper-ties. For example, procedure calls have a positive affecton understandability, since direct method invocations makethe transfer of control explicit and, as a result, control de-pendencies become easily traceable. On the other hand,event connectors increase reusability and adaptability be-cause senders and receivers of events are usually unawareof each other and, therefore, can more easily be replaced orupdated. However, having two architectural elements thatcommunicate over different connector types in parallel car-ries the danger that the beneficial effects of each individualconnector may cancel each other out.

While method calls increase understandability, usingan additional event-based connector reduces this benefitbecause it is unclear whether and under what circum-stances additional communication occurs between Com-ponentA and ComponentB. For example, it is not evidentwhether ComponentA functionality needs to invoke servicesin ComponentB. Furthermore, while an event connector canenforce an ordered delivery of events (e.g., using a FIFOpolicy), the procedure call might bypass this ordering. Con-sequently, understandability is affected, because a softwaremaintenance engineer has to consider the (often unforeseenand even unforeseeable) side effects the connector typesmay have on one another.

On the other hand, the direct method invocation poten-tially cancels the positive impact of the event connector onadaptability and reusability. In cases where only an eventconnector is used, components can be replaced during sys-tem runtime or redeployed onto different hosts. In the sce-nario in Figure 6, ComponentA’s implementation cannot bereplaced, moved or updated during runtime without invali-dating the direct reference ComponentB has on ClassA.

This smell may be acceptable in certain cases. For ex-ample, standalone desktop applications often use both con-nector types to handle user input via a GUI. In these cases,event connectors are not used for adaptability benefits, butto enable concurrent input from the user.

Example from Industrial Systems. In the MIDAS sys-tem, shown in Figure 2, the primary method of communi-cation is through event-based connectors provided by theunderlying architectural framework. All high-level services

of MIDAS, such as resource discovery and fault-tolerancewere also implemented using event-based communication.While refactoring as described in Section 4.2, we observedan instance of the Extraneous Adjacent Connector smell.We identified that the Service Discovery Engine, whichcontains resource discovery logic, was directly accessingthe Service Registry component using procedure calls. Dur-ing the refactoring an additional event-based connector forrouting had to be placed between these two components, be-cause the Fault Tolerance Engine, which contains the faulttolerance logic, also needed access to the Service Registry.However, the existing procedure call connector increasedthe coupling between those two components and preventeddynamic adaptation of both components.

This smell was accidentally introduced in MIDAS tosolve another challenge encountered during the implemen-tation. In the original design, the Service Discovery Enginewas broadcasting its events to all attached connectors. Oneof these connectors enabled the Service Discovery Engineto access peers over a UDP/IP network. This instance ofthe Extraneous Adjacent Connector smell was introducedso that the Service Discovery Engine could directly accessthe Service Registry, avoiding unnecessary network traf-fic. However, as discussed, the introduced smell instancecaused the adaptability of the system to decrease.

6 Conclusion

Architectural smells constitute a class of potential prob-lems caused by the presence of design fragments that de-tract from lifecycle properties. The schematic diagrams likethose shown in Section 5 can be used by architects to detectarchitectural smells. Architectural smells can be detected inboth the conceptual architecture of a software system andthe recovered architecture of an implemented system. Oncean architectural smell is detected, an architect can assess theimpact of the smell on relevant qualities by conducting ananalysis such as that in Section 5.

Code smells have helped developers identify when andwhere source code needs to be refactored [5]. Analogously,architectural smells tell architects when and where to refac-tor their architectures. While general principles, such asisolation of change and separation of concerns, may be usedby architects to determine when and where to refactor an ar-chitecture, architectural smells provide specific repeatableforms that have the potential to be automatically detected.

Architectural smells can be applied to large, com-plex systems by revealing opportunities for smaller, localchanges within the architecture that cumulatively add upto improved system quality. Therefore, architects can usesmells to analyze the most relevant parts of an architecturewithout needing to deal with the intractability of analyzingthe system as a whole.

Our planned future work on architectural smells includesa categorization of architectural smells, architectural smelldetection and correction processes, and tool support to aidin those processes. A categorization of architectural smellswould include an extensive list of smells and an analysis ofthe impact, origins, and ways to correct the smells. Toolsand methods to detect architectural smells would aim to ex-tract relevant facts from implemented systems. Architec-tural smells may be written in an Architectural DescriptionLanguage (ADL), i.e., “a language that provides features formodeling a software system’s conceptual architecture, dis-tinguished from the system’s implementation” [18]. Usingan ADL specification of a smell, conceptual architecturescan be analyzed for smells before they are implemented.Correction of smells would include the inception of a setof architectural refactoring operations and the provision oftools to help recommend particular operations for detectedsmells. In attempting to repair architectures of widely-usedsystems, the authors of [27] identified a set of operationsthat can be used as a starting point for determining a com-plete set of architectural refactoring operations. By tryingto correct some of the architectural smells we found in bothour own and others’ experiences, such as [2] [8] [9] [27],we hope to identify other architectural refactoring opera-tions and determine which operations are relevant to partic-ular smells.

References

[1] A. Abd-Allah. Composing heterogeneous software architec-tures. PhD thesis, University of Southern California, 1996.

[2] I. Bowman, R. Holt, and N. Brewster. Linux as a case study:its extracted software architecture. In Proc. of the 21st Int.Conf. on Software Engineering, 1999.

[3] W. Brown, R. Malveau, H. M. III, T. Mowbray, J. Wiley, andI. Sons. AntiPatterns - Refactoring Software, Architectures,and Projects in Crisis. Wiley, New York, 1998.

[4] I. Foster and et al. The anatomy of the grid: Enabling scal-able virtual organizations. Int. Journal of High PerformanceComputing Applications, 15(3), 2001.

[5] M. Fowler. Refactoring: Improving the Design of ExistingCode. Addison-Wesley Professional, 1999.

[6] C. Gacek. Detecting Architectural Mismatches During Sys-tems Composition. PhD thesis, Univ. of Southern California,1998.

[7] D. Garlan, R. Allen, and J. Ockerbloom. Architectural mis-match or why it’s hard to build systems out of existing parts.In Proc. of the 17th Int. Conf. on Software Engineering,1995.

[8] M. W. Godfrey and E. H. S. Lee. Secrets from the monster:Extracting mozilla’s software architecture. In Proc. of theSecond Int. Symposium on Constructing Software Engineer-ing Tools, 2000.

[9] B. Grone, A. Knopfel, and R. Kugel. Architecture recoveryof apache 1.3 – a case study. In Proc. of the 2002 Int. Conf.on Software Engineering Research and Practice, 2002.

[10] K. Haase. Java message service tutorial, 2002.[11] G. Kiczales and E. Hilsdale. Aspect-Oriented Programming.

Springer, 2003.[12] N. G. Leveson. Safeware: System Safety and Computers.

Addison-Wesley, 1995.[13] A. Lozano, M. Wermelinger, and B. Nuseibeh. Assessing

the impact of bad smells using historical information. 9thInt. Workshop on Principles of Software Evolution, 2007.

[14] S. Malek, C. Seo, S. Ravula, B. Petrus, and N. Medvi-dovic. Reconceptualizing a family of heterogeneous em-bedded systems via explicit architectural support. In Proc.of the 29th Int. Conf. on Software Engineering, 2007.

[15] R. Marinescu. Detection strategies: metrics-based rules fordetecting design flaws. In Proc. of the 20th IEEE Int. Conf.on Software Maintenance, 2004.

[16] C. Mattmann, N. Medvidovic, P. Ramirez, and V. Jakobac.Unlocking the Grid. In Proc. of the 8th ACM SIGSOFT Sym-posium on Component-Based Software Engineering, 2005.

[17] C. A. Mattmann, J. Garcia, I. Krka, D. Popescu, and N. Med-vidovic. The anatomy and physiology of the grid revisited.Technical Report USC-CSSE-2008-820, Univ. of SouthernCalifornia, 2008.

[18] N. Medvidovic and R. Taylor. A Classification and Compar-ison Framework for Software Architecture Description Lan-guages. IEEE Trans. on Software Engineering, pages 70–93,2000.

[19] N. R. Mehta, N. Medvidovic, and S. Phadke. Towards ataxonomy of software connectors. In Proc. of the 22nd Int.Conf. on Software Engineering, 2000.

[20] T. Mens and T. Tourwe. A survey of software refactoring.IEEE Trans. on Software Engineering, Jan 2004.

[21] B. Oki, M. Pfluegl, A. Siegel, and D. Skeen. The Informa-tion Bus: an architecture for extensible distributed systems.In Proc. of the 14th ACM Symposium on Operating SystemsPrinciples, 1994.

[22] R. Roshandel. Calculating architectural reliability via mod-eling and analysis. In Proc. of the 26th Int. Conf. on SoftwareEngineering, 2004.

[23] C. Seo, S. Malek, G. Edwards, D. Popescu, N. Medvidovic,B. Petrus, and S. Ravula. Exploring the role of software ar-chitecture in dynamic and fault tolerant pervasive systems.Int. Workshop on Software Engineering for Pervasive Com-puting Applications, Systems, and Environments, 2007.

[24] M. Shaw and et al. Abstractions for software architectureand tools to support them. IEEE Trans. on Software Engi-neering, 1995.

[25] O. Tatebe, Y. Morita, S. Matsuoka, N. Soda, andS. Sekiguchi. Grid datafarm architecture for petascale dataintensive computing. In Proc. of the 2nd IEEE/ACM Int.Symposium on Cluster Computing and the Grid, 2002.

[26] R. Taylor, N. Medvidovic, and E. Dashofy. Software Archi-tecture: Foundations, Theory, and Practice. John Wiley &Sons, 2008.

[27] J. Tran, M. Godfrey, E. Lee, and R. Holt. Architectural re-pair of open source software. 8th Int. Workshop on ProgramComprehension, 2000.