]> git.uio.no Git - ifi-stolz-refaktor.git/blame - thesis/master-thesis-erlenkr.tex
SearchBasedExtractAndMoveMethodChangerBenchmark: adding system parameter
[ifi-stolz-refaktor.git] / thesis / master-thesis-erlenkr.tex
CommitLineData
7c28933b 1\documentclass[USenglish]{ifimaster}
571ef294 2\usepackage{import}
7c28933b 3\usepackage[utf8]{inputenc}
9ff90080
EK
4\usepackage[T1]{fontenc,url}
5\urlstyle{sf}
571ef294 6\usepackage{babel,textcomp,csquotes,ifimasterforside,varioref,graphicx}
84fe308b 7\usepackage[style=numeric-comp,backend=bibtex]{biblatex}
571ef294 8%\usepackage[backend=biber,style=numeric-comp]{biblatex}
12c254af 9\usepackage{amsthm}
00aa0588 10\usepackage{todonotes}
8fae7b44
EK
11\usepackage{perpage} %the perpage package
12\MakePerPage{footnote} %the perpage package command
9ff90080 13
12c254af
EK
14\theoremstyle{plain}
15\newtheorem*{wordDef}{Definition}
16
17\newcommand{\definition}[1]{\begin{wordDef}#1\end{wordDef}}
137e0e7b
EK
18\newcommand{\see}[1]{(see \ref{#1})}
19\newcommand{\explanation}[3]{\noindent\textbf{\textit{#1}}\\*\emph{When:}
20#2\\*\emph{How:} #3\\*[-7px]}
f041551b
EK
21\newcommand{\type}[1]{\texttt{#1}}
22\newcommand{\typeref}[1]{\footnote{\type{#1}}}
23\newcommand{\typewithref}[2]{\type{#2}\typeref{#1.#2}}
24\newcommand{\method}[1]{\type{#1}}
25\newcommand{\methodref}[2]{\footnote{\type{#1}\method{\##2()}}}
26\newcommand{\methodwithref}[2]{\method{#2}\footnote{\type{#1}\method{\##2()}}}
9ff90080 27
7c28933b
EK
28
29\title{Refactoring}
84fe308b 30\subtitle{An unfinished essay}
7c28933b
EK
31\author{Erlend Kristiansen}
32
33\bibliography{bibliography/master-thesis-erlenkr-bibliography}
9ff90080
EK
34
35\begin{document}
531c4132 36\ififorside
9ff90080 37\frontmatter{}
9ff90080
EK
38
39
40\chapter*{Abstract}
41Empty document.
42
43\tableofcontents{}
44\listoffigures{}
45\listoftables{}
46
47\chapter*{Preface}
48
055dca93 49\mainmatter
00aa0588 50
b0e80574 51\chapter{Introduction}
7c28933b 52
8fae7b44 53\section{What is Refactoring?}
7c28933b 54
00aa0588 55This question is best answered dividing the answer into two parts. First
8fae7b44 56defining the concept of a refactoring, then discuss what the discipline of
51a854d4 57refactoring is all about. And to make it clear already from the beginning: The
8fae7b44 58discussions in this report must be seen in the context of object oriented
51a854d4
EK
59programming languages. It may be obvious, but much of the material will not make
60much sense otherwise, although some of the techniques may be applicable to
00aa0588
EK
61sequential \todo{sequential?} languages, then possibly in other forms.
62
63\subsection{Defining refactoring}
8fae7b44 64Martin Fowler, in his masterpiece on refactoring \cite{refactoring}, defines a
00aa0588
EK
65refactoring like this:
66\begin{quote}
67 \emph{Refactoring} (noun): a change made to the \todo{what does he mean by
68 internal?} internal structure of software to make it easier to understand and
69 cheaper to modify without changing its observable
8fae7b44 70 behavior.~\cite{refactoring} % page 53
00aa0588 71\end{quote}
137e0e7b 72This definition gives additional meaning to the word \emph{refactoring}, beyond
00aa0588
EK
73its \todo{original?} original meaning. Fowler is mixing the \emph{motivation}
74behind refactoring into his definition. Instead it could be made clean, only
8fae7b44 75considering the mechanical and behavioral aspects of refactoring. That is to
137e0e7b 76factor the program again, putting it together in a different way than before,
8fae7b44 77while preserving the behavior of the program. An alternative definition could
137e0e7b 78then be:
51a854d4 79
51a854d4 80\definition{A refactoring is a transformation
8fae7b44 81done to a program without altering its external behavior.}
00aa0588 82
8fae7b44
EK
83So a refactoring primarily changes how the \emph{code} of a program is perceived
84by the \emph{programmer}, and not the behavior experienced by any user of the
137e0e7b 85program. Although the logical meaning is preserved, such changes could
8fae7b44 86potentially alter the program's behavior when it comes to performance gain or
00aa0588
EK
87penalties. So any logic depending on the performance of a program could make the
88program behave differently after a refactoring.
89
137e0e7b
EK
90In the extreme case one could argue that such a thing as \emph{software
91obfuscation} is to refactor. If we where to define it as a refactoring, it could
92be defined as a composite refactoring \see{intro_composite}, consisting of, for
93instance, a series of rename refactorings. (But it could of course be much more
94complex, and the mechanics of it would not exactly be carved in stone.) To
95perform some serious obfuscation one would also take advantage of techniques not
96found among established refactorings, such as removing whitespace. This might
97not even generate a different syntax tree for languages not sensitive to
98whitespace, placing it in the gray area of what transformations is to be
99considered refactorings.
00aa0588
EK
100
101Finally, to \emph{refactor} is (quoting Martin Fowler)
7c28933b
EK
102\begin{quote}
103 \ldots to restructure software by applying a series of refactorings without
8fae7b44 104 changing its observable behavior.~\cite{refactoring} % page 54, definition
7c28933b
EK
105\end{quote}
106
00aa0588
EK
107% subsection with the history of refactoring?
108
109\subsection{Motivation} % better headline?
110To get a grasp of what refactoring is all about, we can answer this question:
111\emph{Why do people refactor?} Possible answers could include: ``To remove
112duplication'' or ``to break up long methods''. Practitioners of the art of
113Design Patterns~\cite{dp} could say that they do it to introduce a long-needed
114pattern to their program's design. So it's safe to say that peoples' intentions
115are to make their programs \emph{better} in some sense. But what aspects of the
116programs are becoming improved?
51a854d4
EK
117
118As already mentioned, people often refactor to get rid of duplication. Moving
00aa0588
EK
119identical or similar code into methods, and maybe pushing those up or down in
120their hierarchies. Making template methods for overlapping algorithms
121\todo{better?: functionality} and so on. It's all about gathering what belongs
122together and putting it all in one place. And the result? The code is easier to
137e0e7b
EK
123maintain. When removing the implicit coupling between the code snippets, the
124location of a bug is limited to only one place, and new functionality need only
125to be added this one place, instead of a number of places people might not even
126remember.
51a854d4
EK
127
128The same people find out that their program contains a lot of long and
129hard-to-grasp methods. Then what do they do? They begin dividing their methods
00aa0588
EK
130into smaller ones, using the \emph{Extract Method}
131refactoring~\cite{refactoring}. Then they may discover something about their
132program that they weren't aware of before; revealing bugs they didn't know about
133or couldn't find due to the complex structure of their program. \todo{Proof?}
134Making the methods smaller and giving good names to the new ones clarifies the
135algorithms and enhances the \emph{understandability} of the program. This makes
136simple refactoring an excellent method for exploring unknown program code, or
137code that you had forgotten that you wrote!
51a854d4
EK
138
139The word \emph{simple} came up in the last section. In fact, most basic
140refactorings are simple. The true power of them are revealed first when they are
137e0e7b 141combined into larger --- higher level --- refactorings, called \emph{composite
8fae7b44 142refactorings} \see{intro_composite}. Often the goal of such a series of
137e0e7b
EK
143refactorings is a design pattern. Thus the \emph{design} can be evolved
144throughout the lifetime of a program, opposed to designing up-front. It's all
51a854d4
EK
145about being structured and taking small steps to improve the design.
146
147Many refactorings are aimed at lowering the coupling between different classes
148and different layers of logic. Say for instance that the coupling between the
149user interface and the business logic of a program is lowered. Then the business
150logic of the program could much easier be the target of automated tests,
0b0567f2
EK
151increasing the productivity in the software development process. It would also
152be much easier to distribute the different parts of the program if they were
153decoupled.
154
155Another effect of refactoring is that with the increased separation of concerns
137e0e7b
EK
156coming out of many refactorings, the \emph{performance} is improved. When
157profiling programs, the problem parts are narrowed down to smaller parts of the
158code, which are easier to tune, and optimization can be performed only where
159needed and in a more effective way.
160
161Refactoring program code --- with a goal in mind --- can give the code itself
162more value. That is in the form of robustness to bugs, understandability and
163maintainability. With the first as an obvious advantage, but with the following
00aa0588
EK
164two being also very important in software development. By incorporating
165refactoring in the development process, bugs are found faster, new functionality
166is added more easily and code is easier to understand by the next person exposed
167to it, which might as well be the person who wrote it. So, refactoring can also
137e0e7b 168add to the monetary value of a business, by increased productivity of the
8fae7b44 169development process in the long run. Where this last point also should open
137e0e7b
EK
170the eyes of some nearsighted managers who seldom see beyond the next milestone.
171
172
173\section{Classification of refactorings}
174% only interesting refactorings
175% with 2 detailed examples? One for structured and one for intra-method?
176% Is replacing Bubblesort with Quick Sort considered a refactoring?
177
178\subsection{Structural refactorings}
179
180\subsubsection{Basic refactorings}
181
182% Composing Methods
183\explanation{Extract Method}{You have a code fragment that can be grouped
184together.}{Turn the fragment into a method whose name explains the purpose of
185the method.}
186
187\explanation{Inline Method}{A method's body is just as clear as its name.}{Put
188the method's body into the body of its callers and remove the method.}
189
190\explanation{Inline Temp}{You have a temp that is assigned to once with a simple
191expression, and the temp is getting in the way of other refactorings.}{Replace
192all references to that temp with the expression}
193
194% Moving Features Between Objects
195\explanation{Move Method}{A method is, or will be, using or used by more
196features of another class than the class on which it is defined.}{Create a new
197method with a similar body in the class it uses most. Either turn the old method
198into a simple delegation, or remove it altogether.}
199
200\explanation{Move Field}{A field is, or will be, used by another class more than
201the class on which it is defined}{Create a new field in the target class, and
202change all its users.}
203
204% Organizing Data
205\explanation{Replace Magic Number with Symbolic Constant}{You have a literal
206number with a particular meaning.}{Create a constant, name it after the meaning,
207and replace the number with it.}
208
209\explanation{Encapsulate Field}{There is a public field.}{Make it private and
210provide accessors.}
211
212\explanation{Replace Type Code with Class}{A class has a numeric type code that
8fae7b44 213does not affect its behavior.}{Replace the number with a new class.}
137e0e7b
EK
214
215\explanation{Replace Type Code with Subclasses}{You have an immutable type code
8fae7b44 216that affects the behavior of a class.}{Replace the type code with subclasses.}
137e0e7b
EK
217
218\explanation{Replace Type Code with State/Strategy}{You have a type code that
8fae7b44 219affects the behavior of a class, but you cannot use subclassing.}{Replace the
137e0e7b
EK
220type code with a state object.}
221
222% Simplifying Conditional Expressions
223\explanation{Consolidate Duplicate Conditional Fragments}{The same fragment of
8fae7b44 224code is in all branches of a conditional expression.}{Move it outside of the
137e0e7b
EK
225expression.}
226
227\explanation{Remove Control Flag}{You have a variable that is acting as a
228control flag fro a series of boolean expressions.}{Use a break or return
229instead.}
230
231\explanation{Replace Nested Conditional with Guard Clauses}{A method has
8fae7b44 232conditional behavior that does not make clear the normal path of
137e0e7b
EK
233execution.}{Use guard clauses for all special cases.}
234
8fae7b44 235\explanation{Introduce Null Object}{You have repeated checks for a null
137e0e7b
EK
236value.}{Replace the null value with a null object.}
237
238\explanation{Introduce Assertion}{A section of code assumes something about the
239state of the program.}{Make the assumption explicit with an assertion.}
240
241% Making Method Calls Simpler
242\explanation{Rename Method}{The name of a method does not reveal its
243purpose.}{Change the name of the method}
244
245\explanation{Add Parameter}{A method needs more information from its
246caller.}{Add a parameter for an object that can pass on this information.}
247
248\explanation{Remove Parameter}{A parameter is no longer used by the method
249body.}{Remove it.}
250
251%\explanation{Parameterize Method}{Several methods do similar things but with
252%different values contained in the method.}{Create one method that uses a
253%parameter for the different values.}
254
255\explanation{Preserve Whole Object}{You are getting several values from an
256object and passing these values as parameters in a method call.}{Send the whole
257object instead.}
258
259\explanation{Remove Setting Method}{A field should be set at creation time and
260never altered.}{Remove any setting method for that field.}
261
262\explanation{Hide Method}{A method is not used by any other class.}{Make the
263method private.}
264
8fae7b44
EK
265\explanation{Replace Constructor with Factory Method}{You want to do more than
266simple construction when you create an object}{Replace the constructor with a
137e0e7b
EK
267factory method.}
268
269% Dealing with Generalization
8fae7b44 270\explanation{Pull Up Field}{Two subclasses have the same field.}{Move the field
137e0e7b
EK
271to the superclass.}
272
273\explanation{Pull Up Method}{You have methods with identical results on
274subclasses.}{Move them to the superclass.}
275
8fae7b44 276\explanation{Push Down Method}{Behavior on a superclass is relevant only for
137e0e7b
EK
277some of its subclasses.}{Move it to those subclasses.}
278
279\explanation{Push Down Field}{A field is used only by some subclasses.}{Move the
280field to those subclasses}
281
282\explanation{Extract Interface}{Several clients use the same subset of a class's
8fae7b44 283interface, or two classes have part of their interfaces in common.}{Extract the
137e0e7b
EK
284subset into an interface.}
285
286\explanation{Replace Inheritance with Delegation}{A subclass uses only part of a
287superclasses interface or does not want to inherit data.}{Create a field for the
288superclass, adjust methods to delegate to the superclass, and remove the
289subclassing.}
290
291\explanation{Replace Delegation with Inheritance}{You're using delegation and
292are often writing many simple delegations for the entire interface}{Make the
293delegating class a subclass of the delegate.}
294
295\subsubsection{Composite refactorings}
296
297% Composing Methods
298% \explanation{Replace Method with Method Object}{}{}
299
300% Moving Features Between Objects
301\explanation{Extract Class}{You have one class doing work that should be done by
302two}{Create a new class and move the relevant fields and methods from the old
303class into the new class.}
304
305\explanation{Inline Class}{A class isn't doing very much.}{Move all its features
306into another class and delete it.}
307
308\explanation{Hide Delegate}{A client is calling a delegate class of an
309object.}{Create Methods on the server to hide the delegate.}
310
311\explanation{Remove Middle Man}{A class is doing to much simple delegation.}{Get
312the client to call the delegate directly.}
313
314% Organizing Data
315\explanation{Replace Data Value with Object}{You have a data item that needs
8fae7b44 316additional data or behavior.}{Turn the data item into an object.}
137e0e7b
EK
317
318\explanation{Change Value to Reference}{You have a class with many equal
319instances that you want to replace with a single object.}{Turn the object into a
320reference object.}
321
322\explanation{Encapsulate Collection}{A method returns a collection}{Make it
8fae7b44 323return a read-only view and provide add/remove methods.}
137e0e7b
EK
324
325% \explanation{Replace Array with Object}{}{}
326
327\explanation{Replace Subclass with Fields}{You have subclasses that vary only in
328methods that return constant data.}{Change the methods to superclass fields and
329eliminate the subclasses.}
330
331% Simplifying Conditional Expressions
332\explanation{Decompose Conditional}{You have a complicated conditional
333(if-then-else) statement.}{Extract methods from the condition, then part, an
334else part.}
335
336\explanation{Consolidate Conditional Expression}{You have a sequence of
337conditional tests with the same result.}{Combine them into a single conditional
338expression and extract it.}
339
340\explanation{Replace Conditional with Polymorphism}{You have a conditional that
8fae7b44 341chooses different behavior depending on the type of an object.}{Move each leg
137e0e7b
EK
342of the conditional to an overriding method in a subclass. Make the original
343method abstract.}
344
345% Making Method Calls Simpler
346\explanation{Replace Parameter with Method}{An object invokes a method, then
347passes the result as a parameter for a method. The receiver can also invoke this
348method.}{Remove the parameter and let the receiver invoke the method.}
349
350\explanation{Introduce Parameter Object}{You have a group of parameters that
351naturally go together.}{Replace them with an object.}
352
353% Dealing with Generalization
354\explanation{Extract Subclass}{A class has features that are used only in some
355instances.}{Create a subclass for that subset of features.}
356
357\explanation{Extract Superclass}{You have two classes with similar
358features.}{Create a superclass and move the common features to the
359superclass.}
360
361\explanation{Collapse Hierarchy}{A superclass and subclass are not very
362different.}{Merge them together.}
363
364\explanation{Form Template Method}{You have two methods in subclasses that
365perform similar steps in the same order, yet the steps are different.}{Get the
366steps into methods with the same signature, so that the original methods become
367the same. Then you can pull them up.}
368
369
370\subsection{Functional refactorings}
371
372\explanation{Substitute Algorithm}{You want to replace an algorithm with one
373that is clearer.}{Replace the body of the method with the new algorithm.}
00aa0588
EK
374
375
376\section{The impact on software quality}
377
378\subsection{What is meant by quality?}
379The term \emph{software quality} has many meanings. It all depends on the
9a55a5bc
EK
380context we put it in. If we look at it with the eyes of a software developer, it
381usually mean that the software is easily maintainable and testable, or in other
382words, that it is \emph{well designed}. This often correlates with the
383management scale, where \emph{keeping the schedule} and \emph{customer
137e0e7b
EK
384satisfaction} is at the center. From the customers point of view, in addition to
385good usability, \emph{performance} and \emph{lack of bugs} is always
386appreciated, measurements that are also shared by the software developer. (In
387addition, such things as good documentation could be measured, but this is out
388of the scope of this document.)
9a55a5bc 389
00aa0588 390\subsection{The impact on performance}
9a55a5bc
EK
391\begin{quote}
392 Refactoring certainly will make software go more slowly, but it also makes the
00aa0588 393 software more amenable to performance tuning.~\cite{refactoring} % page 69
9a55a5bc
EK
394\end{quote}
395There is a common belief that refactoring compromises performance, due to
396increased degree of indirection and that polymorphism is slower than
397conditionals.
398
00aa0588 399In a survey, Demeyer~\cite{demeyer2002} disproves this view in the case of
9a55a5bc
EK
400polymorphism. He is doing an experiment on, what he calls, ``Transform Self Type
401Checks'' where you introduce a new polymorphic method and a new class hierarchy
402to get rid of a class' type checking of a ``type attribute``. He uses this kind
403of transformation to represent other ways of replacing conditionals with
404polymorphism as well. The experiment is performed on the C++ programming
00aa0588
EK
405language and with three different compilers and platforms. \todo{But is the
406result better?} Demeyer concludes that, with compiler optimization turned on,
407polymorphism beats middle to large sized if-statements and does as well as
408case-statements. (In accordance with his hypothesis, due to similarities
409between the way C++ handles polymorphism and case-statements.)
9a55a5bc
EK
410\begin{quote}
411 The interesting thing about performance is that if you analyze most programs,
412 you find that they waste most of their time in a small fraction of the code.
00aa0588 413 ~\cite{refactoring}
9a55a5bc
EK
414\end{quote}
415So, although an increased amount of method calls could potentially slow down
416programs, one should avoid premature optimization and sacrificing good design,
417leaving the performance tuning until after profiling the software and having
418isolated the actual problem areas.
419
420
00aa0588 421
00aa0588
EK
422\section{Correctness of refactorings}
423% Volker's example?
424
425\section{Composite refactorings} \label{intro_composite}
426% motivation, example(s)
427% manual vs automated?
428% what about refactoring in a very large code base?
429
430\section{Software metrics}
431
432
433%\part{The project}
434%\chapter{Planning the project}
435%\part{Conclusion}
436%\chapter{Results}
437
b0e80574 438
5837a41f
EK
439\chapter{Refactorings in Eclipse JDT: Design, Shortcomings and Wishful
440Thinking}\label{ch:jdt_refactorings}
441
442This chapter will deal with some of the design behind refactoring support in
443Eclipse, and the JDT in specific. After which it will follow a section about
444shortcomings of the refactoring API in terms of composition of refactorings. The
445chapter will be concluded with a section telling some of the ways the
446implementation of refactorings in the JDT could have worked to facilitate
447composition of refactorings.
055dca93 448
b0e80574 449\section{Design}
f041551b
EK
450The refactoring world of Eclipse can in general be separated into two parts: The
451language independent part and the the part written for a specific programming
07e173d4
EK
452language -- the language that is the target of the supported refactorings.
453\todo{What about the language specific part?}
f041551b
EK
454
455\subsection{The Language Toolkit}
456The Language Toolkit, or LTK for short, is the framework that is used to
457implement refactorings in Eclipse. It is language independent and provides the
458abstractions of a refactoring and the change it generates, in the form of the
459classes \typewithref{org.eclipse.ltk.core.refactoring}{Refactoring} and
460\typewithref{org.eclipse.ltk.core.refactoring}{Change}. (There is also parts of
461the LTK that is concerned with user interaction, but they will not be discussed
462here, since they are of little value to us and our use of the framework.)
463
464\subsubsection{The Refactoring Class}
465The abstract class \type{Refactoring} is the core of the LTK framework. Every
466refactoring that is going to be supported by the LTK have to end up creating an
467instance of one of its subclasses. The main responsibilities of subclasses of
468\type{Refactoring} is to implement template methods for condition checking
469(\methodwithref{org.eclipse.ltk.core.refactoring.Refactoring}{checkInitialConditions}
470and
471\methodwithref{org.eclipse.ltk.core.refactoring.Refactoring}{checkFinalConditions}),
472in addition to the
473\methodwithref{org.eclipse.ltk.core.refactoring.Refactoring}{createChange}
07e173d4
EK
474method that creates and returns an instance of the \type{Change} class.
475
476If the refactoring shall support that others participate in it when it is
477executed, the refactoring has to be a processor-based
478refactoring\typeref{org.eclipse.ltk.core.refactoring.participants.ProcessorBasedRefactoring}.
479It then delegates to its given
480\typewithref{org.eclipse.ltk.core.refactoring.participants}{RefactoringProcessor}
481for condition checking and change creation.
f041551b
EK
482
483\subsubsection{The Change Class}
07e173d4
EK
484This class is the base class for objects that is responsible for performing the
485actual workspace transformations in a refactoring. The main responsibilities for
486its subclasses is to implement the
487\methodwithref{org.eclipse.ltk.core.refactoring.Change}{perform} and
488\methodwithref{org.eclipse.ltk.core.refactoring.Change}{isValid} methods. The
489\method{isValid} method verifies that the change object is valid and thus can be
490executed by calling its \method{perform} method. The \method{perform} method
491performs the desired change and returns an undo change that can be executed to
492reverse the effect of the transformation done by its originating change object.
493
61420ef7 494\subsubsection{Executing a Refactoring}\label{executing_refactoring}
07e173d4
EK
495The life cycle of a refactoring generally follows two steps after creation:
496condition checking and change creation. By letting the refactoring object be
497handled by a
498\typewithref{org.eclipse.ltk.core.refactoring}{CheckConditionsOperation} that
499in turn is handled by a
500\typewithref{org.eclipse.ltk.core.refactoring}{CreateChangeOperation}, it is
501assured that the change creation process is managed in a proper manner.
502
503The actual execution of a change object has to follow a detailed life cycle.
504This life cycle is honored if the \type{CreateChangeOperation} is handled by a
505\typewithref{org.eclipse.ltk.core.refactoring}{PerformChangeOperation}. If also
506an undo manager\typeref{org.eclipse.ltk.core.refactoring.IUndoManager} is set
507for the \type{PerformChangeOperation}, the undo change is added into the undo
508history.
055dca93 509
b0e80574 510\section{Shortcomings}
80663734 511This section is introduced naturally with a conclusion: The JDT refactoring
5837a41f
EK
512implementation does not facilitate composition of refactorings.
513\todo{refine}This section will try to explain why, and also identify other
514shortcomings of both the usability and the readability of the JDT refactoring
515source code.
80663734
EK
516
517I will begin at the end and work my way toward the composition part of this
518section.
519
5837a41f 520\subsection{Absence of Generics in Eclipse Source Code}
80663734
EK
521This section is not only concerning the JDT refactoring API, but also large
522quantities of the Eclipse source code. The code shows a striking absence of the
523Java language feature of generics. It is hard to read a class' interface when
5837a41f
EK
524methods return objects or takes parameters of raw types such as \type{List} or
525\type{Map}. This sometimes results in having to read a lot of source code to
526understand what is going on, instead of relying on the available interfaces. In
527addition, it results in a lot of ugly code, making the use of typecasting more
528of a rule than an exception.
529
530\subsection{Composite Refactorings Will Not Appear as Atomic Actions}
531
532\subsubsection{Missing Flexibility from JDT Refactorings}
533The JDT refactorings are not made with composition of refactorings in mind. When
534a JDT refactoring is executed, it assumes that all conditions for it to be
535applied successfully can be found by reading source files that has been
536persisted to disk. They can only operate on the actual source material, and not
537(in-memory) copies thereof. This constitutes a major disadvantage when trying to
538compose refactorings, since if an exception occur in the middle of a sequence of
539refactorings, it can leave the project in a state where the composite
540refactoring was executed only partly. It makes it hard to discard the changes
541done without monitoring and consulting the undo manager, an approach that is not
542bullet proof.
543
544\subsubsection{Broken Undo History}
545When designing a composed refactoring that is to be performed as a sequence of
546refactorings, you would like it to appear as a single change to the workspace.
547This implies that you would also like to be able to undo all the changes done by
548the refactoring in a single step. This is not the way it appears when a sequence
549of JDT refactorings is executed. It leaves the undo history filled up with
550individual undo actions corresponding to every single JDT refactoring in the
551sequence. This problem is not trivial to handle in Eclipse. (See section
552\ref{hacking_undo_history}.)
553
554\section{Wishful Thinking}
80663734 555
80663734 556
b0e80574
EK
557
558\chapter{Composite Refactorings in Eclipse}
559
560\section{A Simple Ad Hoc Model}
561As pointed out in chapter \ref{ch:jdt_refactorings}, the Eclipse JDT refactoring
562model is not very well suited for making composite refactorings. Therefore a
563simple model using changer objects (of type \type{RefaktorChanger}) is used as
564an abstraction layer on top of the existing Eclipse refactorings.
565
566\section{The Extract and Move Method Refactoring}
61420ef7
EK
567%The Extract and Move Method Refactoring is implemented mainly using these
568%classes:
569%\begin{itemize}
570% \item \type{ExtractAndMoveMethodChanger}
571% \item \type{ExtractAndMoveMethodPrefixesExtractor}
572% \item \type{Prefix}
573% \item \type{PrefixSet}
574%\end{itemize}
575
576\subsection{The Building Blocks}
577This is a composite refactoring, and hence is built up using several primitive
578refactorings. These basic building blocks are, as its name implies, the Extract
579Method Refactoring \cite{refactoring} and the Move Method Refactoring
580\cite{refactoring}. In Eclipse, the implementations of these refactorings are
581found in the classes
582\typewithref{org.eclipse.jdt.internal.corext.refactoring.code}{ExtractMethodRefactoring}
583and
584\typewithref{org.eclipse.jdt.internal.corext.refactoring.structure}{MoveInstanceMethodProcessor},
585where the last class is designed to be used together with the processor-based
586\typewithref{org.eclipse.ltk.core.refactoring.participants}{MoveRefactoring}.
587
588\subsubsection{The ExtractMethodRefactoring Class}
589This class is quite simple in its use. The only parameters it requires for
590construction is a compilation
591unit\typeref{org.eclipse.jdt.core.ICompilationUnit}, the offset into the source
592code where the extraction shall start, and the length of the source to be
593extracted. Then you have to set the method name for the new method together with
594which access modifier that shall be used and some not so interesting parameters.
595
596\subsubsection{The MoveInstanceMethodProcessor Class}
597For the Move Method the processor requires a little more advanced input than
598the class for the Extract Method. For construction it requires a method
599handle\typeref{org.eclipse.jdt.core.IMethod} from the Java Model for the method
600that is to be moved. Then the target for the move have to be supplied as the
601variable binding from a chosen variable declaration. In addition to this, one
602have to set some parameters regarding setters/getters and delegation.
603
604To make a whole refactoring from the processor, one have to construct a
605\type{MoveRefactoring} from it.
b0e80574
EK
606
607\subsection{The ExtractAndMoveMethodChanger Class}
61420ef7
EK
608The \typewithref{no.uio.ifi.refaktor.changers}{ExtractAndMoveMethodChanger}
609class, that is a subclass of the class
610\typewithref{no.uio.ifi.refaktor.changers}{RefaktorChanger}, is the class
611responsible for composing the \type{ExtractMethodRefactoring} and the
612\type{MoveRefactoring}. Its constructor takes a project
613handle\typeref{org.eclipse.core.resources.IProject}, the method name for the new
614method and a \typewithref{no.uio.ifi.refaktor.utils}{SmartTextSelection}.
615
616A \type{SmartTextSelection} is basically a text
617selection\typeref{org.eclipse.jface.text.ITextSelection} object that enforces
618the providing of the underlying document during creation. I.e. its
619\methodwithref{no.uio.ifi.refaktor.utils.SmartTextSelection}{getDocument} method
620will never return \type{null}.
621
622Before extracting the new method, the possible targets for the move operation is
623found with the help of an
624\typewithref{no.uio.ifi.refaktor.extractors}{ExtractAndMoveMethodPrefixesExtractor}.
72b64328
EK
625The possible targets is computed from the prefixes that the extractor returns
626from its
61420ef7
EK
627\methodwithref{no.uio.ifi.refaktor.extractors.ExtractAndMoveMethodPrefixesExtractor}{getSafePrefixes}
628method. The changer then choose the most suitable target by finding the most
72b64328
EK
629frequent occurring prefix among the safe ones. The target is the type of the
630first part of the prefix.
61420ef7
EK
631
632After finding a suitable target, the \type{ExtractAndMoveMethodChanger} first
633creates an \type{ExtractMethodRefactoring} and performs it as explained in
634section \ref{executing_refactoring} about the execution of refactorings. Then it
635creates and performs the \type{MoveRefactoring} in the same way, based on the
636changes done by the Extract Method refactoring.
637
b0e80574 638\subsection{The ExtractAndMoveMethodPrefixesExtractor Class}
61420ef7 639This extractor extracts properties needed for building the Extract and Move
72b64328
EK
640Method refactoring. It searches through the given selection to find safe
641prefixes, and those prefixes form a base that can be used to compute possible
642targets for the move part of the refactoring. It finds both the candidates, in
643the form of prefixes, and the non-candidates, called unfixes. All prefixes (and
644unfixes) are represented by a
645\typewithref{no.uio.ifi.refaktor.extractors}{Prefix}, and they are collected
646into prefix sets.\typeref{no.uio.ifi.refaktor.extractors.PrefixSet}.
647
648The prefixes and unfixes are found by property
649collectors\typeref{no.uio.ifi.refaktor.extractors.collectors.PropertyCollector}.
650A property collector follows the visitor pattern \cite{dp} and is of the
651\typewithref{org.eclipse.jdt.core.dom}{ASTVisitor} type. An \type{ASTVisitor}
652visits nodes in an abstract syntax tree that forms the Java document object
653model. The tree consists of nodes of type
654\typewithref{org.eclipse.jdt.core.do}{ASTNode}.
655
656\subsubsection{The PrefixesCollector}
657The \typewithref{no.uio.ifi.refaktor.extractors.collectors}{PrefixesCollector}
658is of type \type{PropertyCollector}. It visits expression
659statements\typeref{org.eclipse.jdt.core.dom.ExpressionStatement} and creates
660prefixes from its expressions in the case of method invocations. The prefixes
661found is registered with a prefix set, together with all its sub-prefixes.
662\todo{Rewrite in the case of changes to the way prefixes are found}
663
664\subsubsection{The UnfixesCollector}
665The \typewithref{no.uio.ifi.refaktor.extractors.collectors}{UnfixesCollector}
666finds unfixes within the selection. An unfix is a name that is assigned to
667within the selection. The reason that this cannot be allowed, is that the result
668would be an assignment to the \type{this} keyword, which is not valid in Java.
669
670\subsubsection{Computing Safe Prefixes}
671A safe prefix is a prefix that does not enclose an unfix. A prefix is enclosing
672an unfix if the unfix is in the set of its sub-prefixes. As an example,
673\texttt{``a.b''} is enclosing \texttt{``a''}, as is \texttt{``a''}. The safe
674prefixes is unified in a \type{PrefixSet} and can be fetched calling the
675\method{getSafePrefixes} method of the
676\type{ExtractAndMoveMethodPrefixesExtractor}.
61420ef7 677
b0e80574 678\subsection{The Prefix Class}
72b64328 679\todo{?}
b0e80574
EK
680\subsection{The PrefixSet Class}
681
5837a41f
EK
682\subsection{Hacking the Refactoring Undo
683History}\label{hacking_undo_history}
8fae7b44
EK
684\todo{Where to put this section?}
685
686As an attempt to make multiple subsequent changes to the workspace appear as a
687single action (i.e. make the undo changes appear as such), I tried to alter
688the undo changes\typeref{org.eclipse.ltk.core.refactoring.Change} in the history
689of the refactorings.
690
691My first impulse was to remove the, in this case, last two undo changes from the
f041551b
EK
692undo manager\typeref{org.eclipse.ltk.core.refactoring.IUndoManager} for the
693Eclipse refactorings, and then add them to a composite
8fae7b44
EK
694change\typeref{org.eclipse.ltk.core.refactoring.CompositeChange} that could be
695added back to the manager. The interface of the undo manager does not offer a
696way to remove/pop the last added undo change, so a possible solution could be to
697decorate \cite{dp} the undo manager, to intercept and collect the undo changes
f041551b
EK
698before delegating to the \method{addUndo}
699method\methodref{org.eclipse.ltk.core.refactoring.IUndoManager}{addUndo} of the
8fae7b44
EK
700manager. Instead of giving it the intended undo change, a null change could be
701given to prevent it from making any changes if run. Then one could let the
702collected undo changes form a composite change to be added to the manager.
703
704There is a technical challenge with this approach, and it relates to the undo
705manager, and the concrete implementation
706UndoManager2\typeref{org.eclipse.ltk.internal.core.refactoring.UndoManager2}.
707This implementation is designed in a way that it is not possible to just add an
708undo change, you have to do it in the context of an active
709operation\typeref{org.eclipse.core.commands.operations.TriggeredOperations}.
710One could imagine that it might be possible to trick the undo manager into
711believing that you are doing a real change, by executing a refactoring that is
712returning a kind of null change that is returning our composite change of undo
713refactorings when it is performed.
714
715Apart from the technical problems with this solution, there is a functional
716problem: If it all had worked out as planned, this would leave the undo history
717in a dirty state, with multiple empty undo operations corresponding to each of
718the sequentially executed refactoring operations, followed by a composite undo
719change corresponding to an empty change of the workspace for rounding of our
720composite refactoring. The solution to this particular problem could be to
721intercept the registration of the intermediate changes in the undo manager, and
722only register the last empty change.
723
724Unfortunately, not everything works as desired with this solution. The grouping
725of the undo changes into the composite change does not make the undo operation
726appear as an atomic operation. The undo operation is still split up into
727separate undo actions, corresponding to the change done by its originating
728refactoring. And in addition, the undo actions has to be performed separate in
729all the editors involved. This makes it no solution at all, but a step toward
730something worse.
731
732There might be a solution to this problem, but it remains to be found. The
733design of the refactoring undo management is partly to be blamed for this, as it
734it is to complex to be easily manipulated.
735
b0e80574 736
9ff90080
EK
737\backmatter{}
738\printbibliography
055dca93 739\listoftodos
9ff90080 740\end{document}