]>
Commit | Line | Data |
---|---|---|
7c28933b | 1 | \documentclass[USenglish]{ifimaster} |
571ef294 | 2 | \usepackage{import} |
7c28933b | 3 | \usepackage[utf8]{inputenc} |
9ff90080 | 4 | \usepackage[T1]{fontenc,url} |
3510e539 | 5 | \usepackage{lmodern} % using Latin Modern to be able to use bold typewriter font |
9ff90080 | 6 | \urlstyle{sf} |
571ef294 | 7 | \usepackage{babel,textcomp,csquotes,ifimasterforside,varioref,graphicx} |
84fe308b | 8 | \usepackage[style=numeric-comp,backend=bibtex]{biblatex} |
12c254af | 9 | \usepackage{amsthm} |
00aa0588 | 10 | \usepackage{todonotes} |
b289552b | 11 | \usepackage{verbatim} |
ddcea0b5 EK |
12 | \usepackage{minted} |
13 | \usemintedstyle{bw} | |
8fae7b44 EK |
14 | \usepackage{perpage} %the perpage package |
15 | \MakePerPage{footnote} %the perpage package command | |
9ff90080 | 16 | |
12c254af EK |
17 | \theoremstyle{plain} |
18 | \newtheorem*{wordDef}{Definition} | |
19 | ||
ddcea0b5 EK |
20 | \graphicspath{ {./figures/} } |
21 | ||
12c254af | 22 | \newcommand{\definition}[1]{\begin{wordDef}#1\end{wordDef}} |
b01d328a | 23 | \newcommand{\see}[1]{(see section \ref{#1})} |
137e0e7b EK |
24 | \newcommand{\explanation}[3]{\noindent\textbf{\textit{#1}}\\*\emph{When:} |
25 | #2\\*\emph{How:} #3\\*[-7px]} | |
3510e539 | 26 | \newcommand{\type}[1]{\texttt{\textbf{#1}}} |
f041551b EK |
27 | \newcommand{\typeref}[1]{\footnote{\type{#1}}} |
28 | \newcommand{\typewithref}[2]{\type{#2}\typeref{#1.#2}} | |
29 | \newcommand{\method}[1]{\type{#1}} | |
30 | \newcommand{\methodref}[2]{\footnote{\type{#1}\method{\##2()}}} | |
31 | \newcommand{\methodwithref}[2]{\method{#2}\footnote{\type{#1}\method{\##2()}}} | |
3510e539 | 32 | \newcommand{\var}[1]{\type{#1}} |
9ff90080 | 33 | |
7c28933b EK |
34 | |
35 | \title{Refactoring} | |
84fe308b | 36 | \subtitle{An unfinished essay} |
7c28933b EK |
37 | \author{Erlend Kristiansen} |
38 | ||
39 | \bibliography{bibliography/master-thesis-erlenkr-bibliography} | |
9ff90080 EK |
40 | |
41 | \begin{document} | |
531c4132 | 42 | \ififorside |
9ff90080 | 43 | \frontmatter{} |
9ff90080 EK |
44 | |
45 | ||
46 | \chapter*{Abstract} | |
47 | Empty document. | |
48 | ||
49 | \tableofcontents{} | |
50 | \listoffigures{} | |
51 | \listoftables{} | |
52 | ||
53 | \chapter*{Preface} | |
54 | ||
f3a108c3 EK |
55 | To make it clear already from the beginning: The discussions in this report must |
56 | be seen in the context of object oriented programming languages, and Java in | |
57 | particular, since that is the language in which most of the examples will be | |
58 | given. All though the techniques discussed may be applicable to languages from | |
59 | other paradigms, they will not be the subject of this report. | |
60 | ||
055dca93 | 61 | \mainmatter |
00aa0588 | 62 | |
740e1b6c | 63 | \chapter{What is Refactoring?} |
7c28933b | 64 | |
f3a108c3 EK |
65 | This question is best answered by first defining the concept of a |
66 | \emph{refactoring}, what it is to \emph{refactor}, and then discuss what aspects | |
67 | of programming that make people want to refactor their code. | |
00aa0588 | 68 | |
740e1b6c | 69 | \section{Defining refactoring} |
8fae7b44 | 70 | Martin Fowler, in his masterpiece on refactoring \cite{refactoring}, defines a |
00aa0588 | 71 | refactoring like this: |
ee45c41f | 72 | |
00aa0588 EK |
73 | \begin{quote} |
74 | \emph{Refactoring} (noun): a change made to the \todo{what does he mean by | |
75 | internal?} internal structure of software to make it easier to understand and | |
76 | cheaper to modify without changing its observable | |
8fae7b44 | 77 | behavior.~\cite{refactoring} % page 53 |
00aa0588 | 78 | \end{quote} |
ee45c41f EK |
79 | |
80 | \noindent This definition assign additional meaning to the word | |
81 | \emph{refactoring}, beyond the composition of the prefix \emph{re-}, usually | |
82 | meaning something like ``again'' or ``anew'', and the word \emph{factoring}, | |
83 | that can mean to determine the \emph{factors} of something. Where a | |
84 | \emph{factor} would be close to the mathematical definition of something that | |
85 | divides a quantity, without leaving a remainder. Fowler is mixing the | |
86 | \emph{motivation} behind refactoring into his definition. Instead it could be | |
87 | made clean, only considering the mechanical and behavioral aspects of | |
88 | refactoring. That is to factor the program again, putting it together in a | |
89 | different way than before, while preserving the behavior of the program. An | |
90 | alternative definition could then be: | |
51a854d4 | 91 | |
51a854d4 | 92 | \definition{A refactoring is a transformation |
8fae7b44 | 93 | done to a program without altering its external behavior.} |
00aa0588 | 94 | |
ee1d883a EK |
95 | From this we can conclude that a refactoring primarily changes how the |
96 | \emph{code} of a program is perceived by the \emph{programmer}, and not the | |
740e1b6c EK |
97 | \emph{behavior} experienced by any user of the program. Although the logical |
98 | meaning is preserved, such changes could potentially alter the program's | |
99 | behavior when it comes to performance gain or -penalties. So any logic depending | |
100 | on the performance of a program could make the program behave differently after | |
101 | a refactoring. | |
00aa0588 | 102 | |
137e0e7b EK |
103 | In the extreme case one could argue that such a thing as \emph{software |
104 | obfuscation} is to refactor. If we where to define it as a refactoring, it could | |
105 | be defined as a composite refactoring \see{intro_composite}, consisting of, for | |
106 | instance, a series of rename refactorings. (But it could of course be much more | |
107 | complex, and the mechanics of it would not exactly be carved in stone.) To | |
108 | perform some serious obfuscation one would also take advantage of techniques not | |
109 | found among established refactorings, such as removing whitespace. This might | |
110 | not even generate a different syntax tree for languages not sensitive to | |
ee1d883a | 111 | whitespace, placing it in the gray area of what kind of transformations is to be |
137e0e7b | 112 | considered refactorings. |
00aa0588 EK |
113 | |
114 | Finally, to \emph{refactor} is (quoting Martin Fowler) | |
7c28933b EK |
115 | \begin{quote} |
116 | \ldots to restructure software by applying a series of refactorings without | |
8fae7b44 | 117 | changing its observable behavior.~\cite{refactoring} % page 54, definition |
7c28933b EK |
118 | \end{quote} |
119 | ||
740e1b6c | 120 | \section{The etymology of 'refactoring'} |
f3a108c3 EK |
121 | It is a little difficult to pinpoint the exact origin of the word |
122 | ``refactoring'', as it seems to have evolved as part of a colloquial | |
123 | terminology, more than a scientific term. There is no authoritative source for a | |
124 | formal definition of it. | |
125 | ||
126 | According to Martin Fowler~\cite{etymology-refactoring}, there may also be more | |
127 | than one origin of the word. The most well-known source, when it comes to the | |
128 | origin of \emph{refactoring}, is the Smalltalk\footnote{\emph{Smalltalk}, | |
129 | object-oriented, dynamically typed, reflective programming language.}\todo{find | |
130 | reference to Smalltalk website or similar?} community and their infamous | |
131 | \emph{Refactoring | |
132 | Browser}\footnote{\url{http://st-www.cs.illinois.edu/users/brant/Refactory/RefactoringBrowser.html}} | |
133 | described in the article \emph{A Refactoring Tool for | |
134 | Smalltalk}~\cite{refactoringBrowser1997}, published in 1997. | |
135 | Allegedly~\cite{etymology-refactoring}, the metaphor of factoring programs was | |
136 | also present in the Forth\footnote{\emph{Forth} -- stack-based, extensible | |
137 | programming language, without type-checking. See \url{http://www.forth.org}} | |
138 | community, and the word ``refactoring'' is mentioned in a book by Leo Brodie, | |
139 | called \emph{Thinking Forth}~\cite{brodie1984}, first published in | |
140 | 1984\footnote{\emph{Thinking Forth} was first published in 1984 by the | |
141 | \emph{Forth Interest Group}. Then it was reprinted in 1994 with minor | |
142 | typographical corrections, before it was transcribed into an electronic edition | |
143 | typeset in \LaTeX\ and published under a Creative Commons licence in 2004. The | |
144 | edition cited here is the 2004 edition, but the content should essentially be as | |
145 | in 1984.}. The exact word is only printed one place\footnote{p. 232}, but the | |
146 | term \emph{factoring} is prominent in the book, that also contains a whole | |
147 | chapter dedicated to (re)factoring, and how to keep the (Forth) code clean and | |
148 | maintainable. | |
ee45c41f | 149 | |
f3a108c3 EK |
150 | \begin{quote} |
151 | \ldots good factoring technique is perhaps the most important skill for a | |
152 | Forth programmer.~\cite{brodie1984} | |
153 | \end{quote} | |
ee45c41f EK |
154 | |
155 | \noindent Brodie also express what \emph{factoring} means to him: | |
156 | ||
f3a108c3 EK |
157 | \begin{quote} |
158 | Factoring means organizing code into useful fragments. To make a fragment | |
159 | useful, you often must separate reusable parts from non-reusable parts. The | |
160 | reusable parts become new definitions. The non-reusable parts become arguments | |
161 | or parameters to the definitions.~\cite{brodie1984} | |
162 | \end{quote} | |
163 | ||
164 | Fowler claims that the usage of the word \emph{refactoring} did not pass between | |
165 | the \emph{Forth} and \emph{Smalltalk} communities, but that it emerged | |
166 | independently in each of the communities. | |
167 | ||
740e1b6c EK |
168 | \todo{more history?} |
169 | ||
170 | \section{Motivation -- Why people refactor} | |
171 | To get a grasp of what refactoring is all about, we can try to answer this | |
172 | question: \emph{Why do people refactor?} Possible answers could include: ``To | |
173 | remove duplication'' or ``to break up long methods''. Practitioners of the art | |
174 | of Design Patterns~\cite{dp} could say that they do it to introduce a | |
b01d328a | 175 | long-needed pattern into their program's design. So it is safe to say that |
740e1b6c EK |
176 | peoples' intentions are to make their programs \emph{better} in some sense. But |
177 | what aspects of the programs are becoming improved? | |
51a854d4 EK |
178 | |
179 | As already mentioned, people often refactor to get rid of duplication. Moving | |
00aa0588 | 180 | identical or similar code into methods, and maybe pushing those up or down in |
740e1b6c EK |
181 | their class hierarchies. Making template methods for overlapping |
182 | algorithms/functionality and so on. It's all about gathering what belongs | |
00aa0588 | 183 | together and putting it all in one place. And the result? The code is easier to |
137e0e7b EK |
184 | maintain. When removing the implicit coupling between the code snippets, the |
185 | location of a bug is limited to only one place, and new functionality need only | |
186 | to be added this one place, instead of a number of places people might not even | |
187 | remember. | |
51a854d4 EK |
188 | |
189 | The same people find out that their program contains a lot of long and | |
190 | hard-to-grasp methods. Then what do they do? They begin dividing their methods | |
00aa0588 EK |
191 | into smaller ones, using the \emph{Extract Method} |
192 | refactoring~\cite{refactoring}. Then they may discover something about their | |
193 | program that they weren't aware of before; revealing bugs they didn't know about | |
194 | or couldn't find due to the complex structure of their program. \todo{Proof?} | |
195 | Making the methods smaller and giving good names to the new ones clarifies the | |
b01d328a EK |
196 | algorithms and enhances the \emph{understandability} of the program |
197 | \see{magic_number_seven}. This makes simple refactoring an excellent method for | |
198 | exploring unknown program code, or code that you had forgotten that you wrote! | |
51a854d4 | 199 | |
f65da046 | 200 | The word \emph{simple} came up in the last section. In fact, most primitive |
51a854d4 | 201 | refactorings are simple. The true power of them are revealed first when they are |
137e0e7b | 202 | combined into larger --- higher level --- refactorings, called \emph{composite |
8fae7b44 | 203 | refactorings} \see{intro_composite}. Often the goal of such a series of |
137e0e7b EK |
204 | refactorings is a design pattern. Thus the \emph{design} can be evolved |
205 | throughout the lifetime of a program, opposed to designing up-front. It's all | |
b01d328a | 206 | about being structured and taking small steps to improve a program's design. |
51a854d4 EK |
207 | |
208 | Many refactorings are aimed at lowering the coupling between different classes | |
b01d328a EK |
209 | and different layers of logic. \todo{which refactorings?} Say for instance that |
210 | the coupling between the user interface and the business logic of a program is | |
211 | lowered. Then the business logic of the program could much easier be the target | |
212 | of automated tests, increasing the productivity in the software development | |
213 | process. It is also easier to distribute (e.g. between computers) the different | |
214 | components of a program if they are sufficiently decoupled. | |
0b0567f2 EK |
215 | |
216 | Another effect of refactoring is that with the increased separation of concerns | |
137e0e7b EK |
217 | coming out of many refactorings, the \emph{performance} is improved. When |
218 | profiling programs, the problem parts are narrowed down to smaller parts of the | |
219 | code, which are easier to tune, and optimization can be performed only where | |
220 | needed and in a more effective way. | |
221 | ||
b01d328a EK |
222 | Last, but not least, and this should probably be the best reason to refactor, is |
223 | to refactor to \emph{facilitate a program change}. If one has managed to keep | |
224 | one's code clean and tidy, and the code is not bloated with design patterns that | |
225 | is not ever going to be needed, then some refactoring might be needed to | |
226 | introduce a design pattern that is appropriate for the change that is going to | |
227 | happen. | |
228 | ||
137e0e7b EK |
229 | Refactoring program code --- with a goal in mind --- can give the code itself |
230 | more value. That is in the form of robustness to bugs, understandability and | |
231 | maintainability. With the first as an obvious advantage, but with the following | |
ee1d883a | 232 | two being also very important for software development. By incorporating |
00aa0588 EK |
233 | refactoring in the development process, bugs are found faster, new functionality |
234 | is added more easily and code is easier to understand by the next person exposed | |
ee1d883a EK |
235 | to it, which might as well be the person who wrote it. The consequence of this, |
236 | is that refactoring can increase the average productivity of the development | |
237 | process, and thus also add to the monetary value of a business in the long run. | |
238 | Where this last point also should open the eyes of some nearsighted managers who | |
239 | seldom see beyond the next milestone. | |
137e0e7b | 240 | |
b01d328a | 241 | \section{The magical number seven}\label{magic_number_seven} |
f4cea2d6 EK |
242 | \emph{The magical number seven, plus or minus two: some limits on our capacity |
243 | for processing information}~\cite{miller1956} is an article by George A. Miller | |
244 | that was published in the journal \emph{Psychological Review} in 1956. It | |
245 | presents evidence that support that the capacity of the number of objects a | |
246 | human being can hold in its working memory is roughly seven, plus or minus two | |
247 | objects. This number varies a bit depending on the nature and complexity of the | |
248 | objects, but is according to Miller ``\ldots never changing so much as to be | |
249 | unrecognizable.'' | |
250 | ||
251 | Miller's article culminates in the section called \emph{Recoding}, a term he | |
252 | borrows from communication theory. The central result in this section is that by | |
253 | recoding information, the capacity of the amount of information that a human can | |
254 | process at a time is increased. By \emph{recoding}, Miller means to group | |
255 | objects together in chunks and give each chunk a new name that it can be | |
256 | remembered by. By organizing objects into patterns of ever growing depth, one | |
257 | can memorize and process a much larger amount of data than if it were to be | |
258 | represented as its basic pieces. This grouping and renaming is analogous to how | |
259 | many refactorings work, by grouping pieces of code and give them a new name. | |
260 | Examples are the central \emph{Extract Method} and \emph{Extract Class} | |
261 | refactorings~\cite{refactoring}. | |
262 | ||
263 | \begin{quote} | |
264 | \ldots recoding is an extremely powerful weapon for increasing the amount of | |
265 | information that we can deal with.~\cite{miller1956} | |
266 | \end{quote} | |
ee45c41f | 267 | |
f4cea2d6 EK |
268 | An example from the article address the problem of memorizing a sequence of |
269 | binary digits. Let us say we have the following sequence\footnote{The example | |
270 | presented here is slightly modified (and shortened) from what is presented in | |
271 | the original article~\cite{miller1956}, but it is essentially the same.} of | |
272 | 16 binary digits: ``1010001001110011''. Most of us will have a hard time | |
273 | memorizing this sequence by only reading it once or twice. Imagine if we instead | |
274 | translate it to this sequence: ``A273''. If you have a background from computer | |
275 | science, it will be obvious that the latest sequence is the first sequence | |
276 | recoded to be represented by digits with base 16. Most people should be able to | |
277 | memorize this last sequence by only looking at it once. | |
278 | ||
279 | Another result from the Miller article is that when the amount of information a | |
280 | human must interpret increases, it is crucial that the translation from one code | |
281 | to another must be almost automatic for the subject to be able to remember the | |
282 | translation, before he or she is presented with new information to recode. Thus | |
283 | learning and understanding how to best organize certain kinds of data is | |
284 | essential to efficiently handle that kind of data in the future. This is much | |
285 | like when children learn to read. First they must learn how to recognize | |
286 | letters. Then they can learn distinct words, and later read sequences of words | |
287 | that form whole sentences. Eventually, most of them will be able to read whole | |
288 | books and briefly retell the important parts of its content. This suggest that | |
289 | the use of design patterns~\cite{dp} is a good idea when reasoning about | |
290 | computer programs. With extensive use of design patterns when creating complex | |
291 | program structures, one does not always have to read whole classes of code to | |
292 | comprehend how they function, it may be sufficient to only see the name of a | |
293 | class to almost fully understand its responsibilities. | |
294 | ||
295 | \begin{quote} | |
296 | Our language is tremendously useful for repackaging material into a few chunks | |
297 | rich in information.~\cite{miller1956} | |
298 | \end{quote} | |
ee45c41f | 299 | |
f4cea2d6 EK |
300 | Without further evidence, these results at least indicates that refactoring |
301 | source code into smaller units with higher cohesion and, when needed, | |
302 | introducing appropriate design patterns, should aid in the cause of creating | |
303 | computer programs that are easier to maintain and has code that is easier (and | |
304 | better) understood. | |
305 | ||
740e1b6c | 306 | \section{Notable contributions to the refactoring literature} |
d21ef41f EK |
307 | \todo{Update with more contributions} |
308 | \begin{description} | |
309 | \item[1992] William F. Opdyke submits his doctoral dissertation called | |
310 | \emph{Refactoring Object-Oriented Frameworks}~\cite{opdyke1992}. This | |
311 | work defines a set of refactorings, that are behavior preserving given that | |
312 | their preconditions are met. The dissertation is focused on the automation | |
313 | of refactorings. | |
314 | \item[1999] Martin Fowler et al.: \emph{Refactoring: Improving the Design of | |
315 | Existing Code}~\cite{refactoring}. This is maybe the most influential text | |
316 | on refactoring. It bares similarities with Opdykes thesis~\cite{opdyke1992} | |
317 | in the way that it provides a catalog of refactorings. But Fowler's book is | |
318 | more about the craft of refactoring, as he focuses on establishing a | |
319 | vocabulary for refactoring, together with the mechanics of different | |
320 | refactorings and when to perform them. His methodology is also founded on | |
321 | the principles of test-driven development. | |
f3a108c3 | 322 | \item[todo] \emph{Refactoring to Patterns}\todo{include} |
d21ef41f | 323 | \end{description} |
3b7c1d90 EK |
324 | |
325 | \section{Tool support} | |
326 | \todo{write, section vs. subsection} | |
327 | ||
328 | \section{Relation to design patterns} | |
f3a108c3 | 329 | \todo{write, section vs. subsection, refactoring to patterns?} |
b289552b EK |
330 | \begin{comment} |
331 | ||
137e0e7b EK |
332 | \section{Classification of refactorings} |
333 | % only interesting refactorings | |
334 | % with 2 detailed examples? One for structured and one for intra-method? | |
335 | % Is replacing Bubblesort with Quick Sort considered a refactoring? | |
336 | ||
337 | \subsection{Structural refactorings} | |
338 | ||
f65da046 | 339 | \subsubsection{Primitive refactorings} |
137e0e7b EK |
340 | |
341 | % Composing Methods | |
342 | \explanation{Extract Method}{You have a code fragment that can be grouped | |
343 | together.}{Turn the fragment into a method whose name explains the purpose of | |
344 | the method.} | |
345 | ||
346 | \explanation{Inline Method}{A method's body is just as clear as its name.}{Put | |
347 | the method's body into the body of its callers and remove the method.} | |
348 | ||
349 | \explanation{Inline Temp}{You have a temp that is assigned to once with a simple | |
350 | expression, and the temp is getting in the way of other refactorings.}{Replace | |
351 | all references to that temp with the expression} | |
352 | ||
353 | % Moving Features Between Objects | |
354 | \explanation{Move Method}{A method is, or will be, using or used by more | |
355 | features of another class than the class on which it is defined.}{Create a new | |
356 | method with a similar body in the class it uses most. Either turn the old method | |
357 | into a simple delegation, or remove it altogether.} | |
358 | ||
359 | \explanation{Move Field}{A field is, or will be, used by another class more than | |
360 | the class on which it is defined}{Create a new field in the target class, and | |
361 | change all its users.} | |
362 | ||
363 | % Organizing Data | |
364 | \explanation{Replace Magic Number with Symbolic Constant}{You have a literal | |
365 | number with a particular meaning.}{Create a constant, name it after the meaning, | |
366 | and replace the number with it.} | |
367 | ||
368 | \explanation{Encapsulate Field}{There is a public field.}{Make it private and | |
369 | provide accessors.} | |
370 | ||
371 | \explanation{Replace Type Code with Class}{A class has a numeric type code that | |
8fae7b44 | 372 | does not affect its behavior.}{Replace the number with a new class.} |
137e0e7b EK |
373 | |
374 | \explanation{Replace Type Code with Subclasses}{You have an immutable type code | |
8fae7b44 | 375 | that affects the behavior of a class.}{Replace the type code with subclasses.} |
137e0e7b EK |
376 | |
377 | \explanation{Replace Type Code with State/Strategy}{You have a type code that | |
8fae7b44 | 378 | affects the behavior of a class, but you cannot use subclassing.}{Replace the |
137e0e7b EK |
379 | type code with a state object.} |
380 | ||
381 | % Simplifying Conditional Expressions | |
382 | \explanation{Consolidate Duplicate Conditional Fragments}{The same fragment of | |
8fae7b44 | 383 | code is in all branches of a conditional expression.}{Move it outside of the |
137e0e7b EK |
384 | expression.} |
385 | ||
386 | \explanation{Remove Control Flag}{You have a variable that is acting as a | |
387 | control flag fro a series of boolean expressions.}{Use a break or return | |
388 | instead.} | |
389 | ||
390 | \explanation{Replace Nested Conditional with Guard Clauses}{A method has | |
8fae7b44 | 391 | conditional behavior that does not make clear the normal path of |
137e0e7b EK |
392 | execution.}{Use guard clauses for all special cases.} |
393 | ||
8fae7b44 | 394 | \explanation{Introduce Null Object}{You have repeated checks for a null |
137e0e7b EK |
395 | value.}{Replace the null value with a null object.} |
396 | ||
397 | \explanation{Introduce Assertion}{A section of code assumes something about the | |
398 | state of the program.}{Make the assumption explicit with an assertion.} | |
399 | ||
400 | % Making Method Calls Simpler | |
401 | \explanation{Rename Method}{The name of a method does not reveal its | |
402 | purpose.}{Change the name of the method} | |
403 | ||
404 | \explanation{Add Parameter}{A method needs more information from its | |
405 | caller.}{Add a parameter for an object that can pass on this information.} | |
406 | ||
407 | \explanation{Remove Parameter}{A parameter is no longer used by the method | |
408 | body.}{Remove it.} | |
409 | ||
410 | %\explanation{Parameterize Method}{Several methods do similar things but with | |
411 | %different values contained in the method.}{Create one method that uses a | |
412 | %parameter for the different values.} | |
413 | ||
414 | \explanation{Preserve Whole Object}{You are getting several values from an | |
415 | object and passing these values as parameters in a method call.}{Send the whole | |
416 | object instead.} | |
417 | ||
418 | \explanation{Remove Setting Method}{A field should be set at creation time and | |
419 | never altered.}{Remove any setting method for that field.} | |
420 | ||
421 | \explanation{Hide Method}{A method is not used by any other class.}{Make the | |
422 | method private.} | |
423 | ||
8fae7b44 EK |
424 | \explanation{Replace Constructor with Factory Method}{You want to do more than |
425 | simple construction when you create an object}{Replace the constructor with a | |
137e0e7b EK |
426 | factory method.} |
427 | ||
428 | % Dealing with Generalization | |
8fae7b44 | 429 | \explanation{Pull Up Field}{Two subclasses have the same field.}{Move the field |
137e0e7b EK |
430 | to the superclass.} |
431 | ||
432 | \explanation{Pull Up Method}{You have methods with identical results on | |
433 | subclasses.}{Move them to the superclass.} | |
434 | ||
8fae7b44 | 435 | \explanation{Push Down Method}{Behavior on a superclass is relevant only for |
137e0e7b EK |
436 | some of its subclasses.}{Move it to those subclasses.} |
437 | ||
438 | \explanation{Push Down Field}{A field is used only by some subclasses.}{Move the | |
439 | field to those subclasses} | |
440 | ||
441 | \explanation{Extract Interface}{Several clients use the same subset of a class's | |
8fae7b44 | 442 | interface, or two classes have part of their interfaces in common.}{Extract the |
137e0e7b EK |
443 | subset into an interface.} |
444 | ||
445 | \explanation{Replace Inheritance with Delegation}{A subclass uses only part of a | |
446 | superclasses interface or does not want to inherit data.}{Create a field for the | |
447 | superclass, adjust methods to delegate to the superclass, and remove the | |
448 | subclassing.} | |
449 | ||
450 | \explanation{Replace Delegation with Inheritance}{You're using delegation and | |
451 | are often writing many simple delegations for the entire interface}{Make the | |
452 | delegating class a subclass of the delegate.} | |
453 | ||
454 | \subsubsection{Composite refactorings} | |
455 | ||
456 | % Composing Methods | |
457 | % \explanation{Replace Method with Method Object}{}{} | |
458 | ||
459 | % Moving Features Between Objects | |
460 | \explanation{Extract Class}{You have one class doing work that should be done by | |
461 | two}{Create a new class and move the relevant fields and methods from the old | |
462 | class into the new class.} | |
463 | ||
464 | \explanation{Inline Class}{A class isn't doing very much.}{Move all its features | |
465 | into another class and delete it.} | |
466 | ||
467 | \explanation{Hide Delegate}{A client is calling a delegate class of an | |
468 | object.}{Create Methods on the server to hide the delegate.} | |
469 | ||
470 | \explanation{Remove Middle Man}{A class is doing to much simple delegation.}{Get | |
471 | the client to call the delegate directly.} | |
472 | ||
473 | % Organizing Data | |
474 | \explanation{Replace Data Value with Object}{You have a data item that needs | |
8fae7b44 | 475 | additional data or behavior.}{Turn the data item into an object.} |
137e0e7b EK |
476 | |
477 | \explanation{Change Value to Reference}{You have a class with many equal | |
478 | instances that you want to replace with a single object.}{Turn the object into a | |
479 | reference object.} | |
480 | ||
481 | \explanation{Encapsulate Collection}{A method returns a collection}{Make it | |
8fae7b44 | 482 | return a read-only view and provide add/remove methods.} |
137e0e7b EK |
483 | |
484 | % \explanation{Replace Array with Object}{}{} | |
485 | ||
486 | \explanation{Replace Subclass with Fields}{You have subclasses that vary only in | |
487 | methods that return constant data.}{Change the methods to superclass fields and | |
488 | eliminate the subclasses.} | |
489 | ||
490 | % Simplifying Conditional Expressions | |
491 | \explanation{Decompose Conditional}{You have a complicated conditional | |
492 | (if-then-else) statement.}{Extract methods from the condition, then part, an | |
493 | else part.} | |
494 | ||
495 | \explanation{Consolidate Conditional Expression}{You have a sequence of | |
496 | conditional tests with the same result.}{Combine them into a single conditional | |
497 | expression and extract it.} | |
498 | ||
499 | \explanation{Replace Conditional with Polymorphism}{You have a conditional that | |
8fae7b44 | 500 | chooses different behavior depending on the type of an object.}{Move each leg |
137e0e7b EK |
501 | of the conditional to an overriding method in a subclass. Make the original |
502 | method abstract.} | |
503 | ||
504 | % Making Method Calls Simpler | |
505 | \explanation{Replace Parameter with Method}{An object invokes a method, then | |
506 | passes the result as a parameter for a method. The receiver can also invoke this | |
507 | method.}{Remove the parameter and let the receiver invoke the method.} | |
508 | ||
509 | \explanation{Introduce Parameter Object}{You have a group of parameters that | |
510 | naturally go together.}{Replace them with an object.} | |
511 | ||
512 | % Dealing with Generalization | |
513 | \explanation{Extract Subclass}{A class has features that are used only in some | |
514 | instances.}{Create a subclass for that subset of features.} | |
515 | ||
516 | \explanation{Extract Superclass}{You have two classes with similar | |
517 | features.}{Create a superclass and move the common features to the | |
518 | superclass.} | |
519 | ||
520 | \explanation{Collapse Hierarchy}{A superclass and subclass are not very | |
521 | different.}{Merge them together.} | |
522 | ||
523 | \explanation{Form Template Method}{You have two methods in subclasses that | |
524 | perform similar steps in the same order, yet the steps are different.}{Get the | |
525 | steps into methods with the same signature, so that the original methods become | |
526 | the same. Then you can pull them up.} | |
527 | ||
528 | ||
529 | \subsection{Functional refactorings} | |
530 | ||
531 | \explanation{Substitute Algorithm}{You want to replace an algorithm with one | |
532 | that is clearer.}{Replace the body of the method with the new algorithm.} | |
00aa0588 | 533 | |
b289552b | 534 | \end{comment} |
00aa0588 EK |
535 | |
536 | \section{The impact on software quality} | |
537 | ||
538 | \subsection{What is meant by quality?} | |
539 | The term \emph{software quality} has many meanings. It all depends on the | |
9a55a5bc EK |
540 | context we put it in. If we look at it with the eyes of a software developer, it |
541 | usually mean that the software is easily maintainable and testable, or in other | |
542 | words, that it is \emph{well designed}. This often correlates with the | |
543 | management scale, where \emph{keeping the schedule} and \emph{customer | |
137e0e7b EK |
544 | satisfaction} is at the center. From the customers point of view, in addition to |
545 | good usability, \emph{performance} and \emph{lack of bugs} is always | |
546 | appreciated, measurements that are also shared by the software developer. (In | |
547 | addition, such things as good documentation could be measured, but this is out | |
548 | of the scope of this document.) | |
9a55a5bc | 549 | |
00aa0588 | 550 | \subsection{The impact on performance} |
9a55a5bc EK |
551 | \begin{quote} |
552 | Refactoring certainly will make software go more slowly, but it also makes the | |
00aa0588 | 553 | software more amenable to performance tuning.~\cite{refactoring} % page 69 |
9a55a5bc | 554 | \end{quote} |
ee45c41f EK |
555 | |
556 | \noindent There is a common belief that refactoring compromises performance, due | |
557 | to increased degree of indirection and that polymorphism is slower than | |
9a55a5bc EK |
558 | conditionals. |
559 | ||
00aa0588 | 560 | In a survey, Demeyer~\cite{demeyer2002} disproves this view in the case of |
9a55a5bc EK |
561 | polymorphism. He is doing an experiment on, what he calls, ``Transform Self Type |
562 | Checks'' where you introduce a new polymorphic method and a new class hierarchy | |
563 | to get rid of a class' type checking of a ``type attribute``. He uses this kind | |
564 | of transformation to represent other ways of replacing conditionals with | |
565 | polymorphism as well. The experiment is performed on the C++ programming | |
00aa0588 EK |
566 | language and with three different compilers and platforms. \todo{But is the |
567 | result better?} Demeyer concludes that, with compiler optimization turned on, | |
568 | polymorphism beats middle to large sized if-statements and does as well as | |
569 | case-statements. (In accordance with his hypothesis, due to similarities | |
570 | between the way C++ handles polymorphism and case-statements.) | |
ee45c41f | 571 | |
9a55a5bc EK |
572 | \begin{quote} |
573 | The interesting thing about performance is that if you analyze most programs, | |
574 | you find that they waste most of their time in a small fraction of the code. | |
00aa0588 | 575 | ~\cite{refactoring} |
9a55a5bc | 576 | \end{quote} |
9a55a5bc | 577 | |
ee45c41f EK |
578 | \noindent So, although an increased amount of method calls could potentially |
579 | slow down programs, one should avoid premature optimization and sacrificing good | |
580 | design, leaving the performance tuning until after profiling\footnote{For and | |
581 | example of a Java profiler, check out VisualVM: | |
582 | \url{http://visualvm.java.net/}} the software and having isolated the actual | |
583 | problem areas. | |
00aa0588 | 584 | |
00aa0588 | 585 | \section{Composite refactorings} \label{intro_composite} |
f3a108c3 EK |
586 | \todo{motivation, examples, manual vs automated?, what about refactoring in a |
587 | very large code base?} | |
6065c96c | 588 | Generally, when thinking about refactoring, at the mechanical level, there are |
f65da046 EK |
589 | essentially two kinds of refactorings. There are the \emph{primitive} |
590 | refactorings, and the \emph{composite} refactorings. A primitive refactoring can | |
6065c96c EK |
591 | be defined like this: |
592 | ||
f65da046 EK |
593 | \definition{A primitive refactoring is a refactoring that cannot be expressed in |
594 | terms of other refactorings.} | |
595 | ||
ee45c41f | 596 | \noindent Examples are the \emph{Pull Up Field} and \emph{Pull Up Method} |
f65da046 | 597 | refactorings~\cite{refactoring}, that moves members up in their class |
ee45c41f EK |
598 | hierarchies. |
599 | ||
600 | A composite refactoring is more complex, and can be defined like this: | |
f65da046 | 601 | |
6065c96c | 602 | \definition{A composite refactoring is a refactoring that can be expressed in |
f65da046 EK |
603 | terms of two or more primitive refactorings.} |
604 | ||
ee45c41f | 605 | \noindent An example of a composite refactoring is the \emph{Extract Superclass} |
6065c96c | 606 | refactoring~\cite{refactoring}. In its simplest form, it is composed of the |
f65da046 | 607 | previously described primitive refactorings, in addition to the \emph{Pull Up |
6065c96c EK |
608 | Constructor Body} refactoring~\cite{refactoring}. It works by creating an |
609 | abstract superclass that the target class(es) inherits from, then by applying | |
610 | \emph{Pull Up Field}, \emph{Pull Up Method} and \emph{Pull Up Constructor Body} | |
ddcea0b5 EK |
611 | on the members that are to be members of the new superclass. For an overview of |
612 | the \emph{Extract Superclass} refactoring, see figure | |
613 | \ref{fig:extractSuperclass}. | |
6065c96c | 614 | |
ddcea0b5 EK |
615 | \begin{figure}[h] |
616 | \centering | |
faa9f4f3 | 617 | \includegraphics[angle=270,width=\linewidth]{extractSuperclassItalic.pdf} |
ddcea0b5 EK |
618 | \caption{The Extract Superclass refactoring} |
619 | \label{fig:extractSuperclass} | |
620 | \end{figure} | |
6065c96c EK |
621 | |
622 | \section{Manual vs. automated refactorings} | |
623 | Refactoring is something every programmer does, even if he or she does not known | |
f65da046 EK |
624 | the term \emph{refactoring}. Every refinement of source code that does not alter |
625 | the program's behavior is a refactoring. For small refactorings, such as | |
626 | \emph{Extract Method}, executing it manually is a manageable task, but is still | |
627 | prone to errors. Getting it right the first time is not easy, considering the | |
628 | signature and all the other aspects of the refactoring that has to be in place. | |
629 | ||
630 | Take for instance the renaming of classes, methods and fields. For complex | |
631 | programs these refactorings are almost impossible to get right. Attacking them | |
632 | with textual search and replace, or even regular expressions, will fall short on | |
633 | these tasks. Then it is crucial to have proper tool support that can perform | |
634 | them automatically. Tools that can parse source code and thus has semantic | |
635 | knowledge about which occurrences of which names that belongs to what construct | |
636 | in the program. For even trying to perform one of these complex task manually, | |
637 | one would have to be very confident on the existing test suite \see{tdd}. | |
00aa0588 | 638 | |
f65da046 EK |
639 | \section{Correctness of refactorings} |
640 | \todo{Volker's example?} | |
641 | For automated refactorings to be truly useful, they must show a high degree of | |
642 | behavior preservation. This might seem obvious, but there are examples of | |
ee45c41f EK |
643 | refactorings in existing tools that break programs. \todo{More than Eclipse?} I |
644 | will now present an example of an \emph{Extract Method} refactoring followed by | |
645 | a \emph{Move Method} refactoring that breaks a program. The following piece of | |
646 | code shows the target for the composed refactoring: | |
00aa0588 | 647 | |
ddcea0b5 EK |
648 | \begin{minted}[linenos]{java} |
649 | public class C { | |
650 | public X x = new X(); | |
ee45c41f | 651 | |
ddcea0b5 EK |
652 | public void f() { |
653 | x.m(this); | |
654 | x.n(); | |
655 | } | |
656 | } | |
657 | \end{minted} | |
ee45c41f EK |
658 | |
659 | \noindent The next piece of code shows the destination of the refactoring. Note | |
3510e539 EK |
660 | that the method \method{m(C c)} of class \type{C} assigns to the field \var{x} |
661 | of the argument \var{c} that has type \type{C}: | |
ee45c41f EK |
662 | |
663 | \begin{minted}{java} | |
664 | public class X { | |
665 | public void m(C c) { | |
666 | c.x = new X(); | |
667 | } | |
668 | public void n() {} | |
669 | } | |
670 | \end{minted} | |
671 | ||
672 | The refactoring sequence works by extracting line 5 and 6 from the original | |
3510e539 EK |
673 | class \type{C} into a method \method{f} with the statements from those lines as |
674 | its method body. The method is then moved to the class \type{X}. The result is | |
ee45c41f EK |
675 | shown in the following two pieces of code: |
676 | ||
677 | \begin{minted}[linenos]{java} | |
678 | public class C { | |
679 | public X x = new X(); | |
680 | ||
681 | public void f() { | |
682 | x.f(this); | |
683 | } | |
684 | } | |
685 | \end{minted} | |
686 | ||
687 | \begin{minted}[linenos]{java} | |
688 | public class X { | |
689 | public void m(C c) { | |
690 | c.x = new X(); | |
691 | } | |
692 | public void n() {} | |
693 | public void f(C c) { | |
694 | m(c); | |
695 | n(); | |
696 | } | |
697 | } | |
698 | \end{minted} | |
699 | ||
3510e539 EK |
700 | Since, after the refactoring, the method \method{f} of class \type{C} calls the |
701 | method \method{f} of class \type{X}, the program breaks. (See line 5 of the | |
702 | version of class \type{C} after the refactoring.) Before the refactoring, the | |
703 | methods \method{m} and \method{n} of class \type{X} are called on different | |
704 | object instances (see line 5 and 6 of the original class \type{C}). After, they | |
705 | are called on the same object, and the statement on line 3 in the class \type{X} | |
706 | after the refactoring no longer have any effect in our example. | |
ddcea0b5 | 707 | |
f65da046 EK |
708 | \section{Test Driven Development}\label{tdd} |
709 | ||
710 | \section{Software metrics} | |
00aa0588 EK |
711 | |
712 | %\part{The project} | |
713 | %\chapter{Planning the project} | |
714 | %\part{Conclusion} | |
715 | %\chapter{Results} | |
716 | ||
b0e80574 | 717 | |
3b7c1d90 EK |
718 | |
719 | \chapter{\ldots} | |
720 | \todo{write} | |
721 | \section{The problem statement} | |
3f929fcc EK |
722 | \section{Choosing the target language} |
723 | Choosing which programming language to use as the target for manipulation is not | |
724 | a very difficult task. The language have to be an object-oriented programming | |
725 | language, and it must have existing tool support for refactoring. The | |
726 | \emph{Java} programming language\footnote{\url{https://www.java.com/}} is the | |
727 | dominating language when it comes to examples in the literature of refactoring, | |
728 | and is thus a natural choice. Java is perhaps, currently the most influential | |
729 | programming language in the world, with its \emph{Java Virtual Machine} that | |
730 | runs on all of the most popular architectures and also supports\footnote{They | |
731 | compile to java bytecode.} dozens of other programming languages, with | |
732 | \emph{Scala}, \emph{Clojure} and \emph{Groovy} as the most prominent ones. Java | |
733 | is currently the language that every other programming language is compared | |
734 | against. It is also the primary language of the author of this thesis. | |
735 | ||
736 | \section{Choosing the tools} | |
737 | When choosing a tool for manipulating Java, there are certain criterias that | |
738 | have to be met. First of all, the tool should have some existing refactoring | |
739 | support that this thesis can build upon. Secondly it should provide some kind of | |
740 | framework for parsing and analyzing Java source code. Third, it should itself be | |
741 | open source. This is both because of the need to be able to browse the code for | |
742 | the existing refactorings that is contained in the tool, and also because open | |
743 | source projects hold value in them selves. Another important aspect to consider | |
744 | is that open source projects of a certain size, usually has large communities of | |
745 | people connected to them, that are commited to answering questions regarding the | |
746 | use and misuse of the products, that to a large degree is made by the cummunity | |
747 | itself. | |
748 | ||
749 | There is a certain class of tools that meet these criterias, namely the class of | |
750 | \emph{IDEs}\footnote{\emph{Integrated Development Environment}}. These are | |
751 | proagrams that is ment to support the whole production cycle of a cumputer | |
752 | program, and the most popular IDEs that support Java, generally have quite good | |
753 | refactoring support. | |
754 | ||
755 | The main contenders for this thesis is the \emph{Eclipse | |
756 | IDE}\footnote{\url{http://www.eclipse.org/}}, with the \emph{Java development | |
757 | tools} (JDT), the \emph{IntelliJ IDEA Community | |
758 | Edition}\footnote{\url{http://www.jetbrains.com/idea/}} and the \emph{NetBeans | |
759 | IDE}\footnote{\url{https://netbeans.org/}}. Eclipse and NetBeans are both free, | |
760 | open source and community driven, while the IntelliJ IDEA has an open sourced | |
761 | community edition that is free of charge, but also offer an \emph{Ultimate | |
6018eec9 | 762 | Edition} with an extended set of features, at additional cost. All three IDEs |
3f929fcc | 763 | supports adding plugins to extend their functionality and tools that can be used |
6018eec9 | 764 | to parse and analyze Java source code. \todo{investigate if this is true} But |
3f929fcc | 765 | one of the IDEs stand out as a favorite, and that is the \emph{Eclipse IDE}. |
6018eec9 EK |
766 | This is the most popular~\cite{javaReport2011} among them and seems to be de |
767 | facto standard IDE for Java development regardless of platform. | |
3b7c1d90 | 768 | |
5837a41f EK |
769 | \chapter{Refactorings in Eclipse JDT: Design, Shortcomings and Wishful |
770 | Thinking}\label{ch:jdt_refactorings} | |
771 | ||
772 | This chapter will deal with some of the design behind refactoring support in | |
773 | Eclipse, and the JDT in specific. After which it will follow a section about | |
774 | shortcomings of the refactoring API in terms of composition of refactorings. The | |
775 | chapter will be concluded with a section telling some of the ways the | |
776 | implementation of refactorings in the JDT could have worked to facilitate | |
777 | composition of refactorings. | |
055dca93 | 778 | |
b0e80574 | 779 | \section{Design} |
f041551b | 780 | The refactoring world of Eclipse can in general be separated into two parts: The |
b289552b | 781 | language independent part and the part written for a specific programming |
07e173d4 EK |
782 | language -- the language that is the target of the supported refactorings. |
783 | \todo{What about the language specific part?} | |
f041551b EK |
784 | |
785 | \subsection{The Language Toolkit} | |
786 | The Language Toolkit, or LTK for short, is the framework that is used to | |
787 | implement refactorings in Eclipse. It is language independent and provides the | |
788 | abstractions of a refactoring and the change it generates, in the form of the | |
789 | classes \typewithref{org.eclipse.ltk.core.refactoring}{Refactoring} and | |
790 | \typewithref{org.eclipse.ltk.core.refactoring}{Change}. (There is also parts of | |
791 | the LTK that is concerned with user interaction, but they will not be discussed | |
792 | here, since they are of little value to us and our use of the framework.) | |
793 | ||
794 | \subsubsection{The Refactoring Class} | |
795 | The abstract class \type{Refactoring} is the core of the LTK framework. Every | |
796 | refactoring that is going to be supported by the LTK have to end up creating an | |
797 | instance of one of its subclasses. The main responsibilities of subclasses of | |
798 | \type{Refactoring} is to implement template methods for condition checking | |
799 | (\methodwithref{org.eclipse.ltk.core.refactoring.Refactoring}{checkInitialConditions} | |
800 | and | |
801 | \methodwithref{org.eclipse.ltk.core.refactoring.Refactoring}{checkFinalConditions}), | |
802 | in addition to the | |
803 | \methodwithref{org.eclipse.ltk.core.refactoring.Refactoring}{createChange} | |
07e173d4 EK |
804 | method that creates and returns an instance of the \type{Change} class. |
805 | ||
806 | If the refactoring shall support that others participate in it when it is | |
807 | executed, the refactoring has to be a processor-based | |
808 | refactoring\typeref{org.eclipse.ltk.core.refactoring.participants.ProcessorBasedRefactoring}. | |
809 | It then delegates to its given | |
810 | \typewithref{org.eclipse.ltk.core.refactoring.participants}{RefactoringProcessor} | |
811 | for condition checking and change creation. | |
f041551b EK |
812 | |
813 | \subsubsection{The Change Class} | |
07e173d4 EK |
814 | This class is the base class for objects that is responsible for performing the |
815 | actual workspace transformations in a refactoring. The main responsibilities for | |
816 | its subclasses is to implement the | |
817 | \methodwithref{org.eclipse.ltk.core.refactoring.Change}{perform} and | |
818 | \methodwithref{org.eclipse.ltk.core.refactoring.Change}{isValid} methods. The | |
819 | \method{isValid} method verifies that the change object is valid and thus can be | |
820 | executed by calling its \method{perform} method. The \method{perform} method | |
821 | performs the desired change and returns an undo change that can be executed to | |
822 | reverse the effect of the transformation done by its originating change object. | |
823 | ||
61420ef7 | 824 | \subsubsection{Executing a Refactoring}\label{executing_refactoring} |
07e173d4 EK |
825 | The life cycle of a refactoring generally follows two steps after creation: |
826 | condition checking and change creation. By letting the refactoring object be | |
827 | handled by a | |
828 | \typewithref{org.eclipse.ltk.core.refactoring}{CheckConditionsOperation} that | |
829 | in turn is handled by a | |
830 | \typewithref{org.eclipse.ltk.core.refactoring}{CreateChangeOperation}, it is | |
831 | assured that the change creation process is managed in a proper manner. | |
832 | ||
833 | The actual execution of a change object has to follow a detailed life cycle. | |
834 | This life cycle is honored if the \type{CreateChangeOperation} is handled by a | |
835 | \typewithref{org.eclipse.ltk.core.refactoring}{PerformChangeOperation}. If also | |
836 | an undo manager\typeref{org.eclipse.ltk.core.refactoring.IUndoManager} is set | |
837 | for the \type{PerformChangeOperation}, the undo change is added into the undo | |
838 | history. | |
055dca93 | 839 | |
b0e80574 | 840 | \section{Shortcomings} |
80663734 | 841 | This section is introduced naturally with a conclusion: The JDT refactoring |
5837a41f EK |
842 | implementation does not facilitate composition of refactorings. |
843 | \todo{refine}This section will try to explain why, and also identify other | |
844 | shortcomings of both the usability and the readability of the JDT refactoring | |
845 | source code. | |
80663734 EK |
846 | |
847 | I will begin at the end and work my way toward the composition part of this | |
848 | section. | |
849 | ||
5837a41f | 850 | \subsection{Absence of Generics in Eclipse Source Code} |
80663734 EK |
851 | This section is not only concerning the JDT refactoring API, but also large |
852 | quantities of the Eclipse source code. The code shows a striking absence of the | |
853 | Java language feature of generics. It is hard to read a class' interface when | |
5837a41f EK |
854 | methods return objects or takes parameters of raw types such as \type{List} or |
855 | \type{Map}. This sometimes results in having to read a lot of source code to | |
856 | understand what is going on, instead of relying on the available interfaces. In | |
857 | addition, it results in a lot of ugly code, making the use of typecasting more | |
858 | of a rule than an exception. | |
859 | ||
860 | \subsection{Composite Refactorings Will Not Appear as Atomic Actions} | |
861 | ||
862 | \subsubsection{Missing Flexibility from JDT Refactorings} | |
863 | The JDT refactorings are not made with composition of refactorings in mind. When | |
864 | a JDT refactoring is executed, it assumes that all conditions for it to be | |
865 | applied successfully can be found by reading source files that has been | |
866 | persisted to disk. They can only operate on the actual source material, and not | |
867 | (in-memory) copies thereof. This constitutes a major disadvantage when trying to | |
868 | compose refactorings, since if an exception occur in the middle of a sequence of | |
869 | refactorings, it can leave the project in a state where the composite | |
870 | refactoring was executed only partly. It makes it hard to discard the changes | |
871 | done without monitoring and consulting the undo manager, an approach that is not | |
872 | bullet proof. | |
873 | ||
874 | \subsubsection{Broken Undo History} | |
875 | When designing a composed refactoring that is to be performed as a sequence of | |
876 | refactorings, you would like it to appear as a single change to the workspace. | |
877 | This implies that you would also like to be able to undo all the changes done by | |
878 | the refactoring in a single step. This is not the way it appears when a sequence | |
879 | of JDT refactorings is executed. It leaves the undo history filled up with | |
880 | individual undo actions corresponding to every single JDT refactoring in the | |
881 | sequence. This problem is not trivial to handle in Eclipse. (See section | |
882 | \ref{hacking_undo_history}.) | |
883 | ||
884 | \section{Wishful Thinking} | |
80663734 | 885 | |
80663734 | 886 | |
b0e80574 EK |
887 | |
888 | \chapter{Composite Refactorings in Eclipse} | |
889 | ||
890 | \section{A Simple Ad Hoc Model} | |
891 | As pointed out in chapter \ref{ch:jdt_refactorings}, the Eclipse JDT refactoring | |
892 | model is not very well suited for making composite refactorings. Therefore a | |
893 | simple model using changer objects (of type \type{RefaktorChanger}) is used as | |
894 | an abstraction layer on top of the existing Eclipse refactorings. | |
895 | ||
896 | \section{The Extract and Move Method Refactoring} | |
61420ef7 EK |
897 | %The Extract and Move Method Refactoring is implemented mainly using these |
898 | %classes: | |
899 | %\begin{itemize} | |
900 | % \item \type{ExtractAndMoveMethodChanger} | |
901 | % \item \type{ExtractAndMoveMethodPrefixesExtractor} | |
902 | % \item \type{Prefix} | |
903 | % \item \type{PrefixSet} | |
904 | %\end{itemize} | |
905 | ||
906 | \subsection{The Building Blocks} | |
907 | This is a composite refactoring, and hence is built up using several primitive | |
908 | refactorings. These basic building blocks are, as its name implies, the Extract | |
909 | Method Refactoring \cite{refactoring} and the Move Method Refactoring | |
910 | \cite{refactoring}. In Eclipse, the implementations of these refactorings are | |
911 | found in the classes | |
912 | \typewithref{org.eclipse.jdt.internal.corext.refactoring.code}{ExtractMethodRefactoring} | |
913 | and | |
914 | \typewithref{org.eclipse.jdt.internal.corext.refactoring.structure}{MoveInstanceMethodProcessor}, | |
915 | where the last class is designed to be used together with the processor-based | |
916 | \typewithref{org.eclipse.ltk.core.refactoring.participants}{MoveRefactoring}. | |
917 | ||
918 | \subsubsection{The ExtractMethodRefactoring Class} | |
919 | This class is quite simple in its use. The only parameters it requires for | |
920 | construction is a compilation | |
921 | unit\typeref{org.eclipse.jdt.core.ICompilationUnit}, the offset into the source | |
922 | code where the extraction shall start, and the length of the source to be | |
923 | extracted. Then you have to set the method name for the new method together with | |
924 | which access modifier that shall be used and some not so interesting parameters. | |
925 | ||
926 | \subsubsection{The MoveInstanceMethodProcessor Class} | |
927 | For the Move Method the processor requires a little more advanced input than | |
928 | the class for the Extract Method. For construction it requires a method | |
929 | handle\typeref{org.eclipse.jdt.core.IMethod} from the Java Model for the method | |
930 | that is to be moved. Then the target for the move have to be supplied as the | |
931 | variable binding from a chosen variable declaration. In addition to this, one | |
932 | have to set some parameters regarding setters/getters and delegation. | |
933 | ||
934 | To make a whole refactoring from the processor, one have to construct a | |
935 | \type{MoveRefactoring} from it. | |
b0e80574 EK |
936 | |
937 | \subsection{The ExtractAndMoveMethodChanger Class} | |
61420ef7 EK |
938 | The \typewithref{no.uio.ifi.refaktor.changers}{ExtractAndMoveMethodChanger} |
939 | class, that is a subclass of the class | |
940 | \typewithref{no.uio.ifi.refaktor.changers}{RefaktorChanger}, is the class | |
941 | responsible for composing the \type{ExtractMethodRefactoring} and the | |
942 | \type{MoveRefactoring}. Its constructor takes a project | |
943 | handle\typeref{org.eclipse.core.resources.IProject}, the method name for the new | |
944 | method and a \typewithref{no.uio.ifi.refaktor.utils}{SmartTextSelection}. | |
945 | ||
946 | A \type{SmartTextSelection} is basically a text | |
947 | selection\typeref{org.eclipse.jface.text.ITextSelection} object that enforces | |
948 | the providing of the underlying document during creation. I.e. its | |
949 | \methodwithref{no.uio.ifi.refaktor.utils.SmartTextSelection}{getDocument} method | |
950 | will never return \type{null}. | |
951 | ||
952 | Before extracting the new method, the possible targets for the move operation is | |
953 | found with the help of an | |
954 | \typewithref{no.uio.ifi.refaktor.extractors}{ExtractAndMoveMethodPrefixesExtractor}. | |
72b64328 EK |
955 | The possible targets is computed from the prefixes that the extractor returns |
956 | from its | |
61420ef7 EK |
957 | \methodwithref{no.uio.ifi.refaktor.extractors.ExtractAndMoveMethodPrefixesExtractor}{getSafePrefixes} |
958 | method. The changer then choose the most suitable target by finding the most | |
72b64328 EK |
959 | frequent occurring prefix among the safe ones. The target is the type of the |
960 | first part of the prefix. | |
61420ef7 EK |
961 | |
962 | After finding a suitable target, the \type{ExtractAndMoveMethodChanger} first | |
963 | creates an \type{ExtractMethodRefactoring} and performs it as explained in | |
964 | section \ref{executing_refactoring} about the execution of refactorings. Then it | |
965 | creates and performs the \type{MoveRefactoring} in the same way, based on the | |
966 | changes done by the Extract Method refactoring. | |
967 | ||
b0e80574 | 968 | \subsection{The ExtractAndMoveMethodPrefixesExtractor Class} |
61420ef7 | 969 | This extractor extracts properties needed for building the Extract and Move |
72b64328 EK |
970 | Method refactoring. It searches through the given selection to find safe |
971 | prefixes, and those prefixes form a base that can be used to compute possible | |
972 | targets for the move part of the refactoring. It finds both the candidates, in | |
973 | the form of prefixes, and the non-candidates, called unfixes. All prefixes (and | |
974 | unfixes) are represented by a | |
975 | \typewithref{no.uio.ifi.refaktor.extractors}{Prefix}, and they are collected | |
976 | into prefix sets.\typeref{no.uio.ifi.refaktor.extractors.PrefixSet}. | |
977 | ||
978 | The prefixes and unfixes are found by property | |
979 | collectors\typeref{no.uio.ifi.refaktor.extractors.collectors.PropertyCollector}. | |
980 | A property collector follows the visitor pattern \cite{dp} and is of the | |
981 | \typewithref{org.eclipse.jdt.core.dom}{ASTVisitor} type. An \type{ASTVisitor} | |
982 | visits nodes in an abstract syntax tree that forms the Java document object | |
983 | model. The tree consists of nodes of type | |
984 | \typewithref{org.eclipse.jdt.core.do}{ASTNode}. | |
985 | ||
986 | \subsubsection{The PrefixesCollector} | |
987 | The \typewithref{no.uio.ifi.refaktor.extractors.collectors}{PrefixesCollector} | |
988 | is of type \type{PropertyCollector}. It visits expression | |
989 | statements\typeref{org.eclipse.jdt.core.dom.ExpressionStatement} and creates | |
990 | prefixes from its expressions in the case of method invocations. The prefixes | |
991 | found is registered with a prefix set, together with all its sub-prefixes. | |
992 | \todo{Rewrite in the case of changes to the way prefixes are found} | |
993 | ||
994 | \subsubsection{The UnfixesCollector} | |
995 | The \typewithref{no.uio.ifi.refaktor.extractors.collectors}{UnfixesCollector} | |
996 | finds unfixes within the selection. An unfix is a name that is assigned to | |
997 | within the selection. The reason that this cannot be allowed, is that the result | |
998 | would be an assignment to the \type{this} keyword, which is not valid in Java. | |
999 | ||
1000 | \subsubsection{Computing Safe Prefixes} | |
1001 | A safe prefix is a prefix that does not enclose an unfix. A prefix is enclosing | |
1002 | an unfix if the unfix is in the set of its sub-prefixes. As an example, | |
1003 | \texttt{``a.b''} is enclosing \texttt{``a''}, as is \texttt{``a''}. The safe | |
1004 | prefixes is unified in a \type{PrefixSet} and can be fetched calling the | |
1005 | \method{getSafePrefixes} method of the | |
1006 | \type{ExtractAndMoveMethodPrefixesExtractor}. | |
61420ef7 | 1007 | |
b0e80574 | 1008 | \subsection{The Prefix Class} |
72b64328 | 1009 | \todo{?} |
b0e80574 EK |
1010 | \subsection{The PrefixSet Class} |
1011 | ||
5837a41f EK |
1012 | \subsection{Hacking the Refactoring Undo |
1013 | History}\label{hacking_undo_history} | |
8fae7b44 EK |
1014 | \todo{Where to put this section?} |
1015 | ||
1016 | As an attempt to make multiple subsequent changes to the workspace appear as a | |
1017 | single action (i.e. make the undo changes appear as such), I tried to alter | |
1018 | the undo changes\typeref{org.eclipse.ltk.core.refactoring.Change} in the history | |
1019 | of the refactorings. | |
1020 | ||
1021 | My first impulse was to remove the, in this case, last two undo changes from the | |
f041551b EK |
1022 | undo manager\typeref{org.eclipse.ltk.core.refactoring.IUndoManager} for the |
1023 | Eclipse refactorings, and then add them to a composite | |
8fae7b44 EK |
1024 | change\typeref{org.eclipse.ltk.core.refactoring.CompositeChange} that could be |
1025 | added back to the manager. The interface of the undo manager does not offer a | |
1026 | way to remove/pop the last added undo change, so a possible solution could be to | |
1027 | decorate \cite{dp} the undo manager, to intercept and collect the undo changes | |
f041551b EK |
1028 | before delegating to the \method{addUndo} |
1029 | method\methodref{org.eclipse.ltk.core.refactoring.IUndoManager}{addUndo} of the | |
8fae7b44 EK |
1030 | manager. Instead of giving it the intended undo change, a null change could be |
1031 | given to prevent it from making any changes if run. Then one could let the | |
1032 | collected undo changes form a composite change to be added to the manager. | |
1033 | ||
1034 | There is a technical challenge with this approach, and it relates to the undo | |
1035 | manager, and the concrete implementation | |
1036 | UndoManager2\typeref{org.eclipse.ltk.internal.core.refactoring.UndoManager2}. | |
1037 | This implementation is designed in a way that it is not possible to just add an | |
1038 | undo change, you have to do it in the context of an active | |
1039 | operation\typeref{org.eclipse.core.commands.operations.TriggeredOperations}. | |
1040 | One could imagine that it might be possible to trick the undo manager into | |
1041 | believing that you are doing a real change, by executing a refactoring that is | |
1042 | returning a kind of null change that is returning our composite change of undo | |
1043 | refactorings when it is performed. | |
1044 | ||
1045 | Apart from the technical problems with this solution, there is a functional | |
1046 | problem: If it all had worked out as planned, this would leave the undo history | |
1047 | in a dirty state, with multiple empty undo operations corresponding to each of | |
1048 | the sequentially executed refactoring operations, followed by a composite undo | |
1049 | change corresponding to an empty change of the workspace for rounding of our | |
1050 | composite refactoring. The solution to this particular problem could be to | |
1051 | intercept the registration of the intermediate changes in the undo manager, and | |
1052 | only register the last empty change. | |
1053 | ||
1054 | Unfortunately, not everything works as desired with this solution. The grouping | |
1055 | of the undo changes into the composite change does not make the undo operation | |
1056 | appear as an atomic operation. The undo operation is still split up into | |
1057 | separate undo actions, corresponding to the change done by its originating | |
1058 | refactoring. And in addition, the undo actions has to be performed separate in | |
1059 | all the editors involved. This makes it no solution at all, but a step toward | |
1060 | something worse. | |
1061 | ||
1062 | There might be a solution to this problem, but it remains to be found. The | |
1063 | design of the refactoring undo management is partly to be blamed for this, as it | |
1064 | it is to complex to be easily manipulated. | |
1065 | ||
b0e80574 | 1066 | |
9ff90080 EK |
1067 | \backmatter{} |
1068 | \printbibliography | |
055dca93 | 1069 | \listoftodos |
9ff90080 | 1070 | \end{document} |