Refactoring Catalog for Legacy software using C and Aspect Oriented

0 downloads 0 Views 129KB Size Report
refactoring, two techniques that deals with the problems of ... This paper documents a collection of ... Keywords: Refactoring, legacy software, aspect oriented.
Refactoring Catalog for Legacy software using C and Aspect Oriented Language S.A.M Rizvi and Zeba Khanam, Jamia Millia Islamia, New Delhi, India

Abstract- This paper explores the combination of AOP and refactoring, two techniques that deals with the problems of permanent evolution of software. AOP has evolved to deal with a large legacy of object-oriented (OO) code. Most of the work has been done in the area of refactoring the object oriented code but little with the procedural code and that too with aspect orientation. But the AO concept when applied to the procedural source code can be used to solve the existence of potential problems in the code thus improving the underlying design. The poorly designed procedural code when refactored with aspect orientation yields a better code. This paper documents a collection of novel refactorings enabling the extraction of crosscutting concerns from the procedural legacy source code. Therefore we establish a systematic approach for refactoring and then propose a refactoring catalog to deal with the procedural code that establishes a systematic approach to refactor the procedural code. To this end, we first investigate the impact of existing object-oriented refactorings such as those proposed by Fowler on procedural code. Then we propose some novel refactorings that are unique to the procedural code and the ones using the aspect concept are termed as aspect-oriented refactorings. We use AspeCt oriented C, an AOP language for C to demonstrate our approach.

concentrate on a particular concern in order to deal with it effectively. The abstraction can be achieved by applying the separation of concern technique. Loose coupling is an essential property of any software. We need to break, or decompose systems and problems into smaller subsystems and sub-problems, in order to concentrate on each sub problem by turns. The more it is loosely coupled; the easier it is to break. Loose coupling greatly facilitates system development because we are able to reason with an issue of the system at a time. AOP [1][14] provides stronger modularization. Experience with refactoring software [4] [11][7] suggests that refactoring techniques [5] have the potential to bring the concepts and mechanisms of aspect orientation to existing procedural code and applications, hence implementing the “separation of concern” in a more effective way.

Keywords: Refactoring, legacy software, aspect oriented programming, object oriented refactoring

AOP is an emerging field and its steady progress can be traced from “bleeding edge” research field to mainstream technology [1][24]. Its contribution to refactoring is remarkable and especially its support to refactoring object oriented frameworks provided stronger modularisation and software composition mechanisms than those provided by previous technologies. But one of the hurdles in its implementation to the procedural code is that there isn’t any developed or established theory and discipline for the process and that it does not have that much of modularity as it is in object oriented code due to the presence of classes.

1

Introduction

Refactoring is an approach that facilitates the continuous change of source code, enabling it to evolve in line with changes in environments and requirements. [1] Software engineering is a discipline that is dedicated to designing, implementing and modifying software so that it is of higher quality, more affordable, maintainable and easier to build. It creates models and tools for the support of abstraction [12][13]. We cannot concentrate on many subjects or concerns simultaneously. Instead, we need to abstract from most of the concerns so that we can

However, although refactoring has been studied widely for object-oriented software. The development of refactoring patterns for procedural software using the concept of aspect oriented programming has not been done. In this paper we, propose a systematic approach to refactoring procedural code and a refactoring catalog for procedural software.

2. Activities of Refactoring Process

In this paper we propose a systematic approach towards procedural programs. The refactoring approach is based on Monteiro’s pattern language. In [25] the pattern language contributes to refactoring existing systems into aspect

1

oriented versions of those Systems. The pattern language consist of three patterns Cross cutting concerns, Decide to refactor to aspects, and Refactor towards Aspect friendly code base that are intended to focus on the initial issues that arise when considering the option to refactor an existing OO system to AOP. When performing refactoring on the procedural programs there are certain issues that need to be assessed before refactoring. 1. Is the refactoring process focusing only on refactoring cross cutting concern (CCC)? 2. What about the code written in bad style or poorly designed code, should it be refactored or not? 3. Should the badly designed code be refactored into aspect friendly code or should it be refactored according to the traditional approach? Refactoring takes time but can be performed in phases. Refactoring to a better style or design brings benefits to understandability, maintainability and ease of evolution, that are independent of whether you Decide to refactor to aspects or not. Before going ahead with AOP refactorings, ensure that the system is already well-decomposed according to the current notions of good style. Fowler’s book provides a collection of 22 bad smells that indicate the kinds of situation in the code that warrant the use of the refactorings. Good examples of such smells are: Duplicated Code, Long Method and Large class. But these refactorings are for object oriented code In the subsequent section, refactorings for procedural programs are proposed. The problem is studied from three aspects.First; it is investigated [14] whether the objectoriented refactorings such as those proposed by Fowler [4] can be applied to procedural code. Second; proposal of some modification guidelines in order to adopt some of these refactorings to the domain of procedural language. Final step is the identification of some new refactorings using ACC that are unique to procedural C code.

