DenkzeitWiki

Suchen:

Aktuelle Änderungen Printable View Änderungen Bearbeiten

TailRecursionElimination > Recursion > ExtensibleMarkupLanguage > PythonWindowsProgramming > InterestingPythonModules > AgileSoftwareEngineering > ObjectObsessedProgramming > ObjectOrientedProgramming > AspectOrientedProgramming > ReflectionAndIntrospection > LetzteInformatikPruefungen > CurrentTrendsInProgramming > RapidApplicationDevelopment > DotNetFrameworkClassBrowser > SoftwareTransactionalMemory > FontsForProgramming > RefactoringInDynamicLanguagesClear Trail
Main /

Refactoring In Dynamic Languages

LargeScaleApps

DynamicLanguages
BottomUpProgramming
SoftwareEngineering
AgileSoftwareEngineering

OptionalStaticTyping
TypeInference
StaticVsDynamicTyping


"I cannot imagine how the dynamic folks can maintain medium to large projects without refactoring over several iterations over several years of requirement additions and changes."

Perhaps they compose larger software from smaller independent parts, rather than composing large software from large interdependent parts.[1]


One of the key features of Smalltalk that allows us to perform the sorts of analyses and source code transformations necessary for refactoring is that it has reflective facilities, that is, the ability for the language to examine and modify its own structures. For instance, the Refactoring Browser examines the context stacks of executing programs to determine runtime properties such as callers of a particular method or cardinality relationships between components and aggregates. Refactoring can be performed in the absence of reflective facilities, but then requires a separate, metalanguage that can be used to manipulate the original program. Having a single language simplifies the process...

Some preconditions of refactorings are not simple to compute from the static program text. With Smalltalk's dynamic typing, determining the type of a particular variable can be extremely difficult and time consuming. Moreover, there are analyses that defy static analysis in any language, such as cardinality relationships between objects.

Since, performing these types of analysis statically is difficult or impossible, the Refactoring Browser computes some of the preconditions by performing the analysis dynamically rather than statically. By observing the actual values that occur, the Refactoring Browser can perform correct refactorings. As an example, consider the rename method refactoring. To correctly rename a method, all calls to that method must be renamed. This is difficult in an environment that uses polymorphism to the extent that Smalltalk does. Smalltalk also allows dynamically created messages to be sent via the perform: message. If an application uses this approach, any automatic renaming process has the potential of failure. Under these conditions, guaranteeing the safety of a rename is impossible.

The Refactoring Browser uses method wrappers to collect runtime information. These wrappers are activated when the wrapped method is called and when it returns. The wrapper can execute an arbitrary block of Smalltalk code. To perform the rename method refactoring dynamically, the Refactoring Browser renames the initial method and then puts a method wrapper on the original method. As the program runs, the wrapper detects sites that call the original method. Whenever a call to the old method is detected, the method wrapper suspends execution of the program, goes up the call stack to the sender and changes the source code to refer to the new, renamed method. Therefore, as the program is exercised, it converges towards a correctly refactored program.

The major drawback to this type of refactoring is that the refactoring is only as good as your test suite. [2]



Boilerplate
 > I think you missed the point or I did not express myself
 > clearly. If you have IDE support for "rename method" there
 > is no need to stew. As you come up with a better name, you
 > can confidently rename the method even if its used in 1000
 > files.

 ... assuming, of course, that those 1000 files aren't config  files,
 and don't include some sort of weird loading that the IDE didn't notice,
 and that the name wasn't exported outside your module,
 and that it isn't in use in some other developer's workspace in code
 that isn't checked in, and ...

 I personally LOVE refactoring. It's a major tool for keeping my codebases clean.
 But - IDE refactoring only help me a trifle. Dynamic languages tend to let me
 do refactoring that abstract away more complexity, because there is usually
 less mandated boilerplate, and there is more flexibility in how I map
 the problem to the solution. The lack of boilerplate means that my actual
 changes are less obscured by noise in the diff, so it is often easier to
 do refactoring in them - even without the support tools.


When you have large code bases being developed by large teams, changes ripple throughout the code base constantly. Some are small, others are like tidal waves. Static typed systems tend to absorb those ripples more reliably than dynamic systems. Static system creak and groan under the changes, and those creaks stand out and can easily be found.

Dynamic system absorb those changes more readily, and silently. That's a key benefit. You can make a local change, that may well have far reaching effects, in a dynamic language and still be able to work on your change without having to "fix" the entire system just to get it to start up for a test. You can fix the rest of the system later.


static languages with dynamic features

The problems with refactoring in dynamic languages also arise in static languages when certain features are used:
template <typename T>
void f1(T t)
{
    t.init();
}

template <typename T>
void f2(T t)
{
    t.init();
}


Edit - BackLinks - Tags - Page Hist - Print - Changes - Home - Orphans - Help

Zuletzt geändert am 04.07.2009 14:21 Uhr und seit 7. April 2005 3579 aufgerufen.