---
author:
- Mohammad Reza Ahmadzadeh Raji
bibliography:
- 'thesis1.bib'
date: |
     A Thesis Presented in Partial Fulfilment of the Requirements for the Degree of Master of Engineering in Computer Engineering\
    Razi University\
    2014 
title: '**Refactoring Software Packages via Community Detection from Stability Point of View**'
---

![image](logoEn)\
**Faculty of Engineering**\
**Department of Computer Engineering**\
**M.Sc.Thesis**\
\[6mm\] 2.5cm

1.5cm 1.5cm **June 2014**

Acknowledgements {#acknowledgements .unnumbered}
================

##### 

First and foremost, I would like to express my appreciation and thanks to my supervisor, Dr. Behzad Montazeri. I would like to thank him for his encouragement, motivation and priceless advices throughout my research.

##### 

I would also like to express my deepest appreciation to my father, Dr. Mehrdad Ahmadzadeh, my mother and my wife, Sara who have been the most supportive, through thick and thin and have helped me in the difficulties of the paths I have taken.

**Dedicated to my beloved wife, for her endless support and encouragement**

Abstract {#abstract .unnumbered}
========

##### 

As the complexity and size of software projects increases in real-world environments, maintaining and creating maintainable and dependable code becomes harder and more costly. Refactoring is considered as a method for enhancing the internal structure of code for improving many software properties such as maintainability.

##### 

In this thesis, the subject of refactoring software packages using community detection algorithms is discussed, with a focus on the notion of package stability. The proposed algorithm starts by extracting a package dependency network from Java byte code and a community detection algorithm is used to find possible changes in package structures. In this work, the reasons for the importance of considering dependency directions while modeling package dependencies with graphs are also discussed, and a proof for the relationship between package stability and the modularity of package dependency graphs is presented that shows how modularity is in favor of package stability.

##### 

For evaluating the proposed algorithm, a tool for live analysis of software packages is implemented, and two software systems are tested. Results show that modeling package dependencies with directed graphs and applying the presented refactoring method, leads to a higher increase in package stability than undirected graph modeling approaches that have been studied in the literature.\
\
**Keywords:** Graph clustering, Community detection, Package refactoring, Software metrics, Stability, Coupling, Cohesion.

Introduction to code refactoring
================================

##### 

There are many properties that can be associated with good code. Sommerville describes good code as one that is highly maintainable, dependable, efficient and usable [@sommerville2004]. Truly reusable code is considered gold in the software industry as it significantly effects productivity and thus lowers costs [@lim1994] and without a doubt, good code is backed by a good design. A professional software engineer must first design a software and then implement the code based on the design. However, in real-world scenarios, the great attributes of a good software might fade away as the project grows. Tight schedules, high customer demands and the high number of programmers involved in large projects are considered as some of the reasons that make efficient and engineered implementations change into a mess. A mess that is not easily maintained, reused, changed or depended upon. Refactoring is considered the cure for this infiltration of the project.

##### 

Refactoring is a common word for a day-to-day programmer with its origins in mathematics and ultimately in the Latin language. The root *factor* has the meaning of *maker* and hence refactoring is known as re-making something. In mathematics, when you factor an expression, you re-make it and provide a more cleaner version. The exact origin of the word, refactoring, in computer science is somewhat unknown, however the Forth language community is known to have been the first people to have used this expression [@fowler1999]. Chapter six of Leo Brodie’s book, Thinking Forth is dedicated to the subject of refactoring [@brodie1984].

##### 

Martin Fowler, the author of one of the most canonical books on refactoring [@fowler1999], describes it as *“the process of changing a software system in such a way that it does not alter the external behavior of the code, yet improves its internal structure.”*

##### 

This thesis solely focuses on refactoring methods that involve the use of graph clustering methods, however to better understand the reasons and effects of proposed methods, a brief and concise explanation of known refactoring techniques is given.

Well-known refactoring techniques
---------------------------------

-   **Rename method.** This technique may be the most simple refactoring method one can use. Simply renaming identifiers and variables will make the code clearer, more understandable and can reduce the need for comments. An appropriate name for a method, variable or a class is one that is descriptive so that a new programmer can understand its work just by a glance.

-   **Inline temp.** Temporary variables can make methods longer and more complicated. It is suggested that temporary variables that are being used only once or are a result of a method call be completely removed and the value assigned to them be used in the code. An example is provided below.

    **Incorrect:**

    ``` {language="python"}
        def add_something():
            return 1 + 2
        
        def foo():
            temp_variable = add_something()
            print "The result is " + temp_variable
    ```

    **Correct:**

    ``` {language="python"}
        def foo():
            print "The result is " + add_something()
    ```

-   **Extract method.** Known as arguably the most important refactoring technique, Extract method aims at reducing the size of long methods by breaking them into smaller methods with descriptive variables. Many refactoring and simplifying techniques in software engineering involve breaking code and algorithms into smaller, more understandable chunks. This method is one of them.

    ``` {language="python"}
        class Foo:
            username
            def __init__(self):
                # Some initialization code
                self.username = "Some username"
        
            def func1(self):
                print "Welcome"
                print "You have logged in as " + self.username
                print "Something else"
                
            def func2(self):
                print "Welcome"
                print "You have logged in as " + self.username
                print "Some reports"
                
    ```

    ##### 

    In the provided example, lines 8 and 9 are equal to lines 13 and 14 and can be extracted into a new method that greets the user. Extract method is considered as an important and basic refactoring technique that highly effects the cohesion of classes from which methods have been extracted. Extract method suggests the extraction of pieces of code that are used more than once (duplicate code). If this condition is met while extracting piece of code A from methods B and C, then after refactoring, both B and C will be using A and thus reducing the cohesion in their class. However, one must realize that if appropriate interfaces are not used in the code and other classes in a package use method A, then instead of reducing cohesion, coupling will be increased. A thorough study on this issue and a metric for finding appropriate pieces of code for extracting while considering the notion of cohesion is provided in [@goto2013extract].

    Considering our focus on graph clustering methods in refactoring, it is worth noting that some work has been done in detemining the class a method belongs to, with the help of community detection techniques [@pan2009class]. However, introducing new methods and extracting them with community detection is still in need of attention.

-   **Inline method.** In some cases, the opposite of Extract method should be applied. Suppose method A is simple, clear and is being used only once, possibly in a stable class whose content is not likely to change. In this case, using an identifier for the code in method A only results in an extra call for no benefit. This method can be removed and its content can be used inline.

-   **Replace method with Method object.** This technique can be considered as an aid, in situations where Extract method becomes difficult because of the high number of temporary variables in a long method. In a case where the number of temporary variables is high, Extract method can become a cumbersome task because passing around all the temporary variables between the extracted methods can prove to be messy and finding the needed temporary variables for a piece of extracted code can take a lot of time.

    To resolve this issue, one approach is to move the long method into a new class, set the local temporary variables as class attributes and then apply Extract method. This method provides a better state, from which we can continue our refactoring using Extract method or other techniques.

-   **Pull up method.** Imagine a scenario in which a piece of code is duplicated in two different classes, it is best to pull that code up into a super class of those two classes.

    **Before refactoring:**

    ``` {language="python"}
        class Person:
            firstname = None
            lastname = None
            def __init__(self):
                # Some initialization code
                
        class Student(Person):
            studentNo = None
            def __init__(self):
                # Some initialization code
                
            def makeFullName(self):
                return self.firstname + " " + self.lastname
                
            def getStudentNo(self):
                return self.studentNo
                
        class Employee(Person):
            salary = None
            def __init__(self):
                # Some initialization code
            
            def makeFullName(self):
                return self.firstname + " " + self.lastname
                
            def getSalary(self):
                return self.salary
                
    ```

    **After refactoring:**

    ``` {language="python"}
        class Person:
            firstname = None
            lastname = None
            def __init__(self):
                # Some initialization code
        
            def makeFullName(self):
                return self.firstname + " " + self.lastname
                
        class Student(Person):
            studentNo = None
            def __init__(self):
                # Some initialization code
                
            def getStudentNo(self):
                return self.studentNo
                
        class Employee(Person):
            salary = None
            def __init__(self):
                # Some initialization code
                
            def getSalary(self):
                return self.salary
                
    ```

-   **Extract surrounding method.** Imagine a case in which several different methods are almost identical but with a slight difference in the middle of each one. In some languages, one can pull up the duplicated code into a new method and pass the middle section to the method which it yields to. This ability is provided in some languages like Ruby and can be simulated in some other languages by passing callback functions. A Ruby example is given below.

    ``` {language="ruby"}
        def testMethod
            puts "Something printed from inside testMethod"
            yield
            puts "Something printed from inside testMethod"
        end
        testMethod {puts "Something printed from the block"}
    ```

-   **Replace conditional with polymorphism.** This method of refactoring can help remove the complexity and code smell of conditional logic and demonstrate the principle of true object-oriented design.

Code quality and software metrics
=================================

##### 

Code quality is one of the most important factors that directly effects a project’s maintainability phase. The quality of a good code determines how flexible a project is and determines the limits of the resuability of its components. Good code can be changed more quickly and newcomers to the project can understand it more easily. Another important feature that code quality can greatly effect, is how much we can trust that new changes will not cause unexpected effects and will not introduce bugs to the project [@baggen2012standardized].

##### 

Although code quality is considered as an important subject in software projects, many developers and projects simply neglect its importance and features. This is normally due to tightened schedules, high customer demands and low budgets.

##### 

Code quality has been discussed in the literature for a long time and more specifically, quantitative measurement of quality factors and providing metrics has been greatly studied. However, the study of software metrics has been diverse and the need for a strong and refined approach is felt [@kitchenham2010s]. In this thesis we focus on three well-known object-oriented quality factors, namely coupling, cohesion and package stability.

Coupling and cohesion
---------------------

##### 

Coupling is one of the most famous internal product attributes. Generally, two pieces of code are said to be coupled if changes in one causes the other to change. In the object-oriented paradigm, coupling between two classes is considered a bad and unwanted attribute, however a system with no coupling between its classes would mean that interaction is not occurring between the classes and therefore it would simply fail to function.

##### 

Cohesion, which almost always comes with coupling, is another important internal product attribute. In an object-oriented system, a class is said to have a high cohesion if its internal structures and methods have high connectivity with themselves. The goal in a good design is high cohesion and low coupling, meaning that classes should be cohesive and therefore fully related to their responsibility while they have a low coupling with other classes so that they can change without causing too many changes in other parts of the system. Designs with high cohesion and low coupling make the system more reliable and maintainable [@fenton1998software], [@troy1981measuring].

##### 

The notions of coupling and cohesion have been excessively studied in the literature and many metrics have been proposed for measuring them. This thesis briefly surveys different approaches in the literature.

### Basic definitions by Myers

##### 

Myers, Stevens and Constantine introduced the concept of coupling in procedural programming. Based on this, Fenton defined six different levels of coupling [@alghamdi2008measuring]. These levels of coupling are shown below from worst to best.

-   **Content coupling.** If one element branches into or changes the internal statements of another element, they are said to have content coupling.

-   **Common coupling.** If two elements refer to the same global variable, they are said to have common coupling.

-   **Control coupling.** If the data that one element sends to the other controls its behavior, then control coupling is implied.

-   **Stamp coupling.** Two elements are stamp coupled if they send more information to each other than necessary.

-   **Data coupling.** If two elements communicate with each other by parameters with no control coupling, then they are data coupled.

-   **No coupling.** If two elements have no communication with each other then they are not coupled.

### Fenton and melton’s metric

##### 

Fenton and melton proposed a metric for coupling which is expressed as

$$\label{eq:fenton}
C(x, y) = i + n / (n+1)$$

where $n$ is the number of interactions between the two components $x$ and $y$ and $i$ is the level of the worst coupling found between $x$ and $y$. In their metric, the coupling level is based on Myer’s classification. No coupling is given a coupling level of 0 and the next levels have higher numeric values.

##### 

Alghamdi discusses several important points about this metric [@alghamdi2008measuring].

-   All types of interconnections are considered equal, with equal effects on coupling.

-   The Fenton and Melton metric is an example of a inter-modular metric, meaning that it calculates the coupling between a pair of components in contrast with intrinsic metrics that measure the coupling of a component individually.

-   Coupling values approach the next level when the interconnections between two components increases.

##### 

Alghamdi also proposes a new coupling metric based on a description matrix of the system [@alghamdi2008measuring].

### Chidamber and Kemerer’s suite

##### 

Chidamber and Kemerer [@chidamber1991towards] gives the first formal definition of coupling by defining coupling as any evidence that a method from one class uses a method or variable of another class. In their proposed suite, known as the CK suite, Chidamber and Kemerer give provide different metrics. The six metrics are as follows.

-   Weighted Method per Class (WMC)

-   Number Of Children (NOC)

-   Depth of Inheritence Tree (DIT)

-   Coupling Between Objects (CBO)

-   Lack of Cohesion in Methods (LCOM)

-   Response For a Class (RFC)

##### 

Among their six metrics, CBO (Coupling Between Objects) is proportional to the number of non-inheritance related couples with other classes. For measuring coupling, CBO aggregates the total number of couples a class has to another class, which implies that different couples have the same strength and effect. Hitz and Montazeri [@hitz1995measuring] argue that the CK suite does not fully conform to measurment theory.

### Alghamdi’s coupling metric

##### 

Alghamdi’s approach is based on the idea of generating a description matrix of all the factors that effect coupling and then calculating a coupling matrix based on the collected data. An overview of this approach is depicted in Fig. \[alghamdi\]

![An overview of Alghamdi’s coupling metric[]{data-label="alghamdi"}](alghamdi.png){width=".7\columnwidth"}

##### 

The description matrix is an $m$ by $n$ matrix where $m$ is the number of system components and $n$ is the number of component members. In an object-oriented system, components are represented by classes and members are class variables and methods. An example of a description matrix is depicted in Table \[desc\_matrix\].

  **Component**   $E_1$      $E_2$      ...   $E_n$
  --------------- ---------- ---------- ----- ----------
  $C_1$           $d_{11}$   $d_{12}$         $d_{1n}$
  $C_2$           $d_{21}$   $d_{22}$         $d_{2n}$
  ...                                          
  $C_m$           $d_{m1}$   $d_{m2}$         $d_{mn}$

  : An example of Alghamdi’s description matrix[]{data-label="desc_matrix"}

### A qualitative approach to coupling and cohesion

##### 

While many quantitative approaches for measuring coupling and cohesion have been proposed in the literature, few qualitative approaches have been discussed. Kelsen [@representational2003] proposes an interesting information-based method for analyzing coupling and cohesion and finding refactoring suggestions. Kelsen’s approach considers a special type of coupling, namely representational coupling. When an object calls a method of another object, some information about the callee is exposed. If the information is about the low level implementation of the callee, then representational coupling is high. If the call exposes higher level information, then representational coupling is low. Many metrics in the literature, including the works of Chidamber and Kemerer [@chidamber1991towards] can not capture representational coupling [@representational2003]. The main reason behind this issue is that many works simply count different types of interactions and assign ordinal numbers to these interactions. Kelsen, also presents a minimum for the representational coupling inherently contained in a system, which is known as intrinsic representational coupling.

##### 

Kelsen’s approach is based on the idea that if one can find two states in a system, namely *witness states*, that yield different messages between objects but cannot affect the states of other objects, then this indicates that coupling can be improved and representational coupling is higher than it should. The elevator example below is borrowed from [@representational2003].

##### 

Suppose that the behavior of some elevators in a building is modeled using two classes, ElevatorControl and Elevator. Every elevator has two methods, *direction()* and *position()*, which return the direction and position of the elevator. The ElevatorControl class is responsible for handling requests and checks every elevator’s distance and position for finding the closest elevator for a request. Two different implementations for ElevatorControl’s *handleRequest* method can be written.

$minDist \gets Infinity$ Elevator $ec \gets null$ //reference to closes elevator $d \gets $ Compute $distance(e, r)$ using $e.direction()$ and $e.position()$ $ec \gets e$ $minDist \gets d$ $ec.addRequest(r)$

$minDist \gets Infinity$ Elevator $ec \gets null$ //reference to closes elevator $d \gets e.computeDistance(r)$ $ec \gets e$ $minDist \gets d$ $ec.addRequest(r)$

##### 

In the second implementation, the task of computing en elevator’s distance is given to each elevator with the $computeDistance$ method. It is clear that the $ElevatorControl$ class does not need to know the distance and position of every elevator and only needs their distances, therefore less information from the $Elevator$ class is being exposed in the second implementation and representational coupling is decreased.

##### 

Kelsen’s qualitative approach may be considered a precise and great method for measuring representational coupling, however, because of its non-quantitative nature it is not clear if it can be applied to large, real-life software systems with many classes, and its utilization in real-life scenarios is currently considered as an open problem.

Stability
---------

##### 

Stability is the amount of likeliness, that a class or a package will not change. Stability is inherently difficult to measure because the future changes and needs of a project are not well known, however some metrics exist that try to measure stability. The importance of this stability in software metrics was first mentioned by Hitz and Montazeri [@hitz1995measuring].

##### 

Some methods for measuring the stability of a software package, utilize the history of the class’s changes in the past and try to predict its future. The changes of a class or a package is typically accessed through version control systems such as Git[^1] and Subversion[^2], however these approaches can not be used in early stages of software design because of the lack of change history available at the time.

##### 

Robert Martin [@martin2003agile] takes a different approach to measuring the stability of a software package. He believes that stability is proportional to responsibility and a package is said to be responsible and independent if many other entities depend on it, while it doesn’t depend on others itself. A package $p$ is said to be irresponsible and thus unstable, if it depends on many other entities, meaning that if they change they cause $p$ to change as well. By Martin’s definition, in Fig. \[stable\_package\], X is an example of a stable package and in Fig. \[unstable\_package\], Y resembles an unstable package.

![An example of a stable package[]{data-label="stable_package"}](stable_package.png)

![An example of an unstable package[]{data-label="unstable_package"}](unstable_package.png)

##### 

As a metric for stability, Martin defines the instability of a package as given in Eq. \[eq:Instability\] where $I$ is instability, $C_a$ is afferent couplings and $C_e$ represents the number of efferent couplings. Afferent couplings is the number of classes outside the package that depend on classes within the package and efferent couplings is the number of classes within the package that depend on outside classes.

$$\label{eq:Instability}
I=\frac{C_e}{C_a + C_e}$$

##### 

If a package $p$ has an *instability* of 0, then the $p$ has maximum stability and if the package holds a value of 1 for *instability*, then it would mean that the number of afferent couplings is 0 and therefore $p$ depends on other packages while no other package depends on $p$ and this would make it an extremely unstable package.

##### 

Martin also proposes the Stable Dependencies Principle (SDP) that helps the software design process by ensuring that modules that should be easily changeable not depend on modules that are harder to change [@martin2003agile]. In this case, packages should always have a higher $I$ metric than the ones they depend on. Concenting to this principle, one would be able to see a tree of packages, in which stable ones are placed at the bottom and the most unstable ones are at the top. The benefit of this approach is that packages that are violating SDP can be easily spotted. Any package depending on a package above it, would mean a violation of the principle.

##### 

It is important to note that not all packages should or could be fully stable, as this would cause an unchangeable and inflexible system. Also, not all packages can be unstable as this would create an irresponsible system with a large number of connections and a high coupling. It is clear that pieces of code that are likely to change should be placed into unstable packages and pieces of code that are not very likely to change in the future should be placed in stable packages. Martin argues that high level design can not be placed in unstable packages because it resembles the architectural decisions of the projects, however if high level code is placed in stable packages then it would almost be impossible to change it after the project becomes more mature and more pieces of code start depending on it. The solution to this dilemma is the use of abstract classes that can introduce the flexibility and flow of stability that is needed. The basic idea behind the Stable Abstraction Principle (SAP) is that a package has to be as abstract as it is stable. This principle ensures that the stability of a package does not contradict its flexibility. The SAP proposes a metric for measuring the abstractness of a package which is a simple ratio and is shown in Eq. \[eq:abstractness\] in which $N_a$ is the number of abstract classes inside the package and $N_c$ is the number of classes inside the package.

![The relationship between asbtractness and instability[]{data-label="abstract_stable_graph"}](abstract_stable_graph.png)

##### 

Martin defines three important areas in the relationship between abstractness and stability. If we set abstractness (A) as the vertical axis and instability (I) as the horizontal axis in a cartesian graph, then three spots depicted in Fig. \[abstract\_stable\_graph\] are as follows.

-   **Zone of pain.** The zone of pain is where a package is highly stable and yet its abstractness is zero. Such a package is hardly changeable.

-   **Zone of uselessness.** A package in this zone is highly abstract and also highly unstable and not depended on. This means that its abstractness is useless.

-   **The main sequence.** This is the ideal point for a package. A package near the main sequence is a package that conforms to the SAP and is as abstract as it is stable. The sequence is ideal and thus not many packages can truly be placed on this line, however the distance of a package from this ideal line can be measured.

$$\label{eq:abstractness}
A = \frac{N_a}{N_c}$$

$$\label{eq:abstract_stable_distance}
D = \frac{|A + I - 1|}{\sqrt{2}}
D' = |A + I - 1|$$

##### 

In Eq. \[eq:abstract\_stable\_distance\], $D$ is the distance from the main sequence and $D'$ is its normalized version that ranges from $[0, 1]$.

Community detection and applications
====================================

##### 

Community detection is defined as the process of finding communities of nodes in networks, such that the nodes inside a community have a higher property resemblance to one another compared to nodes in another community. A network is a graph with a pair of sets, $V$ and $E$, where $V$ is the set of all vertices and $E$ is the set of all edges in the network. Every community in a network is considered as a partition of the set $V$. Typically, the process of detecting communities in a network consists of the following steps.

1.  Specifying a quality measure that defines the quality of a partitioned graph.

2.  Using a specific method to assign nodes to different communities (clusters) in a way that increases the quality measure in step 1.

There are normally three different terms, related to the subject of community detection that are sometimes used interchangeably by mistake, thereforee distinguishing between these terms is needed before going into the details of each method.

-   **Graph partitioning vs Community detection.** The most important difference is that the problem of graph partitioning is universally defined as a problem where the number and sizes of the clusters are specified a priori. This is not the case in graph clustering or cluster analysis in general. The second, less important difference between these two terms is that clustering excludes the possibility of overlap by convention, so that it is still possible to speak of an overlapping clustering, whereas a partition or partitioning excludes the possibility of overlap by definition.

-   **Graph clustering vs Community detection.** Graph clustering and community detection are normally used interchangeably in the litrature and in this thesis.

![The Zachary club[]{data-label="zachary_club"}](zachary.png)

##### 

Many different community detection and graph partitioning algorithms have been proposed in the literature, some of which will be briefly discussed in this thesis.

Classification of clustering methods
------------------------------------

##### 

Graph clustering methods are normally difficult to classify, however Wiggerts [@wiggerts1997using] believes that they can generally be divided into the following methods.

-   **Hierarchical methods.** Hierarchical approaches are known as some of the early solutions to the problem. These methods provide a hierarchy of partitions like a tree, known as a dendrogram. A sample dendrogram is depicted in Fig. \[zachary\_club\_dendrogram\]. Hierarchical methods are themselves divided into the two groups of agglomerative approaches and divisive approaches. In agglomerative approaches, the algorithm starts with placing every node inside a separate cluster. Then the algorithm starts merging the clusters based on their similarity. It is important to note that the algorithm will not stop unless told to, thereforee knowing the number of wanted partitions in the result is crucial. In divisive hierarchical approaches, the algorithm starts with a single cluster that contains all the nodes of the graph. The algorithm then splits the cluster based on the similarity between the nodes, keeping the similar ones in the same cluster. Different hierarchical algorithms are distinguished by their distance function which is responsible for determining the similarity between two given nodes.

-   **Optimization based methods.** These algorithms generally take an initial inaccurate clustering and with the help of a quality measure, try to enhance and improve the cluster and optimize the quality. One of the most common and famous quality measures in the literature is the modularity measure proposed by Girvan and Newman [@chen2013new]. Various kinds of optimization techniques are applicable in this category of graph clustering algorithms, such as genetic algorithm based optimization methods, particle swarm methods, etc. A simple genetic algorithm approach can be like the following [@shtern2012clustering].

    1.  Select a random population of partitions

    2.  Generate a new population by selecting the best according to a quality measure, such as Newman’s modularity

    3.  Repeating step 2 until a certain criteria is met

-   **Graph theoretical based methods.** Graph theoretical algorithms are methods that utilize the formal descriptions and properties of graphs and their respective subgraphs. In these methods, various subgraphs and properties are used to extract meaningful clusters from the original graph. Two important and common types of graph theoretical algorithms exist, namely aggregation algorithms and minimal spanning tree algorithms. Aggregation algorithms use the function of reduction on different nodes and merge them in each step. Different potential nodes for merging are chosen using different techniques, such as neighbourhoodness, strong connections and etc. Minimal spanning tree algorithms use the minimal spanning tree of the graph. These algorithms are normally not considered accurate as they tend to create large clusters, however some enhanced versions of these algorithms have been suggested in the literature [@shtern2012clustering].

-   **Construction algorithms.** These algorithms assign nodes into clusters in one pass. The bisection algorithm and density search techniques are considered as examples of such methods.

![A dendrogram for the Zachary club[]{data-label="zachary_club_dendrogram"}](zachary_dendrogram.eps)

##### 

The minimum cut approach is the most obvious and the most easiest way of tackling the problem of community detection. In this method, one tries to find two groups/partitions in a graph for which the edges connecting the two is the least. This approach mostly falls in the area of graph partitioning, because the number of partitions in the end result must be known a priori so that one can know how many times the algorithm should be applied. It is worth noting that if the minimum cut approach were to be used with no constraint, then a trivial solution to the problem would be to place all vertices in one partition only, thus minimizing the number of edges between partitions. Clearly this solution would not give any information on the *communities* in a network. In the software engineering sense, the result of such a method would be a system with zero coupling and maximum cohesion, which seems the goal. However many important aspects of the software such as reusability, separation of concerns, object orientedness, flexibility, etc. will be lost. This raises the idea that maybe another measurement apart from coupling and cohesion is needed that can help find an optimum point for the two. This measure must be able to truly model and represent different objects in a software dependency network. In the subject of graph theory, a measure that can model the *goodness* of a partition is known as a quality measure. Using a community quality measure in the field of software engineering has only recently been discussed in the literature [@pan2009class], [@pan2013refactoring].

Quality measures
----------------

##### 

The quality of a partition found by a community detection algorithm is determined with a quality measure. This measure should show how good a partition is. Many algorithms provide many partitions without equal goodness, therefore it is absolutely necessary to measure the quality of the provided partitions and detect the best. Quality functions give a number to each partition so that the partitions can be ranked and compared to one another. Arguably, the most common and famous quality function is Newman and Girvan’s Modularity [@newman2004finding].

##### 

Modularity is based on the idea that a random graph contains no meaningful community. Based on this idea, if one can make a similar graph to the one being analyzed with the same number of vertices, edges and degrees but with edges placed at random, then by comparing it to the original graph one can find the major differences that have created communities. To understand the notion of modularity, we start by another measure for the goodness of a partition and build on it. Let $G$ be a graph with elements of its adjacency matrix presented as $A_{vw}$, where $A_{vw}$ is 1 if nodes $v$ and $w$ are connected and 0 otherwise, and $C_v$ being the community in which vertex $v$ belongs to. The following measure shows the fraction of edges in graph $G$, that fall within communities.

$$\label{eq:Fraction of edges in the same community}
\frac{\sum_{vw} A_{vw}\delta(C_v, C_w) } {\sum_{vw}(A_{vw}) } = \frac{1}{2m} \sum_{vw}A_{vw}\delta(C_v, C_w)$$

where $\delta$ is the Kronecker delta function and $m$ is the number of edges in the graph.

##### 

This fraction takes the value of 1 when all edges fall in one community and hence is not a good enough measure.

##### 

The idea behind modularity is that a random graph does not have a meaningful community structure and thus, if generated carefully, should provide a good point of comparison. Carefully generating a random graph that can depict the features and properties of the original graph but with no meaningful community is known as providing a null model in the area of complex systems. In this case, one can provide a graph which has the same amount of vertices, edges and vertex degrees while its edges are rewired randomly, so that the graph looses its community structure. In such a graph, the probability of an edge being in between vertices $v$ and $w$, if connections are made at random is calculated as below.

$$\label{eq:The probability of an edge between v and w}
\frac{k_vk_w}{2m}$$

where $k_v$ and $k_w$ are the degrees of vertex $v$ and $w$ respectively. Now, by using equations \[eq:Fraction of edges in the same community\] and \[eq:The probability of an edge between v and w\], one can calculate the modularity measure as

$$\label{eq:Modularity}
Q=\frac{1}{2m}\sum_{vw}[A_{vw} - \frac{k_vk_w}{2m}] \delta(C_v, C_w).$$

##### 

By looking at Eq. \[eq:Modularity\], one can see some important aspects of this measure. The Kronecker delta function makes sure that a connection between two graph nodes in two different communities makes no contribution to modularity. Two connected nodes inside a community, make a positive contribution to modularity and the contribution is inversely proportional to the degrees of the two nodes. Also two nodes that are not connected, yet still reside in one community provide a negative contribution to the overall modularity of the clustering.

A brief discussion of well known clustering methods
---------------------------------------------------

In this section, several common graph clustering methods are briefly studied.

### The fast greedy method

##### 

A typical greedy method for clustering a graph while utilizing Newman’s modularity consists of the following steps.

1.  Start with each vertex in its own community, thus having $n$ communities for $n$ vertices.

2.  In each step, merge two communities whose join makes the highest increase in modularity $Q$.

3.  After $n-1$ joins, one community remains and a dendrogram can be created.

4.  Take the clustered solution that has the highest Q.

##### 

The simple greedy method, can waste a good deal of time when dealing with sparse graphs. In the implementation of the simple greedy approach, one has to merge many columns and rows of the sparse adjacency matrix and consequently time and space is wasted on merging elements with the value of 0. For this reason, Clauset and Newman have presented an enhanced version of the greedy method, namely the fast greedy method [@clauset2004finding] which performs much better than many other algorithms in the literature. In the fast greedy method, some data structures such as max heaps and balanced binary trees are used with some alterations in the algorithm that results in the runtime of $|V||E|log(|V|)$.

### The edge-betweenness based method

##### 

The edge betweenness based method, proposed by Girvan and Newman [@girvan2002community] before presenting the modularity measure, is a graph clustering algorithm that focuses on the edges that are between communities in contrast to many other older algorithms that focus on the connections inside a community. Edge betweenness is described as the number of shortest paths between pairs of vertices that run along it. The algorithm for this method is as follows.

1.  Calculate edge betweeenness for all edges

2.  Remove the edge with the highest betweenness value

3.  Recalculate edge betweenness for the rest of the edges

4.  Repeat step 2 until no edges remain

##### 

Calculating betweenness for all $m$ edges and $n$ vertices of a graph can be calculated using Newman’s algorithm for betweenness [@girvan2002community] which can be calculated in time $O(mn)$. Edge betweenness has to be recalculated for every edge removal and thus the algorithm can work in time $|N||M|^2$.

### The walktrap based method

##### 

The walktrap method is based on the notion of random walks [@pons2005computing]. The main idea behind the walktrap method is that random walks in a graph tend to get trapped in dense parts of the graph which could represent communities. In the walktrap method, a distance $r$ between communities is calculated based on the properties of random walks. After this step, typically an agglomerative algorithm is used to merge communities and create a dendrogram, much like other methods. This algorithm has a runtime of $|E||V|^2$.

### The leading eigenvector based method

##### 

The leading eigenvector algorithm utilizes the eigenvalues of the modularity matrix. In this algorithm one determines the eigenvector corresponding to the most positive eigenvalue of the modularity matrix and divide the network into two groups according to the signs of the elements of this vector.

Community detection for directed graphs
---------------------------------------

##### 

Community detection in directed networks is a difficult task [@malliaros2013clustering]. Various algorithms for community detection in undirected graphs have been presented in the literature, however methods for directed approaches have been less common. A comprehensive survey of community detection methods for directed graphs can be found in [@malliaros2013clustering] by Malliaros et al. They propose the following classification for community detection approaches in directed graph.

1.  **Naive graph transformation approach.** In this method, directions are simply removed from the graph and undirected community detection techniques are applied.

2.  **Transformations maintaining directionality.** In this category of methods, the graph is transformed to an undirected version while directionality is maintained using other methods. The original graph can be tranformed to a unipartite weighted graph or a bipartite graph for this approach. An overview of such transformations is depicted in Fig. \[transformation\].

3.  **Extending objective functions and methodologies in directed graphs.** Many objective functions and quality measures used in undirected graphs can be extended to directed versions, i.e. modularity, spectral clustering, page rank and random walk methods, local density clustering.

4.  **Alternative approaches.** Other methods that can not be placed in the first three categories also exist. Such as information theoretic approaches and blockmodeling approaches.

![An example of a transformation that preserves directionality. []{data-label="transformation"}](transform.png){width=".8\columnwidth"}

##### 

Although some algorithms exist for this purpose, many clustering algorithms for undirected graphs can be extended for directed graphs with the help of a direction-compliant quality measure. Several extensions of modularity for directed graphs have been proposed in the literature. Arenas et al [@arenas2007size] proposed an extension of modularity. Their idea is based on the fact that in a directed graph $G$, if vertex $i$ exists with more out-links and vertex $j$ exists with more in-links, then it is more probable that in a random rewiring a link be found from $i$ to $j$ rather than the opposite. Considering the original idea of modularity, this suggests that if an edge is found from $j$ to $i$, then this edge is contributing to a community structure more than $i$ to $j$ would, simply because it is more suprising and less random. By this definition, modularity can be altered for directed networks by changing the null model to a graph with the same number of vertices, edges, out-links and in-links as the original graph. The equation for modularity $Q$ in a graph with the adjacency matrix $A$ and $m$ number of edges can then be expressed as

$$\label{eq:Modularity_directed}
Q=\frac{1}{m}\sum_{ij}[A_{ij} - \frac{k_i^{out}k_j^{in}}{m}] \delta(C_i, C_j)$$

where $\delta$ is the Kronecker delta function, $C_i$ and $C_j$ denote the communities that nodes $i$ and $j$ belong to, and $k_i^{out}$ and $k_j^{in}$ are the number of vertex $i$ and $j$’s out-links and in-links respectively.

Applications of community detection in software engineering
-----------------------------------------------------------

##### 

Graph clustering is widely used in the literature as a method for finding meaning in a structure. This need for finding meaning in a complex system is generally used in four main areas of software engineering.

### Reflexion

##### 

Reflexion is the art of bridging the gap between software and humans, when it comes to analyzing a legacy system. Reflexion analysis tries to build an understandable high level abstraction of a large system, given the source code. In the process, the source code is analyzed and mapped to a new higher level model. This cumbersome task is typically done manually, however graph clustering can be used in semi automated mappings of source code to entities with the help the user’s knowledge about the system. Some related work has been presented in the literature [@murphy1995software], [@mancoridis1999bunch].

### Refactoring

##### 

There are many properties that can be associated with good code. Sommerville describes good code as one that is highly maintainable, dependable, efficient and usable [@sommerville2004]. Truly reusable code is considered gold in the software industry as it significantly effects productivity and thus lowers costs [@lim1994] and without a doubt, good code is backed by a good design. Refactoring is the art of improving the internal structure of code while leaving the outer side intact [@fowler1999]. One of the problems that has been tackled in the literature is refactoring large and complicated legacy systems and also analyzing the structure of new code. Graph clustering techniques can be considered a good method for finding the correct structure and packages of a large system by analyzing the relationships in a software’s dependency graph. Some work has been done in the area of refactoring at the class level, using graph clustering algorithms [@pan2009class]. Recently, some work has also been presented in the package level [@pan2013refactoring], however the lack of an accurate package analysis tool that considers important object oriented aspects, such as stability and reusability is strongly felt in the literature.

### Parallel computing

##### 

Task to processor mappings is considered an important problem in parallel environments. The two general strategies used in such problems is placing tasks that can run concurrently on different processors, while keeping tasks that need many communications on the same processors, in order to increase locality. Graph partitioning tools have been used in some cases to map tasks to hypercube structures [@sadayappan1990cluster].

### Ontologies and concept grouping

##### 

One of the areas that highly utilizes graph clustering methods is ontologies and the semantic web. Various applications have been presented in the literature. One important application is extracting new concepts and taxonomies from ontologies. Extracting more generalized concepts and relations is one of the outputs of an ontology clustering. Tang et al. presents a great survey on such methods [@tang2012survey]. Modularization is also considered important for the problem of ever growing and over grown ontologies. The works in [@ghafourian2013modularization] is one of the most recent methods in this specific area.

Partition stability
-------------------

##### 

In some works the notion of partition stability, also known as robustness is considered as an important property of a good clustering algorithm. The idea is that a stable partition is one that can be recovered even if the structure of the graph is modified, as long as the change in the graph is not too extensive. It important to stress that this thesis only studies stability in the software package sense of the word and does not cover cluster stability.

Refactoring packages using community detection
==============================================

##### 

Several studies have attempted to use community detection methods or cluster analysis in order to find refactoring opportunities [@pan2009class], [@pan2013refactoring], [@melton2006identifying]. These methods have analyzed the code in three main levels.

-   Method level

-   Class level

-   Package level

##### 

This thesis focuses on refactoring at the package level for which there has been little discussions in the literature. Pan et al. [@pan2013refactoring] proposes a novel method for refactoring using the notion of modularity, however neglects the use of a directed clustering approach. In this chapter, the importance of a directed graph model is discussed with regard to the notion of package stability and an improved version of a package refactoring method using community detection is presented.

Basics of modeling packages with graphs
---------------------------------------

##### 

As discussed in previous chapters, many metrics have been proposed for different software properties at the class level. At the package level, which is in a higher level in the abstraction hierarchy compared to a class, the most important property in the literature is the dependency between two packages. When a class inside a package depends on a class from another package, the former package is said to depend on the latter.

##### 

Let $G$ be a graph with the adjacency matrix $A$. Vertices in $G$ represent classes and edge $E_{ij}$ between vertex $i$ and vertex $j$ resembles a dependency between the two classes. Communities in this graph represent package structure. A dependency between two classes can be any usage of methods or variables or inheritance. Classes are being modeled to graph vertices for the sole purpose of using community detection methods for finding appropriate clusters which represent packages and different relationships between classes are not considered different.

##### 

A thorough metric for package dependencies has been proposed in [@gupta2009package] by Gupta et al, which takes into account the different types of connections between packages when sub-packages also exist in the software. The metric is validated using Briand’s evaluation criteria [@briand1996property]. Gupta et al consider two classes of two packages connected if any of the following relationships are found between them.

-   Aggregation relationships between two classes, i.e., one class’s attribute has the type of another class

-   Class inheritence or implementing interfaces

-   Method invocation of one class by the method of another class

-   A class’s method referencing an attribute from another class

-   A class’s method has a parameter of the type of another class

-   A class’s method has a local variable of the type of another class

-   A class’s method invoking a method having a parameter of the type of another class

##### 

By Gupta et al’s metric, coupling between two packages $p_a^i$ and $p_b^i$, where $i$ denotes the hierarchical level, is expressed as

$$\begin{aligned}
\label{eq:coup}
Coup(p_a^i, p_b^i) &=& \left\{\begin{matrix}
 0, & (n=0, m=0)\\ 
 \sum_{x=1}{n}\sum_{y=1}^{m}r(e_x^{i+1}, e_y^{i+1}) \\ 
 + \sum_{y=1}^{m}\sum_{x=1}^{n} r(e_y^{i+1}, e_x^{i+1}), & (n \geq 1 \wedge m \geq 1)
\end{matrix}\right.\end{aligned}$$

where $n$ and $m$ are the number of elements of package $p_a^i$ and $p_b^i$ respectively at hierarchy level $i+1$, and $r$ is the binary connection between elements. An example of different hierarchical levels given in [@gupta2009package] is depicted in Fig. \[hierarchy\_levels\]. The binary connection between elements ($r$) can be calculated as

$$\begin{aligned}
\label{eq:r_gupta}
r(e_x^{i+1}, e_y^{i+1}) &=& \left\{\begin{matrix}
1, & e_x^{i+1} \rightarrow e_y^{i+1};\\ 
0, & otherwise;
\end{matrix}\right.\end{aligned}$$

where $e_x^{i+1} \rightarrow e_y^{i+1}$ denotes that element $x$ depends on element $y$.

![An example of different hierarchical levels[]{data-label="hierarchy_levels"}](hierarchy_levels.png){width=".5\columnwidth"}

Basics of refactoring with community detection
----------------------------------------------

##### 

The use of community detection methods for refactoring packages has only recently been studied in the literature by Pan et al [@pan2013refactoring]. An overview of their method is as follows.

1.  Gather software information and dependencies from Java classes and jar files.

2.  Construct an undirected weighted dependency network based on the information gathered in the first step.

3.  Apply community detection to the dependency network to find the optimal placement of classes in packages.

4.  Compare the optimized clustering with the original packages structure of the code and suggest a list of possible refactoring candidates.

##### 

In the first step of their algorithm Pan et al take into account two types of dependencies between code attributes, method accessing attribute dependency and method call dependency. Any of the two mentioned dependencies between two classes implies a dependency between the two classes.

##### 

Pan et al model package structure with the help of two different networks, namely the undirected Feature Dependency Network (uFDN) and the undirected Weighted Class Dependency Network (uWCDN). Nodes in uFDN represent features inside the software and edges represent dependencies between features. By this definition, uFDN can be expressed as

$$\label{eq:ufdn}
uFDN = (V_f, E_f, W_f)$$

where $V_f$ and $E_f$ represent the set of vertices and edges in uFDN respectively and $W_f$ is the adjacency matrix for the network. The subscript $f$ shows that the two sets and the adjacency matrix are at the feature level. An example of a uFDN presented in [@pan2013refactoring], consisting of two communities, is shown in Fig. \[ufdn\].

![A sample uFDN[]{data-label="ufdn"}](ufdn.png){width=".7\columnwidth"}

The code resembeling the network in \[ufdn\] is given below.

``` {language="java"}
public class X
{
    private int a;
    public void c() {}
    public void b() {c();}
    public void d() {a++; b(); c();}
}
public class Y
{
    public void f()
    {
        X x = new X();
        x.c();          
    }
    public void e() {f();}
}
```

##### 

In uWCDN, only the relationship among the classes are shown. A weight is used for every class dependency that represents the number of connections between the the attributes and methods of the two classes involved in the relationship. uWCDN can be defined as

$$\label{eq:uwcdn}
uWCDN = (V_c, E_c, W_c)$$

where $V_c$ denotes the set of all vertices at the class level, $E_c$ denotes the set of all edges and $W_c$ is the weighted adjacency matrix of the network. Every entry in $W_c$ can be shown as $w_c(i, j)$ which is the weight between the two elements $i$ and $j$ and is used to denote the strength of a dependency between nodes $i$ and $j$. This weight can be calculated as

$$\label{eq:uwcdn_weights}
w_c(i, j) = |\bigcup_{n_i\in F_i}R_{i1} \cap F_j|$$

##### 

The difference between uFDN and uWCDN is shown in Fig. \[ufdn\_uwcdn\].

![A sample uWCDN compared to its respective uFDN[]{data-label="ufdn_uwcdn"}](ufdn_uwcdn.png){width="0.6\columnwidth"}

where $R_{ik}$ denotes the set of all nodes reachable from $i$ within a distance of $k$ and $Fi$ is the set of all the features of class $i$. It is important to note that $w_c(i, j)$ is equal to $w_c(j, i)$.

##### 

The community detection algorithm used by Pan et al utilizes an older definition of modularity [@newman2004fast].

The importance of directed graphs in modeling package relationships
-------------------------------------------------------------------

##### 

Many studies in the literature have utilized undirected community detection methods for various applications. Fortunato [@fortunato2010community] presents a comprehensive review on undirected community detection methods. Many studies that include a directed model of a problem simply discard the information that the directions in the graph provides, and use a naive graph transformation approach. In the naive tranformation approach, graph directions are simply discarded and normal undirected community detection methods are applied to the graph. This can cause many important information to be discarded. We briefly discuss three main problems that an undirected approach can cause and how it effects refactoring and package stability.

### Citation based cluster models

##### 

Using naive transformation approaches for undirected community detection, introduces inaccuracy in certain graphs such as the citation based model that is depicted in Fig. \[citation\_graph\]. In this graph, the two middle vertices can clearly form a meaningful community. The two vertices have in-links from the the same set of vertices while the vertices that they have out-links to are also the same. In the package sense, the middle community resembles a package that is more stable than the package containing the vertices from the left. Many utility packages and libraries contain packages with a similar structure. There is little or no connection between the vertices inside the package, yet they belong to the same community as they are used in similar situations.

![Citation based cluster[]{data-label="citation_graph"}](citation.png){width="0.2\columnwidth"}

##### 

After applying naive transformation and trying to find optimal communities in the graph in Fig. \[citation\_graph\], the output simply looses the intended community structure. The output is given in Fig. \[citation\_modular\]. Black vertices have been put into one community by the algorithm and white vertices have been placed in another community. In this clustering, it is clear that SDP (Stable Dependencies Principle) is violated and both communities depend on each other. Using a community detection algorithm intended for undirected graphs has changed the SDP compliant structure that the programmer had intended.

![Citation based cluster after naive transformation[]{data-label="citation_modular"}](citation_modular.png)

### Bidirected graphs and loss of information

##### 

As discussed in [@malliaros2013clustering], the information needed for correct community detection is simply lost in certain graphs such as the bidirected graph shown in Fig. \[bidirected\_graph\].

![An example of a bidirected graph with two communities[]{data-label="bidirected_graph"}](bidirected.eps)

![An example of a bidirected graph after naive transformation[]{data-label="bidirected_no_direction"}](bidirected_no_direction.eps)

From a stability perspective, the dependency graph in Fig. \[bidirected\_graph\] shows a two packages that fully conform to SDP. The community created by the four vertices on the right represent a very stable package that the left community is depending upon. By performing naive transformation the graph would look like Fig. \[bidirected\_no\_direction\]. This graph has lost its community structure and the two left most vertices and the two right most vertices will be treated in the same way when it is given to a community detection method. Fig. \[bidirected\_no\_direction\_modular\] shows this graph after applying community detection while optimizing Newman’s modularity.

![A clustered version of the graph in Fig \[bidirected\_no\_direction\][]{data-label="bidirected_no_direction_modular"}](bidirected_no_direction_modular.eps)

Stability and modularity
------------------------

In this section, the relationship between the directed version of modularity and the Stability Dependencies Principle (SDP) in refactoring packages is discussed. In a scenrio where a class is chosen to be moved from one package to another using community detection methods, we show that modularity is in favor of SDP and hiding dependencies that violate SDP inside packages has a higher contribution to modularity than hiding non-violating dependencies. To show this behavior, some prior definitions are needed.

A movement of class $i$ from package $p_1$ to package $p_2$ is shown as the tuple $(i, p_1, p_2)$.

A border node in a package is defined as a node that has connections with nodes in other packages and thus directly effects the package’s instability metric.

##### 

SDP is generally satisfied in a case where no stable package depends on an unstable package. When considering the movement of only two border classes, while all other classes and packages are left intact, then the only dependencies effecting the two package’s instability metric are the dependencies of the two border nodes. If a border node $i$ from stable package $p_1$ depends on a node $j$ from unstable package $p_2$, then clearly SDP is violated.

\[sdp\_satisfaction\] Let $k_i^{out}$ and $k_j^{out}$ be the out-link degree of vertices $i$ and $j$ respectively, and $k_i^{in}$ and $k_j^{in}$ be the in-link degree of vertices $i$ and $j$. If $k_i^{out} > k_i^{in}$ and $k_j^{out} < k_j^{in}$ and node $i$ and node $j$ are border nodes, then SDP is satisfied.

\[sdp\_dissatisfaction\] Let $k_i^{out}$ and $k_j^{out}$ be the out-link degree of vertices $i$ and $j$ respectively, and $k_i^{in}$ and $k_j^{in}$ be the in-link degree of vertices $i$ and $j$. If $k_i^{out} < k_i^{in}$ and $k_j^{out} > k_j^{in}$ and node $i$ and node $j$ are border nodes, then SDP is not satisfied.

\[prop:sdp\_mod\] Let $i$ and $j$ be two classes in dependency graph $G$. If a movement $(i, c_i, c_j)$ exists and the conditions of remark \[sdp\_satisfaction\] holds, then the increase in modularity $Q$ is more, compared to the situation in which the conditions of remark \[sdp\_dissatisfaction\] holds true.

Let $Q$ denote modularity while the conditions in remark \[sdp\_satisfaction\] holds true and $\bar{Q}$ denote modularity while the conditions in remark \[sdp\_dissatisfaction\] holds true. $Q$ and $\bar{Q}$ can be calculated using Eq. \[eq:Modularity\_directed\] as

$$\begin{aligned}
Q&=&\frac{1}{m}\sum_{ij}[A_{ij} - \frac{k_i^{out}k_j^{in}}{m}] \delta(C_i, C_j), \\
\bar{Q}&=&\frac{1}{m}\sum_{ij}[A_{ij} - \frac{\bar{k}_i^{out}\bar{k}_j^{in}}{m}] \delta(C_i, C_j).\end{aligned}$$

The bar on in-link or out-link $k$ denotes that it is being calculated in the scenario of remark \[sdp\_dissatisfaction\], and is therefore equivelant to the out-link and in-link in the scenario of remark \[sdp\_satisfaction\] respectively. Thus one can write

$$\begin{aligned}
\label{eq:kij_bar_relation}
\bar{k}_i^{out} &=& k_j^{out} \\
\bar{k}_j^{in} &=& k_i^{in}.\end{aligned}$$

By looking at the conditions of remark \[sdp\_satisfaction\] and remark \[sdp\_dissatisfaction\] it is clear that

$$\begin{aligned}
\label{eq:kij_bar_relation2}
\bar{k}_i^{out}\bar{k}_j^{in} &<& k_i^{out}k_j^{in} \\
\frac{\bar{k}_i^{out}\bar{k}_j^{in}}{m} &<& \frac{k_i^{out}k_j^{in}}{m} \\
A_{ij} - \frac{\bar{k}_i^{out}\bar{k}_j^{in}}{m} &>& A_{ij} - \frac{k_i^{out}k_j^{in}}{m} \\
\bar{Q} &>& Q.\end{aligned}$$

##### 

The above proposition shows how modularity is compatible with the notion of SDP. Modularity is in favor of non-random structure in a network. Violating SDP would mean that a stable package is depending on an unstable package. In this scenario, the above proof shows that keeping two nodes that have violated SDP before, inside a single package is better for $Q$ than keeping two nodes that did not violate SDP. It is also important to note that if $i$ and $j$ belong to two different packages, then the condition will have no contribution to modularity and therefore is not discussed.

##### 

As an example for the proved proposition, suppose that a system contains two packages $C_1$ and $C_2$, where $C_1$ is unstable and $C_2$ is a stable package. Two slighly different versions of this system is depicted in Fig. \[example1\]. In both of these versions, vertices 1, 2, 3 and 4 are members of $C_2$ and vertices 5, 6, 7 and 8 belong to $C_1$. It is clear that in condition (b), edge $(1,5)$ is violating SDP. Based on Proposition \[prop:sdp\_mod\], we show that moving node 1 from $C_2$ to $C_1$ has more positive contribution for package modularity, than in the case of condition (a). If movement $(1, C_2, C_1)$ happens, then four new edges positively contribute to the overall modularity of the dependency graph while one edge’s contribution is eliminated. The reason for this is that edges between two communities provide no contribution to modularity because the kronecker delta function in Eq. \[eq:Modularity\_directed\] becomes zero. therefore edges $(5, 1)$, $(6, 1)$, $(7, 1)$ and $(8, 1)$ will have new contributions to modularity and edge $(1, 3)$ will no longer have any contribution. The changes in modularity $Q$ for condition (b) can be calculated using Eq. \[eq:Modularity\_directed\] as

$$\begin{aligned}
\label{eq:example1}
\Delta Q &=& \overbrace{4(1 - \frac{1 \times 1}{2m})}^{\mathclap{\text{Contribution of the 4 new edges}}} - \underbrace{(1 - \frac{1 \times 1}{2m})}_{\mathclap{\text{Contribution of edge }(1, 3)}} = 3(1 - \frac{1 \times 1}{2m}).\end{aligned}$$

##### 

By replacing $m$ with the number of edges, we have

$$\begin{aligned}
\label{eq:example1b}
\Delta Q &=& \frac{57}{20} = 2.85.\end{aligned}$$

##### 

Changes in modularity for condition (a) can be calculated the same way as follows.

$$\begin{aligned}
\label{eq:example1c}
\Delta Q &=& \overbrace{(1 - \frac{4 \times 4}{2m})}^{\mathclap{\text{Contribution of edge }(5, 1)}} + 3(1-\frac{1 \times 4}{2m}) - (1 - \frac{1 \times 1}{2m}) = \frac{33}{20} = 1.65.\end{aligned}$$

##### 

The results clearly indicate that the graph gained more modularity when trying to suppress an SDP violation than when it is not.

![Two different graph dependency conditions.[]{data-label="example1"}](example1.eps)

Proposed refactoring method
---------------------------

##### 

By considering the discussed importance of directed graphs in refactoring software packages and the package coupling metric proposed by [@gupta2009package], we present a package refactoring algorithm.

##### 

For calculating the dependencies, we use the package coupling metric provided by Gupta et al [@gupta2009package] at hierarchy level $i+1$. This is a crucial point that must be noted. Hierarchy level $i+1$ is being used because it gives access to elements inside packages at level $i$. The classes and sub-pakages in this level of hierarchy are the ones that will be analyzed for possible refactorings. In this study, only one package level is analyzed for refactoring, as deeper levels cause many open problems that need to be tackled. The most basic problem with optimizing software metrics such as coupling and cohesion in many levels of abstractness simultaneously is that cohesion inside one level can be considered as coupling in a deeper level, thus the problem of minimizing coupling contradicts with the problem of maximizing cohesion in a higher level of abstractness, i.e., the package level $i$. therefore, in this work, only packages at level $i$ and their respective elements at level $i+1$ are considered.

##### 

For calculating the package dependency graph’s modularity, we use the directed and weighted version of modularity [@arenas2007size] expressed as

$$\begin{aligned}
\label{eq:directed_weighted_mod}
Q&=&\frac{1}{2w}\sum_{ij}[w_{ij} - \frac{w_i^{out}w_j^{in}}{2w}] \delta(C_i, C_j). \\\end{aligned}$$

where $w_i^{out}$ and $w_j^{in}$ are respectively the output and input weights of nodes $i$ and $j$ and

$$\begin{aligned}
\label{eq:wiout}
w_i^{out} &=& \sum_{j}w_{ij} \\
w_j^{in} &=& \sum_{i}w_{ij} \\
2w &=& \sum_{i} w_i^{out} = \sum_{j} w_j^{in} = \sum_{i} \sum_{j} w_{ij}.\end{aligned}$$

The weights for an edge is equal to the edge’s coupling metric given in Eq. \[eq:r\_gupta\]. These weights are used in the package dependency network, similar to the weights in uWCDN (Eq. \[eq:uwcdn\]) provided by Pan et al [@pan2013refactoring]. Considering the directedness of the network we can define an enhanced version of uWCDN, namely DWPDN (Directed, Weighted Package Dependency Network) that can be expressed as

$$\label{eq:dwpdn}
DWPDN = (V_{i+1}, E_{i+1}, W_{i+1})$$

where $V_{i+1}$ denotes the set of all vertices at hierarchy level $i+1$, $E_{i+1}$ denotes the set of all edges at hierarchy level $i+1$ and $W_{i+1}$ is the assymetric and weighted adjacency matrix of the network at hierarchy level $i+1$. Every element of $W_{i+1}$ can calculated as

$$\label{eq:dwpdn_weights}
w_{i+1}(j, k) = Coup(p_j^{i+1}, p_k^{i+1})$$

where $j$ and $k$ are two elements and $Coup$ is the coupling function from Eq. \[eq:coup\].

##### 

The main phases of the proposed package refactoring algorithm are presented in Alg. \[alg:proposed\_refactoring\].

**Input:** A DWPDN\
**Output:** A list of package movement suggestions and the optimal $Q$ that can be gained

$suggestedMovements \gets \varnothing$ $Q' \gets -1$ $Q \gets \text{modularity based on Eq. \ref{eq:directed_weighted_mod}}$ $selectedCommunity \gets 0$ $C_i \gets $ node $i$’s community $C_j \gets $ node $j$’s community $tempQ \gets \text{modularity, while considering node } i \text{ in }C_j$ $Q' \gets tempQ$ $selectedCommunity \gets C_j$ Add movement $(i, C_i, selectedCommunity)$ to suggestedMovements Move node $i$ to $selectedCommunity$ $Q \gets Q'$ $i \gets 1$ **return** $Q'$ and $suggestedMovements$

Evaluation
==========

##### 

This chapter evaluates the proposed algorithm with two case studies using our implemented package refactoring tool. The two subjects which the algorithm was applied on are the same open source subjects used in [@pan2013refactoring]. In the remaining sections of this chapter, the two subjects are briefly introduced and analyzed by the implemented tool. The proposed refactoring algorithm is applied on the two subjects and the results are evaluated. For simplicity, the first version of the implemented tool does not apply weights and considers all weights between classes to be one.

Subjects
--------

##### 

The two subjects being analyzed in this chapter are the same as the subjects in [@pan2013refactoring], namely Trama[^3] and FrontEndForMySQL[^4].

##### 

Trama is a graphical tool for manipulating and working with matrices. FrontEndForMySQL is a graphical front end for the MySQL database system and provides an easier and more user friendly environment for working with MySQL queries. Some details of the two subjects are shown in Table \[subjects\].

  **System**         Version   Number of packages   Number of classes   
  ------------------ --------- -------------------- ------------------- --
  Trama              1.0       6                    58                  
  FrontEndForMySQL   1.0       10                   56                  

  : Details of the systems analyzed[]{data-label="subjects"}

##### 

The original packaging structure for Trama is depicted in Fig. \[original\_trama\]. The original modularity calculated for the default packaging of Trama is calculated as 0.28 and the list of its packages is as follows.

-   visao

-   visao.renderizador

-   persistencia

-   negocio

-   negocio.leitor.Interface

-   negocio.leitor

![Original packaging structure of Trama[]{data-label="original_trama"}](trama_original.png)

##### 

FrontEndForMySQL is a larger system compared to Trama, with an initial package modularity of 0.21. The system’s default packaging structure is depicted in Fig. \[front\_original\] and it contains the following packages.

-   frontendformysql

-   frontendformysql.domain.BackEnd

-   frontendformysql.domain.BackEndData

-   frontendformysql.domain.BackEndComponent.Editor

-   frontendformysql.domain.BackEndInterfaces

-   frontendformysql.domain.BackEnd.System

-   frontendformysql.domain.BackEndComponent.DriverModule

-   frontendformysql.domain.BackEndData

-   frontendformysql.domain.BackEndComponent.XMLutil

-   frontendformysql.domain.BackEndComponent.IO

-   frontendformysql.domain.BackEndComponent.DataStructures

-   frontendformysql.domain.BackEndComponent.Editor

-   frontendformysql.domain.BackEndInterfaces

-   frontendformysql.domain.BackEnd.System

-   frontendformysql.domain.BackEndComponent.DriverModule

-   frontendformysql.domain.BackEndComponent.XMLutil

-   frontendformysql.domain.BackEndComponent.IO

-   frontendformysql.domain.BackEndComponent.DataStructure

![Original packaging structure of FrontEndForMySQL[]{data-label="front_original"}](trama_original.png)

Case studies and results
------------------------

##### 

After applying the proposed refactoring algorithm, with considering the importance of edge directions, the clustering of Trama changes to the depicted structure in Fig. \[refactor\_trama\] and the suggested movements are given in Table \[trama\_suggestions\]. The new packaging of Trama has a directed modularity of 0.43 and shows an improvement over the original 0.28. It is important to note that not all movements are acceptable and the suggestions should be given to a programmer for final analysis.

  **Order**   **Class name**         **Old package**   **Suggested package**   
  ----------- ---------------------- ----------------- ----------------------- --
  1           Main                   negocio           visao                   
  2           Matriz                 negocio           persistencia            
  3           ModeloTabela           visao             persistencia            
  4           JTableCustomizado      visao             visao.renderizador      
  5           JTableCustomizado\$1   visao             visao.renderizador      
  6           JTableCustomizado\$2   visao             visao.renderizador      
  7           LeitorDeModelo         negocio.leitor    negocio                 
  8           Tela\$23               visao             persistencia            
  9           Tela\$22               visao             persistencia            
  10          Tela\$24               visao             visao.renderizador      
  11          Tela\$3\$1             visao             visao.renderizador      

  : Suggested movements for Trama classes[]{data-label="trama_suggestions"}

![New packaging of the Trama system after refactoring[]{data-label="refactor_trama"}](trama_directed.png)

##### 

As a comparison, an undirected version of the algorithm, using naive transformation, was applied on the Trama system. The produced clustering is shown in Fig. \[trama\_undirected\]. In this clustering, modularity gets a value of 0.41. It is important to note that comparing the modularity of the two approaches would not be correct, as the formula for the two quality measures are inherently different. However, a comparison on package instability is shown in Table \[trama\_instability\_comparison\], in which $OI$ is the original instability of a package, $DI$ is the instability of a package after the proposed refactoring algorithm with edge directions, is applied and $UI$ is the instability of a package after applying the undirected version of the algorithm.

![New packaging of the Trama system after refactoring with naive transformation[]{data-label="trama_undirected"}](trama_undirected.png)

  **Package name**            **OI**   **DI**   **UI**   
  --------------------------- -------- -------- -------- --
  negocio                     0.478    0.529    0.6      
  persistencia                0        0.368    0.409    
  visao.renderizador          0.428    0.538    0        
  negocio.leitor              0        0        0        
  visao                       0.64     0.578    0.5      
  negacio.leitor.Intergface   0        0        0        

  : Comparison of Trama’s instability metric for different approaches[]{data-label="trama_instability_comparison"}

##### 

Table \[trama\_instability\_comparison\] shows how two packages became more stable after applying the proposed, directed clustering algorithm, while the stability of package *visao* decreased by 0.078. From Fig. \[trama\_undirected\], it is also clear that the *visao.renderizador* is merged with other packages and thus is not taken into account for comparison.

##### 

The implementation of the proposed algorithms was also applied to the FrontEndForMySQL system. The original package structure for FrontEndForMySQL and its structure after refactoring are depicted in Fig. \[original\_frontendformysql\] and Fig. \[refactor\_frontendformysql\] respectively. The original modularity for FrontEndForMySQL is calculated as 0.21.

![Original packaging of the FrontEndForMySQL system[]{data-label="original_frontendformysql"}](front_original.png)

![New packaging of the FrontEndForMySQL system after refactoring[]{data-label="refactor_frontendformysql"}](front_directed.png)

##### 

Similar to the previous case study, an undirected version of the algorithm, using a naive transformation for removing edge directions was applied to FrontEndForMySQL and the clustering result is depicted in Fig. \[front\_undirected\]. The comparison table for this package instability measures is given in Table \[front\_instability\_comparison\].

![New packaging of the FrontEndForMySQL system after refactoring with naive transformation[]{data-label="front_undirected"}](front_undirected.png)

  **Package name**                  **OI**   **DI**   **UI**   
  --------------------------------- -------- -------- -------- --
  BackEndInterfaces                 0        0        0.375    
  BackEnd                           0.969    1        0.714    
  BackEnd.System                    0.2      0        0        
  BackEndComponent.IO               0        0.2      0        
  BackEndComponent.XMLutil          0        0        0        
  BackEndComponent.Editor           0        0        0        
  BackEndComponent.DriverModule     0.818    0.25     0.25     
  BackEndComponent.DataStructures   0        0        0        
  frontendformysql                  0.666    0        0.6      
  BackEndData                       0.238    0.125    0.5      

  : Comparison of FrontEndForMySQL’s instability metric for different approaches[]{data-label="front_instability_comparison"}

##### 

Table \[front\_instability\_comparison\] clearly shows that the overall instability of packages is higher when edge directions are not taken into account in the refactoring algorithm.

Live analysis of graph clusters
===============================

##### 

Considering the vast number of graph clustering applications in software engineering, a need for a tool that can import different graph modeled structures, perform graph clustering algorithms and provide a rich client for tweaking the properties of the model, is clearly felt. This need has motivated us to create a tool, namely Picasso, with such capabilities. Fig. \[picasso\_overview\] shows an overall view of this tool while analyzing a software package. Colors are used to show the different communities inside the graph. The server-side and client-side codes of this tool are given in Appendices A and B respectively.

Picasso overview
----------------

![Picasso: A tool for live package dependendy analysis[]{data-label="picasso_overview"}](picasso_overview.png)

##### 

Picasso applies the proposed refactoring algorithm on software packages and provides a list of class moving suggestions. An example of the suggestions that Picasso presents is depicted in Fig. \[picasso\_suggestions\]. Every suggestion is a class movement from a source package to a target package.

![An example of some suggestions provided by Picasso[]{data-label="picasso_suggestions"}](picasso_suggestions.png)

##### 

Picasso provides many extra features that are as follows.

-   Import Java jar files and class files.

-   Import UML structures.

-   Provides an option to choose famous graphs such as the Zachary club network.

-   Calculates modularity and provides a refactored solution for a software system using Alg. \[alg:proposed\_refactoring\].

-   Calculates Martin’s instability metric for software packages.

-   Hierarchically provides cluster graphs of a graph.

-   Provides an extendible messaging system for future works.

-   Provides an edited version of JSNetworkX’s force layout graph visualization algorithm.

-   Provides functions for adding and removing graph edges and nodes.

-   Provides the ability to lock graph nodes in one position for better viewing.

##### 

Picasso’s top menu provides the main functionalities of the tool. The menu bar is depicted in Fig. \[picasso\_menu\] and shows that the tool is in working mode and awaits a response from the Picasso server. The gray section of the top bar shows some information such as the modularity measure of the current clustering and the name of the current selected class in the dependency graph. The top buttons consist of two main groups. The left, green buttons provide directed refactoring, undirected refactoring and the original clustering of the software system being analyzed. The right, blue buttons provide the options for viewing the graph’s clustering graph, viewing the movement suggestions after refactoring and viewing instability measures for different packages. An example of the instability measure window is shown in Fig. \[picasso\_inst\].

![Picasso’s top menu bar[]{data-label="picasso_menu"}](features_bar.png)

![An example of Picasso’s instabilities window[]{data-label="picasso_inst"}](picasso_inst.png)

![Picasso’s sequence diagram[]{data-label="seq_diagram"}](seq.eps)

Picasso’s 3rd party dependencies
--------------------------------

##### 

Picasso utilizes many diverse 3rd party libraries. Some of these libraries have been customized and tweaked specially for Picasso. The following list contains some brief information on these libraries.

-   **Coffea[^5] java analysis tool.** Coffea is an open source static code analyzer for Java byte code that can export package dependency graphs in various graph file formats. Coffea is written in Python and therefore can be integrated well with Picasso.

-   **D3[^6] visualization library.** D3 stands for Data-Driven Documents, and is arguably one of the best Javascript data visualization tools that utilizes HTML5, SVG (Scalable Vector Graphics), CSS3 and Javascript capabilities and provides an extremely flexible platform for data visualization.

-   **JSNetworkX[^7] network visualization library.** This library is a port of the popular NetworkX Python graph library and is build upon the D3 platform.

-   **Python’s igraph[^8] library.** Python’s igraph library is used in Picasso for creating and manipulating graphs on the server side.

-   **Python’s Socks-js[^9] library.** The Socks-JS library is used by Picasso for creating a web socket messaging system that can pass graph and graph cluster information between the server and client sides of the program.

##### 

The sequence diagram in Fig. \[seq\_diagram\] shows how Picasso interacts with these dependencies.

Conclusion and future works
===========================

##### 

The fast expansion of software systems and their complexities, makes large software projects difficult to maintain, and their components hard to reuse. The focus of this work is to use the benefits of graph clustering algorithms and present a refactoring technique for software packages while considering several important software metrics such as coupling, cohesion and stability.

##### 

This work presents a proposition and proof that the cluster quality metric provided by Newman [@newman2004finding] is in favor of Martin’s Stable Dependencies Principle [@martin2003agile] and provides examples that show how directed graphs are important when a system is being modeled with dependency graphs.

##### 

For evaluating our proposed algorithm and to test it in a real life scenario, we implemented a tool, namely Picasso for refactoring software packages and visualizing their directed dependency graphs. The provides tool takes a software system written in the Java language and gives a list of suggested movements for classes.

##### 

Some ideas are presented in the following sections as future works. These possible works are divided into two main categories; refactoring and tool improvements.

Refactoring
-----------

##### 

The refactoring method presented in this work utilizes a directed and weighted version of Newman’s modularity. This requires modularity to be calculated in every step of the proposed algorithm and thus performs slower than the algorithm of Pan et al [@pan2013refactoring]. This may be considered as one of the problems that can be tackled in future works. Also, some rare problems have been found with the directed version of modularity [@malliaros2013clustering] and alternative approaches should also be considered, i.e. random walk based mathods such as LinkRank.

##### 

The importance of directed dependency graphs can also be analyzed in the class level, while using an appropriate metric for class couplings and cohesion.

Tool improvements
-----------------

##### 

Some improvements can be applied on the tool proposed in this work. Currently a force directed layout is used for visualizing graphs. A force directed layouts simulate physical forces between nodes and edges to aesthetically draw a graph. Spring like attractive forces that are based on Hooke’s law are typically used. The force directed layout can be enhanced with collision detection algorithms, so that nodes that are members of the same community can be grouped together instead of being mixed in with nodes from other communities. Also several problems with force directed layouts in large graphs have been pointed out in the literature [@yakovlev2009cluster] and radial tree layouts have been proposed as alternatives. Radial tree layouts can be considered in future implementations of the tool. An example of a radial tree layout from a tool named Barrio, provided in [@yakovlev2009cluster] is depicted in Fig. \[radial\_tree\].

![An example of a radial tree layout[]{data-label="radial_tree"}](radial_tree.png)

##### 

Being able to force a node to be a member of a certain community while calculating the resulting modularity of the graph cluster can be considered as one of the important options in future versions of the application. Some library classes might need to be kept in their original package even though modularity is decreased by doing so.

Server side code for Picasso
============================

``` {language="python"}
# -*- coding: utf-8 -*-
"""
Picasso, ver 0.1
Author: Mohammad A.Raji
Depends on:
    -sockjs-tornado for the asynchronus python server
    -D3.js for visualizing graphs
    -JSNetworkX for visualizing graphs
    -igraph for community detection algorithms
    -Coffea for extracting java dependencies
"""
from __future__ import division
import os
import tornado.ioloop
import tornado.web
import sockjs.tornado
import igraph
import time
import json
import hashlib
from igraph import *

# Request handles class for the index page
class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('picasso.html')

# Connection class: responsible for all the client/server connections
class Connection(sockjs.tornado.SockJSConnection):
    participants = set()

    def on_open(self, info):
        # Add client to the clients list
        self.participants.add(self)
        if len(sys.argv) > 1:
            if len(sys.argv) > 2:
                if sys.argv[1] == "--famous":
                    g = Graph.Famous(sys.argv[2])
                    #g.to_undirected()
                    self.broadcast(self.participants, "graph/" + refactoring.graphToString())
            else:
                refactoring.parseCode(sys.argv[1]);
                self.broadcast(self.participants, "graph/" + refactoring.graphToString())
                self.broadcast(self.participants, "labels/" + refactoring.getVertexLabels())

    def on_message(self, message):
        # Take appropriate action when a message arrives from the client
        self.parseAndApplyMessage(message)

    def on_close(self):
        # Remove client from the clients list and broadcast leave message
        self.participants.remove(self)

    def parseAndApplyMessage(self, msg):
        global refactoring
        message = msg.split("/")
        command = message[0]
        if (len(message) > 1):
            argument = message[1];

            if command == "clusters":
                refactoring.parseGraph(argument)
                refactoring = Refactoring(refactoring.detectCommunities().cluster_graph())
                self.broadcast(self.participants, "graph/" + refactoring.graphToString())
            elif command in ["addnode", "removenode", "addedge", "removeedge"]:
                refactoring.parseChange(command, argument)
            elif command == "getoriginal":
                self.broadcast(self.participants, "membership/" + str(refactoring.original_membership).strip("[]"))
                self.broadcast(self.participants, "measures/" + Refactoring.formatMeasures(refactoring.original_modularity));
                self.broadcast(self.participants, "instability/" + Refactoring.formatInstability(refactoring.original_package_instability));
            elif command == "refactor":
                refactored_results = refactoring.refactor()
                go_membership = refactored_results[1]
                self.broadcast(self.participants, "membership/" + str(go_membership).strip("[]"))
                self.broadcast(self.participants, "measures/" + Refactoring.formatMeasures(refactored_results[0]));
                self.broadcast(self.participants, "suggestions/" + Refactoring.formatSuggestions(refactored_results[2]));
                self.broadcast(self.participants, "instability/" + Refactoring.formatInstability(refactoring.getInstabilityForEachPackage(refactoring.g, go_membership, refactoring.packages)));
            elif command == "urefactor":
                    refactored_results = refactoring.refactor(False)
                    go_membership = refactored_results[1]
                    self.broadcast(self.participants, "membership/" + str(go_membership).strip("[]"))
                    self.broadcast(self.participants, "measures/" + Refactoring.formatMeasures(refactored_results[0]));
                    self.broadcast(self.participants, "suggestions/" + Refactoring.formatSuggestions(refactored_results[2]));
                    self.broadcast(self.participants, "instability/" + Refactoring.formatInstability(refactoring.getInstabilityForEachPackage(refactoring.g, go_membership, refactoring.packages)));

            elif command == "fastgreedy":
                go_membership = refactoring.detectCommunities().membership
                self.broadcast(self.participants, "membership/" + str(go_membership).strip("[]"))
                self.broadcast(self.participants, "measures/" + refactoring.getClusterMeasures());

        else:
            refactoring.parseGraph(command)
            go_membership = refactoring.detectCommunities().membership
            self.broadcast(self.participants, "membership/" + str(go_membership).strip("[]"))
            self.broadcast(self.participants, "measures/" + refactoring.getClusterMeasures());

# All refactoring and graph related capabilities
class Refactoring():
    g = None;
    gc = None;
    parsed_code_filename = None;
    original_membership = None;
    original_modularity = None;

    def __init__(self, graph=None):
        self.packages = dict()
        self.original_package_instability = dict()
        self.g = graph

    def parseChange(self, command, arg):
        if command == "addnode":
            self.g.add_vertex(arg)
        elif command == "removenode":
            self.g.delete_vertices(arg)
        elif command == "addedge":
            from_edge = int(arg.split(",")[0])
            to_edge = int(arg.split(",")[1])
            self.g.add_edge(from_edge, to_edge)
        elif command == "removeedge":
            from_edge = int(arg.split(",")[0])
            to_edge = int(arg.split(",")[1])
            self.g.delete_edges((from_edge, to_edge))

    def parseGraph(self, st):
        self.g = Graph()
        st_graph = st.split("|")
        vertices = st_graph[0].split(";")
        for v in vertices:
            self.g.add_vertex(v)

        edges = st_graph[1].split(";")
        for e in edges:
            from_edge = e.split(",")[0]
            to_edge = e.split(",")[1]
            self.g.add_edge(from_edge, to_edge)
        return self.g

    def graphToString(self):
        vertexlist = []
        for v in self.g.vs:
            vertexlist.append(v.index)
        vertex_str = str(vertexlist).strip("[]");
        vertex_str = vertex_str.replace(" ", "");
        s = str(self.g.get_edgelist()).strip("[]");
        s = s.replace("(", "");
        s = s.replace("),", ";");
        s = s.replace(")", "");
        s = s.replace(" ", "");
        s = vertex_str + "|" + s
        return s

    @staticmethod
    def formatMeasures(measure):
        measures = "";
        measures += "modularity:" + str(round(measure, 2)) # + ","
        return measures;

    @staticmethod
    def formatSuggestions(suggestions):
        return json.dumps(suggestions)

    @staticmethod
    def formatInstability(package_instability):
        return json.dumps(package_instability.items())

    def getClusterMeasures(self):
        if (self.gc == None):
            self.gc = self.detectCommunities()
        measures = "";
        measures += "modularity:" + str(round(self.gc.modularity, 2)) # + ","
        return measures;

    def getVertexLabels(self):
        msg = "";
        for v in self.g.vs:
            msg = msg + v['label'] + ",";

        msg = msg.strip(",")
        return msg

    def detectCommunities(self):
        self.g = self.g.simplify(loops='False', multiple='False')
        gc = self.g.as_undirected().community_fastgreedy()
        gc = gc.as_clustering()
        self.gc = gc
        return gc

    # This function works independently from local graph g
    def makeDwpdnMembership(self, graph):
        # If this graph has no label attribute at all
        if "label" not in graph.vs.attribute_names():
            custom_package_index = 0
            for v in graph.vs:
                v['label'] = str(custom_package_index) + "."
                custom_package_index += 1

        self.packages = dict()
        membership = []
        recent_package = 0;
        for v in graph.vs:
            if v['label'] == None:
                # Make a random package name if this package is a new isolated
                # node with no name
                random_package_name = hashlib.md5(str(time.time())).hexdigest()[0:5] + "."
                v['label'] = random_package_name
            package_name = v['label'].rsplit(".", 1)[0];
            if (self.packages.has_key(package_name)):
                membership.append(self.packages[package_name]);
            else:
                self.packages[package_name] = recent_package;
                membership.append(recent_package);
                recent_package += 1;

        return membership

    # This function works independently from local graph g
    def calculateQ(self, graph, membership):
        Q = 0.0;
        graph = graph.simplify(loops='False', multiple='False')
        m = graph.ecount();
        edge_count_factor = 2*m;
        if graph.is_directed() == True:
            edge_count_factor = m
        for i in graph.vs:
            for j in graph.vs:
                if membership[i.index] != membership[j.index]:
                    continue
                else:
                    Aij = 0
                    if graph.are_connected(i, j):
                        Aij = 1
                    wi_out = i.outdegree()
                    wj_in = j.indegree()
                    Q += Aij - (wi_out*wj_in) / edge_count_factor

        Q *= 1/edge_count_factor
        return Q;

    def getInstabilityForEachPackage(self, graph, membership, packages):
        package_in = packages.fromkeys(packages.iterkeys(), 0);
        package_out = packages.fromkeys(packages.iterkeys(), 0);
        package_instability = packages.fromkeys(packages.iterkeys(), 0);
        for e in graph.es:
            if (membership[e.target] != membership[e.source]):
                package_in[self.getPackageNameFromIndex(membership[e.target])] += 1;
                package_out[self.getPackageNameFromIndex(membership[e.source])] += 1;

        print package_out
        print package_in
        for package in packages:
            if package_out[package] + package_in[package] != 0:
                package_instability[package] = package_out[package] / (package_out[package] + package_in[package])
            else:
                package_instability[package] = 0;

        return package_instability

    def getPackageNameFromIndex(self, index):
        for name, i in self.packages.iteritems():
            if i == index:
                return name

    def refactor(self, directed=True):
        if directed == True:
            graph = self.g;
        else:
            graph = self.g.as_undirected()
        suggested_movements = [];
        Q_prime = -1;
        membership = self.makeDwpdnMembership(graph);
        # Check if there is only one package
        if membership.count(0) == len(membership):
            membership = range(len(membership))
        Q = self.calculateQ(graph, membership);
        selected_community = 0;
        v_range = range(graph.vcount())
        while True:
            restart_loop = False
            for index in v_range:
                i = graph.vs[index]
                for j in graph.vs:
                    temp_membership = list(membership)
                    temp_membership[i.index] = temp_membership[j.index];
                    temp_Q = self.calculateQ(graph, temp_membership);
                    if (temp_Q > Q_prime):
                        Q_prime = temp_Q;
                        selected_community = membership[j.index];
                if (Q_prime > Q):
                    suggested_movements.append((i['label'], self.getPackageNameFromIndex(membership[i.index]), self.getPackageNameFromIndex(selected_community)));
                    membership[i.index] = selected_community;
                    Q = Q_prime;
                    restart_loop = True
                    break;
            if not restart_loop:
                break;

        print "Done refactoring"
        return [Q_prime, membership, suggested_movements]

    def parseCode(self, filename):
        os.system("coffea -R -i " + filename + " -f gml -o temp.gml")
        self.parsed_code_filename = filename
        self.g = read('temp.gml')
        self.original_membership = self.makeDwpdnMembership(self.g)
        self.original_modularity = self.calculateQ(self.g, self.original_membership);
        self.original_package_instability = self.getInstabilityForEachPackage(self.g, self.original_membership, self.packages)

if __name__ == "__main__":
    import logging
    logging.getLogger().setLevel(logging.DEBUG)

    # Instantiate the main refactoring object
    refactoring = Refactoring();

    # Create the router
    Router = sockjs.tornado.SockJSRouter(Connection, '/picasso')

    # Create Tornado application
    app = tornado.web.Application(
            [(r"/", IndexHandler)] + Router.urls
    )

    # Make Tornado app and listen on port 8081
    port = 8081
    app.listen(port)
    print "Listening on port " + str(port);

    # Start IOLoop
    tornado.ioloop.IOLoop.instance().start()
```

Client side Javascript of Picasso
=================================

``` {language="javascript"}
    last = 1;
    conn = null;
    labels = [];
    $(function() {
      colors = ['#FF7F0E', '#AEC7E8', '#2CA02C', '#D62728', '#1F77B4']
      color = window.d3.scale.category20();
      function log(msg)
      {
          console.log(msg);
      }

      function parseAndApplyMessage(msg)
      {
          var message = msg.split("/");
          var command = message[0];
          if (message.length > 1)
          {
              var arguments = message[1];
              if (command == "membership")
              {
                  applyMembership(arguments);
              }
              else if (command == "graph")
              {
                  applyGraph(arguments);
              }
              else if (command == "labels")
              {
                  saveLabels(arguments);
              }
              else if (command == "measures")
              {
                  updateMeasures(arguments);
              }
              else if (command == "suggestions")
              {
                  setSuggestions(arguments);
                  $("#refactor-btn").button("reset");
                  $("#urefactor-btn").button("reset");
              }
              else if (command == "instability")
              {
                  setInstabilities(arguments);
              }
          }
      }

      function setSuggestions(msg)
      {
          var suggestions = JSON.parse(msg);
          txt = "<ol>";
          for (i in suggestions)
          {
              txt += "<li>Move class <span class='class-name'>" + suggestions[i][0] + "</span> from package <span class='package-name'>" + suggestions[i][1] + "</span> to package <span class='package-name'>" + suggestions[i][2] + "</span></li>";
          }
          txt += "</ol>"
          $(".modal-body").html(txt);
      }

      function setInstabilities(msg)
      {
          var instabilities = JSON.parse(msg);
          txt = "<ol>";
          for (i in instabilities)
          {
              txt += "<li>" + instabilities[i][0] + ": " + instabilities[i][1] + "</li>";
          }
          txt += "</ol>"
          $("#instability .modal-body").html(txt);
    }
      function updateMeasures(msg)
      {
          $("#measures").text(msg);
      }

      function saveLabels(msg)
      {
          labels = msg.split(",");
          for (var i = 0;i<G.nodes().length;i++)
          {
              d3.select("#node" + i.toString()).attr("data-label", labels[i]);
          }
      }
      function applyGraph(msg)
      {
          G.clear();
          var splitted_str = msg.split("|")
          var vertex_str = splitted_str[0];
          var edges_str = splitted_str[1];
          var vertices = vertex_str.split(",");
          for (key in vertices)
          {
              var vertex = parseInt(vertices[key]);
              G.add_node(vertex);
          }

          var edges = edges_str.split(";");
          for (key in edges)
          {
              var edge = edges[key];
              var from = parseInt(edge.split(",")[0]);
              var to = parseInt(edge.split(",")[1]);
              G.add_edge(from, to);
          }
          window.d3.selectAll(".node").on("mouseover", function(){
              jQuery("#label").text(d3.select(this).attr("data-label"));
          });
      }

      function applyMembership(msg)
      {
          membership = msg.split(", ");
          iteration = G.nodes_iter();
          for (key in membership)
          {
              node = iteration.next();
              G.node.get(node).color = color(membership[key]);
              window.d3.select("#node" + node.toString() + " circle" ).style("fill", color(membership[key]));
          }
      }

      function connect() {
        disconnect();

        var transports = $('#protocols input:checked').map(function(){
            return $(this).attr('id');
        }).get();

        conn = new SockJS('http://' + window.location.host + '/picasso', transports);

        log('Connecting...');

        conn.onopen = function() {
          log('Connected.');
          update_ui();
        };

        conn.onmessage = function(e) {
            //log('Received: ' + e.data);
            parseAndApplyMessage(e.data);
        };

        conn.onclose = function() {
          log('Disconnected.');
          conn = null;
          update_ui();
        };
      }

      function disconnect() {
        if (conn != null) {
          log('Disconnecting...');

          conn.close();
          conn = null;

          update_ui();
        }
      }

      function update_ui() {
        var msg = '';

        if (conn == null || conn.readyState != SockJS.OPEN) {
          $('#status').text('disconnected');
          $('#connect').text('Connect');
        } else {
          $('#status').text('connected (' + conn.protocol + ')');
          $('#connect').text('Disconnect');
        }
      }

      $('#connect').click(function() {
        if (conn == null) {
          connect();
        } else {
          disconnect();
        }

        update_ui();
        return false;
      });

      connect();
      
    addNode = function(node_name)
    {
        G.add_node(node_name);
        conn.send(G.nodes().join(";") + "|" + G.edges().join(";"));
    }
    addEdge = function(from, to)
    {
        G.add_edge(from, to);
        conn.send(G.nodes().join(";") + "|" + G.edges().join(";"));
    }
    removeEdge = function(from, to)
    {
        G.remove_edge(from, to);
        conn.send(G.nodes().join(";") + "|" + G.edges().join(";"));
    }
    drawGraph = function()
    {
        jsnx.draw(G, {
            element: '#canvas',
            with_labels: true,
            pan_zoom: {
                enabled: false
            },
            layout_attr: {
                'charge': -420,
                'linkDistance': 100
            },
            node_style: {
                fill: function(d) 
                {
                    return d.data.color || '#AAA';
                },
                stroke: 'none'
            },
            edge_style: {
                fill: '#999'
            },
            label_style: {
                fill: 'white',
                'font-size': '12px'
            }
        }, true);
    }
    G = jsnx.DiGraph();
    drawGraph();
    });
```

[^1]: <http://git-scm.com>

[^2]: <http://subversion.apache.org>

[^3]: <http://trama.sourceforge.net>

[^4]: <http://frontend4mysql.sourceforge.net>

[^5]: <https://github.com/sbilinski/coffea>

[^6]: <http://d3js.org>

[^7]: <http://felix-kling.de/JSNetworkX>

[^8]: <http://igraph.org>

[^9]: <https://github.com/sockjs/sockjs-client>