3. Refactoring procedural code The motivation for using AOP for refactoring is that it is a new language paradigm that is different from procedural and object-oriented language; it provides a new construct, an aspect, to modularize crosscutting concerns in the code. Legacy code is a critical part of many systems and the source of many problems. Software systems must constantly

adapt to changes of the environment in which they operate. In most cases, legacy software has been developed in obsolete languages by using old-fashioned development practices. This complicates the upgrade of legacy parts. The most popular way to apply AOP in software development is to extend existing programming languages with new constructs, the most important of which are pointcuts, advices and introductions, that make it possible to express the crosscutting functionalities. There are aspect versions of many widely used languages as, for instance, Java, C/C++, Ada, Smalltalk, Perl, Python, etc.Opdyke identified a series of refactorings for object-oriented source code, using C++ as the subject language. But a similar catalog for procedural languages like C does not exist. So we explore a catalog of refactorings for procedural programming using C and AspeCt Oriented C.The table below depicts the impact of applying the object oriented refactorings on procedural code. Some of them are applicable directly wheras some require modification when applied using the aspect orientated concept. The table 1. below illustrates some of them: Table 1: Impact of applying object oriented refactoring on procedural code Extract method (no change) Add a method

Encapsulate (change)

(no change)

Move

Field Field

(change) Delete unreferenced method (no change) Add Parameter to method (change)

Shotgun surgery (change) Consolidate conditional expression (change)

Rename method

(change)

Merge conditional (change)

duplicate code

Inline method

(no change)

Extract (change)

Hide Method

(change)

Move Method

(change)

Replace Iteration with Recursion (no change) Replace Error code with Exception (change)

Conditional

Introducing Divergent Change in methods(change)

Replace type code with strategy(change)

Remove method

Simplify Expression

(change)

3.1Object Oriented procedural code

conditional (change)

Refactorings

for

2

We study the impact of object oriented refactorings [4] (those applicable) on the procedural programs and observe the changes that are required to implement them on the code. Some of those are directly applicable without any change whereas some are changed when aspect oriented concepts are applied.

catch ():try (call (void withdraw(int))) {printf (“Invalid amount”);} Figure 1: Replace Error code with Exception

Motivating Examples We present here a few examples to explain the behavior when applying existing object-oriented refactoring (OOrefactoring for short) to procedural code and the changes that we have incorporated to refactor the code. When things go wrong the program can be stopped with an error code. Fowler refactored with exception handling techniques .By carefully examining the refactoring Replace Error code with Exception [4], we found that this could not be achieved in procedural languages like C that did not support the exception handling mechanism. As a result, users of these legacy programming languages often implement exception handling by applying an idiom. An idiomatic style [22] of implementation has a number of drawbacks: applying idioms can be fault prone and requires significant effort. It is elaborated in the example below how we have changed this refactoring and applied it to the procedural code as well. Figure 1 presents here function named withdraw(int amount) that performs a check everytime an amount has to be withdrawn and returns -1 everytime the amount exceeds the balance. In C a special output is used to indicate error .The developers traditionally use a return code to signal success or failure of a routine. But with ACC, we examined that we can omit the return code idiom with try () and catch() advice. This makes programs easier to understand, thus reducing the complexity of the code too. Before refactoring

