{'fraction_non_alphanumeric': 0.022021551579442075, 'fraction_numerical': 0.01074222028265467, 'mean_word_length': 4.572390572390573, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 1, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
A New Cohesion Metric and Restructuring Technique for Object Oriented Paradigm

When software systems grow large during development and maintenance, they may lose their quality and become complex to read, understand and maintain. A software component should be of good quality for the readers of the code to find its intents clear and the code behavior obvious. When this is the case it will be less costly to maintain the code and when its intent is clear, the code will be reusable, which is one of the key features of object oriented programming. Several software quality metrics have been proposed to measure overall or partial quality of software units such as classes or procedures. Cohesion is one of the most widely used metrics to measure quality of a software unit in terms of the relatedness of its components. This work presents a new cohesion metric based on program slicing and graph theory for units using object oriented paradigm. One can make a judgment on clarity of intent of the code using the metric we propose here. We aim to find out if a class is cohesive, handling one specific operation. We identify all program statements which constitute operations in the same abstraction domain. When a class has more than one abstraction, this technique suggests a restructuring for generating more cohesive units based on this new cohesion metric.


INTRODUCTION
Quality of a software unit is often measured with metrics like cohesion and coupling. Software developers put a great deal of effort into implementing high quality software units. High quality software has to be cohesive, readable, understandable, and reusable. Although these metrics can be used to measure the quality of a fragment of source code, in this work a unit refers to a class in an object oriented programming environment. In general, while cohesion metrics refer to the inter relatedness of a class's components, coupling measures the dependencies of a class with other units in the whole system. Software development is a continuing process which requires maintenance after release of the software product.
During this maintenance phase, developers may need to add some new functionality to the product or may need to change some of the existing functionalities based on changing needs of the users and transient working environments of the product. During this phase, changes made on the source code may reduce the quality of the software and make future changes more costly. Restructuring techniques help source code regain its quality after maintenance operations or sometimes even before the first release of the product.

A. Basics of Program Slicing
Program slicing is one of the preferred techniques to measure the cohesion level of software units. The concept of program slicing was first proposed by Mark Weiser [9, 12, and 13]. Weiser describes program slicing as the method of automatically decomposing programs by analyzing their relationships between statements based on data and control flow. Given the criterion C=(s, V), where s is a program statement and V is a subset of variables in a program P, program slicing is the process of finding all the program statements that affects value of a variable v in statement s. Figure 2 shows the program slice on the example program fragment P given in Figure 1, with respect to the criterion C= (9, sum). Here the number 9 represents the statement in line 9 of program P, i.e. cout << sum; 1 2 3 4 5 6 7 8 9 10 int i; int sum = 0; int product = 1; for(i = 0; i < N; ++i) { sum = sum + i; product = product *i; } cout<< sum; cout<< product; Program slicing has been used in procedural programming extensively since it was first proposed by Weiser. An empirical study of some slice-based cohesion metrics can be found in [5]. Slice based cohesion metrics have been proposed for measuring cohesion level of a procedure and used in various studies [1][2][3][4][5][6][7][8][9][10][11][12][13]. In [6], reviews on slice-based cohesion measures for procedural paradigm and object-oriented paradigm are discussed. Slice-based cohesion measures for object oriented software discussed in [6] is either an extension of functional cohesion measures [11] or uses data member-method interactions for measurement [18], and they are quite different than our approach described in this paper. Some studies using program slicing, suggest restructuring for procedures by defining the low cohesive parts of them to be extracted from the procedure. In [10], this technique is used to measure the cohesiveness of each statement in a procedure and to identify parts of the procedure that cause low cohesion for restructuring purposes. In [22], cohesion level between output variables of a function is determined and a graph (pair-wise cohesion graph) is generated to visualize this relationship. After removing all edges that represent a cohesion below a given threshold level, they suggest restructuring the function based on connected components in the graph. Although the approach in [22] seems to be similar to ours, we generate our graph in a completely different way seeking semantic relationships between statements in objectoriented programs and our graph represents semantic relationships between data members of a class rather than cohesion values between them. Moreover we suggest extracting new reusable and cohesive classes rather than just a number of functions based on the cohesion metric we define for classes in object oriented software. int i; int sum = 0; for(i = 0; i < N; ++i) { sum = sum + i; } cout<< sum; Figure 2. Slice of P with resp. to C= (9,sum) In [2], the notion of data slices is defined and used for measuring functional cohesion. For each output variable v, the data slice is defined as the set of data tokens (i.e. variable and constant definition and references). Therefore a change made on any of the data tokens in data slice of v will affect the value of output variable v at some point. Cohesion is measured based on the percentage of data tokens that appear in more than one data slice and the ones that appear in all the data slices. In this version of slicing, data tokens are the basic units rather than statements in the program.

B. Object-Oriented Cohesion Metrics and Restructuring
To our knowledge, there has not been any program slicing based cohesion measure suggested for restructuring classes into more cohesive abstractions while preserving behavior of the whole system in object oriented environments. In our approach for measuring cohesion we use a graph representation of the slices found in a class for conceptual evaluation and for restructuring the class into a more cohesive form. This graph representation of program slices will be of great help to see which parts of the class are more related to each other at the statement level.
Although there has been very few slice based cohesion metrics proposed for measuring the quality of classes in object oriented paradigm, to our knowledge none has been proposed for restructuring purposes. In [11], slice based data cohesion measures for object oriented designs are defined as a modification of slice based functional cohesion measures defined by Bieman and Ott [2]. In [11], private and protected member variables of a class are considered as the data tokens and data slices are determined based on them. They do not alter the definition of measuring cohesion and use exactly the same measurement technique proposed by [2]. We believe that, although this study is one of the very few that use program slicing in object oriented paradigm, it does not support restructuring a class into more cohesive form once low cohesion level of the class is determined.
There are some other techniques used to indicate the cohesion level of a class. The majority of them use interactions between data members and methods of the class such as data member usage or sharing of data members [14, 15, 16, 17, 18, and 19]. Some studies represent this methoddata member relationship with an undirected graph and suggest that the number of connected components in the graph indicates the cohesion level [17]. In [19] the dependency relationship between data members is also considered when evaluating the usage of a data member by a method. Although we believe that using graph theory in this manner is an important technique, none of these works suggest any restructuring to improve the cohesion level of a class once they quantitatively identified the low cohesion level of the class at hand.
In this work our evaluation of cohesion is quite different as we take executable statements and data members of a class and the relationship between them as the entities from which we construct our cohesion metrics. Therefore we believe that the information we get from that captures the semantic relationship of the data members more precisely than other techniques which consider only usage of data members in methods and method invocations.
Clustering Techniques is another preferred area of study for cohesion measurement and restructuring in object oriented paradigm. The basic idea in this technique is to group entities in a system (these entities are usually data members, methods and classes) based on the similarities between them or the relationships that they preserve in order to construct more cohesive groups [20].
Almost all applications of restructuring which use clustering techniques have this idea of moving data members or methods or some other entities that they define from one component to another. We believe that this approach may not be very useful for some cases as a method itself may not be cohesive. Our approach on the other hand, will help to generate classes with highly cohesive methods with the selected statements as it focuses on statements, data members, and semantic relationships between them, rather than just usage of data members in other components. In conclusion program slicing in this sense would be the most appropriate technique for restructuring classes as this technique reveals the actual relationship between components of interest.

C. Paper Organization
The rest of the paper is structured as follows. In section 2 we explain how we apply program slicing to object oriented classes with some new definitions of dependencies between statements.
The section highlights the process of determination of slicing criteria and program slices based on the criteria. Section 3 introduces the Data-Slice-Graph (DSG) and the cohesion metrics we develop for it. A restructuring process based on the cohesion and DSG is given in section 4. Section 5 provides an application of the approach on a small explanatory source code. Concluding remarks are provided in Section 6.

II. DETERMINATION OF SLICING CRITERIA AND CONSTRUCTION OF PROGRAM SLICES
In this section we describe our slicing criteria and how we approach the identification process of program slices based on those criteria.

A. Slicing Criteria in a Class
The first step in our approach is to determine the slicing criteria in the class. To identify slicing criteria and slices in a class C, we have defined the following sets:  DM C is the set of all private data members defined in class C.
 ST dxC is the set of all program statements which use data member d in C where d Є DM C .
Therefore each element of the set ST dxC represents a slicing criterion for data member d. Furthermore, for each d1 in DM C , we have a corresponding set ST d1xC representing the slicing criteria for data member d1.

B. Dependency Relation between Statements
In this study we use control and data dependencies between program statements to identify the slices in our target class. Informally speaking, a slice is the combination of backward and forward slices based on a criterion defined in above section. While a backward slice is defined as all the statements that the computation at the slicing criteria may depend on, forward slice consists of all the statements computation of which may be affected by the slicing criteria [23].
In this study, we analyze the dependencies between statements to construct the slices. Our primary focus is to find program statements which constitute operations in the same abstraction domain. For this reason we define a set of conditions for the statements to be evaluated in this manner. We say that two statements, S1 and S2, are dependent when one of the following conditions is true: 1. Execution of statement S1 is controlled by statement S2, or vice versa. An "if" control statement or a "for" loop statement is a good example for this case.
2. A variable defined in S1 is being used in S2 3. A variable, defined in statement S' which uses a variable defined in S1, is being used in S2. 4. A variable defined in statement S' is being used in both S1 and S2.

5.
Invocation of a function f () which includes the statement S1 is controlled by statement S2.
6. Execution of both S1 and S2 is controlled by the statement S'. 7. A variable defined in S1 is passed to a function f as an argument and the argument is being used in statement S2 of function f. int i; int sum = 0; int product = 1; for(i = 0; i < N; ++i) { sum = sum + i; product = product *i; } cout<< sum; cout<< product; Figure 3. Slice of P with resp. to C= (9, sum) Our definition of dependency relationship takes both direct and indirect dependencies into consideration and generates slightly different slices than other program slicing approaches do. After finding a specific slicing criterion, we take all the statements, which we think are semantically related to the criterion, into the slice rather than only the statements which affect value of a specific variable in the criterion. Figure 3 shows the slice we get from program fragment given in Figure 1 with respect to the criterion C= (9, sum) considering the dependency conditions stated above. Notice that from Figure 3 one can infer that all the statements are dependent in that program fragment with respect to the given criteria. We believe that in the scope of class cohesion and restructuring, considering all the dependency conditions listed above will lead to more accurate results as we seek semantic relationships between statements. Figure 4 demonstrates the dependency conditions listed above using some fragments of the source code of the original version of Class1 given in appendix. In condition 1, 5 and 6 of the figure, let the statements at line numbers 129, 131, 132 and 19 be represented by S', S1, S2 and S3 respectively. S', S1 and S2 are dependent since execution of S1 and S2 is controlled by S' and moreover S' and S3 are also dependent as invocation of function ErrorInSize(), which includes S3, depends on S'. In condition 2 and 3, let the statements at line numbers 64, 65, 66 and 67 be represented by S', S1, S2 and S3 respectively. S', S1, S2 and S3 are dependent because of their variable usage. In condition 4, let the statements at line numbers 111, 112 and 113 be represented by S', S1 and S2 respectively. S', S1 and S2 are dependent because a variable defined in S' is used in both S1 and S2. In condition 7, let the statements at line numbers 29 and 101 be represented by S1 and S2 respectively. S1 and S2 are dependent because a variable defined in S1 is being passed to function PushFunInvok(std::string str) as an argument and the argument is being used in statement S2 of the function.

C. Determination of Program Slices
To identify slices for data members defined in a class C, we have defined the following sets in addition to the sets defined in section 2.A: SL dxC = ⋃ Therefore SL dxC is the slice in our class C which includes all statements that directly or indirectly depend on at least one of the statements which reference data member d in C.

III. DATA-SLICE-GRAPH AND A NEW COHESION METRIC
Class structure is the key unit of object oriented programming. Therefore, developers aim to design classes with high quality so that they can be reused, maintained, and tested easily. To reduce maintenance cost, these key units are expected to be simple, understandable, and readable as well.
Cohesion metrics have been studied extensively for the purpose of evaluating the relatedness of the components of a class. Different techniques have been used to quantify this aspect of the quality for a class. Most of the cohesion metrics are not proposed for restructuring classes to improve cohesion; therefore they may not be so practical to be used as a restructuring criterion. We believe that a cohesion metric based on program slicing idea will give more accurate results in object oriented environment as a restructuring criterion.
In object-oriented programming, a class generally is designed to handle one certain operation (one abstraction). To achieve this, most classes have some data members and functions to handle some part of the operation based on the clients' requests using some of the data members defined in the class. From this point we think that there is likely to be a relationship between the data members which are used to perform the intended operation of the class.
As software is exposed to changes during maintenance phase of software development life cycle, the classes may be altered in a way that they include some irrelevant components to their intended operations and therefore they no longer preserve their simplicity and reusability properties by including more than one abstraction. Or a class may initially be designed having more than one abstraction in it because of complex requirements or some other reasons. If the class has more than one abstraction, there must be a group of data members involving in each abstraction domain. In other words, if there is more than one independent group of data members in the class definition, we can say that there is more than one abstraction in the class and so it is not cohesive.
In this study, we aim to formalize the idea described in the paragraph above, and suggest a restructuring to partition the class into two or more cohesive target classes. For doing so, we generate data-slice-graphs (DSG) to visualize the relationship between the data members.
In some other works which use the idea of graph theory for measuring cohesion, they generate the graph based only on whether a method uses the data member of interest or not. A graph generated from this idea may not always reveal actual semantic relationship between data members. A graph generated from program slices, in our sense, will be of great help to see the real relationship between data members; hence we expect it will give more accurate results.
In DSG, each node represents a data member of the class which may possibly need to be restructured. We have the following definitions for DSG:  DSG= (V, E) is a undirected graph such that V is the finite set of data members representing vertices in the graph and E is the finite set of relationships between data members representing edges in the graph.
 |V| is the number of data members of the class  Let v1v2 represent an edge between two nodes v1 and v2; v1v2 The description of DSG indicates that two data members, d1 and d2, are dependent if there is at least one program statement in the class that affects at least one occurrence of both data member d1 and data member d2 based on the dependency conditions given in section 2.B. Therefore the vertices, v1 and v2, representing data members d1 and d2 respectively, have an edge between them in DSG, i.e. v1v2 is in E.
We define the cohesion level of the class as the number of connected components, NC, in its DSG. The bigger NC the less cohesive our class is. Each connected component in DSG refers to one abstraction that the class holds.

IV. RESTRUCTURING THROUGH DSG
To propose restructuring for the class at hand, we use DSG and the number of connected components (NC) in DSG. Before discussing restructuring we shall explain what various values of NC mean:  NC = 0 means there is not any data members defined in the class. That is a class that has no state -a utility class may be an example for this. Note that we do not apply this restructuring idea on this type of classes as DSG does not reveal any relationship for this kind of classes.
 NC = 1 occurs when the class has only one abstraction and when it is most cohesive. We do not restructure this kind of classes as this is the best situation a class may be in.
 NC > 1 occurs when the class has more than one abstraction. DSG reveals this by having more than one connected component and each connected component in this case represent one different abstraction the class is designed to handle. We restructure the code in this case and generate one cohesive class out of each connected component in DSG.
In DSG each connected component is a candidate to be extracted as a new smaller yet more cohesive class. In the example DSG given in Figure 5, C1 and C2 represent two different abstractions and our approach suggests that they should be extracted as new classes. Therefore data members represented by v1-v5 together with their slices are to be one class and data members represented by v6-v8 together with their slices are to be another class. Our approach proposes this restructuring by defining independent sets of statements to be components of new classes. We propose to generate a method in the class with each consecutive set of statements in the slice of any data member that construct the connected component of the class. For example in Figure 5 data members v6, v7, and v8 construct the connected component for a new class C2 and each consecutive set of statements in the slices of these data members will be a method in C2.
In this study, we aim to come up with a technique to generate new cohesive and reusable classes from an existing less cohesive class. Although our approach fully defines all the statements related to one specific abstraction, restructuring the initial class to achieve our goal may require some simple analysis on the slices defined by our technique. In most cases extracting statements in the slices as methods into the new class is straightforward. Yet, there might be a few edge cases to handle for preventing any undesirable results. For example, we do not want to have any dependency from the classes we generate to the original class as this will affect the reusability of the classes by having a mutual dependency with the original class. This scenario is possible if a slice is including a function call. We have defined the following cases regarding possible problems with function calls during restructuring:

 Case 1: Function call in a control block
Definition: Our technique always guarantees that the function definition and the function call in this case are in the same slice. The 5th dependency condition listed in section 2.B assures this. Code fragment given for this condition in Figure 4 demonstrates this case. In that example code, statements at lines 18, 19, 20 and 137 are always guaranteed to be in the same slice.
Action: We suggest changing that function call in the control block with a function call to the corresponding function created in the new class. That will eliminate a callback to the original class. In other words, during restructuring of the code fragment given in Figure 4, statements at line numbers 19, 20 and 21 will be moved into a new class as a function and statements at line numbers between 129 and 139 will be moved to the same class as another function. Let f1 and f2 represent these two functions respectively. We can assure this as all of the statements above will always reside in the same slice. Therefore we replace the function call ErrorInSize(); in function f2 with a function call to function f1. Definition: Our technique always guarantees that the function call in this case will not reside in any of the slices defined by our technique as there is not any data being used in this function call.
Action: We do not need to do anything special for this case. This case does not cause any call back to the original class.

 Case 3: Function call with an argument
Definition: Our technique does not guarantee that all of the statements in the definition of the function will always be in the same slice as function call, although we think that this is a case unlikely to happen. Yet, at least some parts of the function will be in the same slice with the function call, but the action in case 1 would not solve this problem in this case. The 7th dependency condition listed in section 2.B is related to this case and code fragment given for this condition in Figure 4 demonstrates it. In that code fragment function call at line number 31 passes an argument to the function PushFunInvok(std::string str) and statement at line 101 uses that argument. When we analyze this function we will see that all the statements in its definition are fully dependent with respect to the criterion C= (101, str) based on our dependency conditions. This makes the case to be just like case 1 and action in case 1 will handle any possible call backs for our example program.
Action: One should verify if the definition of the function consists of statements which are fully dependent based on some previously defined criteria or based on criterion of the statement which uses the argument passed to the function. If the function definition consists of fully dependent statements then this case is same as case 1. Otherwise this function call should be removed from the slice and the argument in the function call should be replaced with a return value from the function created in the new class corresponding to this consecutive set of statements where the function call resides.
Considering all of these cases will eliminate any possible undesirable dependencies that might arise from call-backs to the original class.

V. CASE STUDY
We now present an example for demonstration of this new cohesion and restructuring approach. We have our initial class as shown in appendix with the name of Class1. This class has 9 private data members and is not very well designed. Figure 6 shows all the properties of the class based on our approach for data members stk and top. Note that in the figure all the numbers given as an element of a set are the line numbers of the statements in the program. Sets for other data members of the class and their pair wise comparisons can be found in [21].  In Figure 6, the set ST stkxClass1 is the set of all statements that use data member stk of Class1. This set represents the slicing criteria for that data member. In this case there are two statements which use data member stk in Class1, and they are the statements at line number 116 and 132. The sets SL 116xClass1 and SL 132xClass1 represent the slices based on the criterion of the statement at line number 116 and the criterion of the statement at line number 132 respectively. And finally the set SL stkxClass1 represent the slice of data member stk including all the statements that is dependent on at least one occurrence of that data member.
After finding all the properties for each data member of the class as shown in Figure 6, now we are ready to construct DSG for the class. Figure 7 shows the process of constructing the graph. We have analyzed the codes for the given example class in appendix and generated the table shown in Figure 8 that demonstrates the pair-wise comparisons of the slices for each data member of the class. Figure 8 shows the intersections of slices of pairs of data members of Class1 given in appendix. "Ø" means that the intersection of the slices is the empty set for the two data members and ∩ means that there are some elements in the intersection of the slices. From this table, we generated the DSG in Figure 9.  In Figure 9, we represent the relationship between data members shown in Figure 8 with an undirected graph representing the corresponding DSG for our class. Each connected component in the DSG in Figure 9 is shown with a different line style. In this case our corresponding DSG has three connected components. That means that the class we have analyzed has three abstractions in it and it is not cohesive and thus it should be restructured. Our restructuring approach suggests creating a new class for each one of the connected component, found in DSG. In this case we suggest extracting three classes. The first class will include data members of funinvokes, rawtime, topInvok and their corresponding slices. The second class will include data members of top and stk and their corresponding slices. And lastly the third class will include x1, x2, y1, y2 and their corresponding slices.
After extracting the suggested classes, the initial class will also be modified as it will invoke the proper functions of the new classes in the places where statements were removed. Therefore, since our approach does not suggest altering the public interface of the original class, this restructuring will not affect clients' code at all. The original and restructured versions of the example class Class1 and the new classes that we extracted from original class are shown in the appendix. Because of the limitation on the number of pages of this paper we show the detailed process of restructuring in [21].

VI. CONCLUSION
In this study we have proposed a new cohesion metrics and an extract class restructuring technique for classes in object oriented environments using program slicing and graph theory. Our approach is different from other related works in a way that we try to find statements that constitutes the same abstraction in a class rather than regrouping existing components of a system. A tool support is needed for this approach to be applied to large software system and that remains as a future work of our study.