The next example that we present is extraction of conditional statement into advice. This refactoring has been modified in order to enable condition checking dynamically and free the method containing the conditional statement from unnecessary complexity. We depicted the case where it could be applied. A conditional statement controls the execution of the marked code. Fig. 2 shows this refactoring. The conditional statement in Fig. 2 in method g() determines the execution of another function f() in the control flow of g().This conditional statement can be made a part of advice and checked every time the function f() has to be executed. Before Refactoring void g() { if (value==TRUE) { f();} After Refactoring void g() { -} pointcut checkvalue():call f() && infunc g();

int withdraw (int amount) { if (amount > _balance) return -1; else { balance -= amount; return 0;}

before: p(){ if(value==TRUE) f();}

After refactoring with aspect code

The most obvious set of aspect-specific refactorings are simply straightforward analogs of refactorings that apply to classes or members. But its not true in case of procedural code whose structure is completely different from object oriented code and is completely dependant on methods and procedures. Aspect-orientation [23] introduces new aspectaware refactorings that differ from existing object-oriented refactorings.

void withdraw (int amount) { balance - = amount ;} before ():call (void withdraw (int)){ if(amount>balance) throw ();}

Figure 2: Extract conditional A Catalog of aspect oriented refactorings code

3

Table 2 lists aspect-oriented refactorings we proposed; This is not the complete set of aspect specific refactorings that we identified, more AO- refactorings will be added to the list as we go on with our experiments and get some new result. Table2: A catalog of aspect oriented refactorings for procedural code Extract fragment advice Create Empty Advice

into

Create introduce() advice Add an intype( ) poincut

Extract Common Members to Aspect

Create an around advice

Create Named Pointcut

Move Local Member Declaration to Aspect code Refactoring idiomatic code to AO specific style with a try() Pointcut Introduce catch () Advice

Rename a Named Pointcut Introduce a primitive pointcut Combine pointcut

However, even in such occasions there will be need to create an advice that calls the method. However before copying the code fragment, a careful analysis of the method’s (or, sometimes, the constructor’s) body should be made, in order to find a suitable pointcut to capture the exact set of intended joinpoints. If the primary code does not offer a suitable joinpoint, one or more refactorings must be performed until the code is ripe for this refactoring. Sometimes the advice will need to capture local variables (either primitives or object references). Note that these situations may be a sign that the method is more complicated than it should be. Consider whether it would make sense to split it in various parts, using Extract Method [4] for each part in turn. Such a split may provide the joinpoints you need. . Before Refactoring public void push (int data) { array [++_top] = data; display();}

Create an empty advice

Introduce a Preturn () in advice. Create a cflow pointcut

Replace method with advice

Create multiple advice for different situations

Extract method into advice

Replace type code with advice

Motivating Examples In this section 3 examples are presented to demonstrate refactorings with AOP.We have used AspeCt oriented C constructs for the purpose. An example (fig 3) demonstrates the extraction of an advice from the code. Extract fragment into advice case is discussed in the next section for elaborating the refactoring. Figure 3 contains a code snippet that demonstrates the extraction of a method in to advice. The figure depicts a push operation on a stack that calls the display () method after push operation that is called at many other places. In order to reuse the condition, we may turn it into a piece of after advice whose name reflects the value that the advice gives. The recommended action in this case is to create a pointcut capturing the required joinpoint and context and move the code fragment to an appropriate advice based on the pointcut.This refactoring should be used when we want to move to an aspect a piece of functionality that does not comprise a complete method or sometimes it is a simple method call. In some cases of object oriented code, the Extract Method [4], Fowler) can be conveniently applied.

After Refactoring public void push(int data) { array [++_top] = data; display (); } pointcut callpush (int data): execution (void push( int)) && args(data); after(int p ) : callpush(p) {display ();} Fig 3: Refactoring for extraction method into advice Figure 4 presents another program that depicts the extraction of a named pointcut.This is done in 2 steps [10] The first step, uses refactoring to create the initial pointcut and advice instances necessary to aspectize the code selected. The second step combines these instances into the final pointcuts and advices. The basic aim of creating a named pointcut is to make the pointcut more readable, usable and easier to be reused at different places. The example depicts the extraction of pointcut.The beginning of the method has been extracted. There are variants to this also like end of the method handler ,extract before/after call that we have modified and implemented in [20].Figure 4 contains a method student which has a precondition declared by if statement. A conditional statement controls the execution of the marked code. The conditional statement if (id= = null) is considered to be part of the advice, as it

4

determines the execution of the method (adddetails (details)) every time it is invoked. In order to reuse the precondition, we may turn it into a piece of before advice whose name reflects the value that the advice gives. This can be refactored by extracting a pointcut check to represent the join point related to the advice. Thus, it becomes a checked condition incorporated into an advice (using the ACC syntax).By doing so; the extracted pointcut check can be reused by other advice as well. We call such a refactoring as Extract Pointcut. Before refactoring void student (int id) { if (id= = null) { printf (``The argument is null''); break(); } adddetail(details); }

if (x = =NULL) { /* rountine to handle the case when memory allocation failed */ } /* routine for handling the normal case */ After refactoring after (void * s): (call ($ malloc (...)) || call ($ calloc (...)) || call ($ realloc (...))) && result(s) { char * result = (char *) (s); if (result == NULL) { /* routine to handle the case when memory allocation fails */ }} Now, the core program looks as follows: ... int *x; x = (int *) malloc (sizeof (int) * 4);

Suggest Documents