The Artima Developer Community
Sponsored Link

Weblogs Forum
Refactoring Dynamic Code

24 replies. Most recent reply: Nov 22, 2007 4:04 AM by Daesung Park

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a flat view of this topic  Flat View
Previous Topic   Next Topic
Threaded View: This topic has 24 replies on 1 page
Frank Sommers

Posts: 2642
Nickname: fsommers
Registered: Jan, 2002

Refactoring Dynamic Code (View in Weblogs) Posted: Oct 16, 2007 9:39 PM
Reply to this message Reply
Summary
The initial productivity gain of working with a dynamic language can decline as a project's codebase grows, and as refactoring becomes increasingly a chore.

Many arguments in favor of dynamic languages center around improved developer productivity. Productivity, however, is a loosely-defined term. For example, productivity can vary over the lifetime of a project: being productive today no more guarantees tomorrow's productivity than today's seeming inefficiency assures failure and waste in the future.

I've heard enough about productivity brought about by dynamic languages to want to test this premise first-hand. So when a client approached me about a tiny application that would be used internally by about twenty people, that sounded like the perfect opportunity for a dynamic language project: It would allow me to learn Rails, something that was high on my wish list, and to enjoy the productivity benefits of Ruby at the same time.

Coming from a Java background, I was very pleasantly surprised not just, or even primarily, with Rails, but especially with Ruby: There seemed to be a Ruby library for all the tasks I needed to accomplish, from connecting to an ODBC data source, to authenticating with Microsoft Exchange and fetching mail from an IMAP server, to generating simple PDF reports. And I could do all that in just a few lines of clean, neatly organized code. Ruby's conciseness and elegance, combined with Rails, allowed me to develop and put the application in production in only a few weeks, working part-time on the project.

Once deployed, the application worked very well. So well, in fact, that a few months into production, the client became interested in expanding the application's features. They agreed to a method whereby we would plan for and deliver each desired feature without a big, up-front design, since they were uncertain about the specifics of the features.

I'm a big believer in such an agile approach, but my experience in developing software that way was at the time limited to Java. With that background, I was confident that frequent refactoring, coupled with good unit and functional tests, would make this approach practicable and fruitful. My confidence in the agile way of doing things was bolstered by several Rails features, such as migrations—small Ruby tasks that affect changes to the database schema—as well as Rails' extensive and well thought-out testing framework.

These tools, along with the relatively small amount of Ruby code required to implement the desired features, made life easy during the first few iterations. With each new feature, however, the amount of refactoring required to keep the codebase clean increased. Although Rails' adherence to the DRY principle helped reduce duplication, each refactoring had to change numerous code artifacts. Some of the changes, admittedly, were needed to keep the code in line with Rails' convention-over-configuration philosophy.

Renaming an entity class, for instance, requires renaming the corresponding database tables, including other columns and indexes referencing the model's table, renaming the model class, changing the corresponding controller, helper classes, and every reference to the entity class in the views, as well as renaming the directory containing the view classes and templates. And, of course, you have to similarly rename the associated tests and all references to the model, controller, and views in the tests and fixtures.

Most of these refactorings, such as changing database table names, are not mandated by Ruby or even Rails. And Rails provides easy overrides for every one of its conventions. Still, I didn't want to start down the slippery slope of masking changes in design with configuration overrides, and decided to just take the time to perform every refactoring the right way.

A few days ago, after having spent many hours renaming things, using search-and-replace, and fixing tests, I was itching for a better way. Even the excellent RAD Rails IDE was of little help, since it is not at present able to rename even Ruby classes without breaking references to those classes. Some of the features that made development fast in the early stages of the project, were now slowing me down.

Some would argue at this point that the primary cause for this productivity decline at this stage of the project is that IDEs just can't refactor dynamic code as well as they can statically typed code. That, however, is only part of the reason, I think.

I wanted to ensure that my refactorings were correctly and consistently performed across the entire application stack mainly because I felt that in the absence of a compile-time type-checking system coding conventions became important crutches to lean on for comfort. For the same reason, I'm also more reliant on tests in this dynamic-language project, and tend to write more tests than I would create for, say, a Java application. And, of course, refactoring tests is a large part of the effort at this point in the project.

If I were to generalize my admittedly limited experience working on a growing codebase in a dynamic language, I would argue that dynamic languages do not necessarily lead to harder-to-refactor code. Rather, it's the infrastructure needed to develop larger applications in dynamic code that make refactoring more of a chore, especially as the codebase grows. Coding conventions and tests are, in a way, the "type system" of a dynamic project in terms of providing guarantees—a sort of contract—a developer can depend on.

I wonder to what extent that infrastructure will get in the way of productivity as this projects grows. While that ongoing overhead may be significant, one could look at it in a way one would consider an investment portfolio: Over a longer period, such a year, it is not the marginal gain or loss in the price of any one equity that counts, nor the loss or gain within a shorter time segment, but the total return on the portfolio over the longer period. A huge gain in the first few months may be neutralized by subsequent declines, and vice versa. In a similar way, it may be that even if my productivity declines over time, it will still exceed what I would have had I chosen a strongly-typed language for this project.

What is your experience with sustained productivity when working with dynamic languages on larger projects? How do you refactor larger code-bases written in a dynamic language?


Re: Refactoring Dynamic Code Posted: Oct 16, 2007 10:01 PM
Reply to this message Reply
Posted by: Isaac Gouy    Posts: 527 / Nickname: igouy / Registered: Jul, 2003
"Refactoring Ruby Code" would have been a sufficiently bold generalization from your one project ;-)


Re: Refactoring Dynamic Code Posted: Oct 16, 2007 10:26 PM
Reply to this message Reply
Posted by: Matt Secoske    Posts: 1 / Nickname: msecoske / Registered: Oct, 2007
I've recently been in your situation, refactoring Rails code.

I'm not sure I could generalize the problem to be a dynamic language problem. It sounds like the problem you had (as I did) was with Rails and its set of conventions.

For instance, the use of fixtures in both model (unit) and controller (functional) tests. This creates a somewhat hidden dependency that can make what seems to be an innocuous model change cause problems with the functional tests. At least that has been my experience.

Also, I have done the "Rails Refactoring Challenge" as well against a fair number of tools. None of them do a good job yet. I am sure that they will at some point, at least with "conventional" Rails code. However, it is very easy to subvert Ruby code, so it will be interesting to see just how well the tools will work.


Re: Refactoring Dynamic Code Posted: Oct 17, 2007 8:07 AM
Reply to this message Reply
Posted by: Frank Sommers    Posts: 2642 / Nickname: fsommers / Registered: Jan, 2002
> Also, I have done the "Rails Refactoring Challenge" as
> well against a fair number of tools. None of them do a
> good job yet. I am sure that they will at some
> point, at least with "conventional" Rails code. However,
> it is very easy to subvert Ruby code, so it will be
> interesting to see just how well the tools will work.

I agree that this is more of a framework-related issue, and that a really good IDE could, in fact, deal with the majority of the refactorings I'm doing by hand. Also, as others pointed out, some of the refactorings would still have to be done by hand even if I used, say, Java.


Re: Refactoring Dynamic Code Posted: Oct 17, 2007 11:38 AM
Reply to this message Reply
Posted by: Cedric Beust    Posts: 140 / Nickname: cbeust / Registered: Feb, 2004
As was pointed out, some of the difficulties you encountered are indeed more due to Rails than to the nature of dynamically typed languages, but there are still many cases where automatic refactoring is simply impossible to achieve in dynamic languages.

For example:

def f1(o)
o.init
end

def f2(o)
o.init
end

class C
def init
...
end
end

If I want to rename C.init to init2, how can I know which other inits need to be renamed as well?

This is sometimes referred to as the "continuous tax" that dynamic typing languages you to pay as the size and scope of your code expands.

--
Cedric
Author "Next Generation Testing in Java"


Re: Refactoring Dynamic Code Posted: Oct 17, 2007 11:41 AM
Reply to this message Reply
Posted by: Joao Pedrosa    Posts: 114 / Nickname: dewd / Registered: Dec, 2005
Speaking of "continued taxes", why do folks get stuck in old versions of JDKs/JREs by the way?


Re: Refactoring Dynamic Code Posted: Nov 2, 2007 6:25 AM
Reply to this message Reply
Posted by: Vincent O'Sullivan    Posts: 724 / Nickname: vincent / Registered: Nov, 2002
Code compatability. Despite a general belief otherwise, there is not 100% backwards compatability from later to earlier JREs.


Re: Refactoring Dynamic Code Posted: Oct 17, 2007 5:34 PM
Reply to this message Reply
Posted by: Isaac Gouy    Posts: 527 / Nickname: igouy / Registered: Jul, 2003
Cedric Beust wrote
-snip-
> many cases where automatic refactoring is simply
> impossible to achieve in dynamic languages.

As I say everytime you repeat this - yes there are cases where automatic refactoring is not possible - now tell us how many cases and tell us what the consequences are.

Have you tried the Ruby refactoring support in IntelliJ IDEA 7.0?


-snip-
> If I want to rename C.init to init2, how can I know which
> other inits need to be renamed as well?

In Smalltalk that's pretty easy because there aren't any other init methods :-)

For those less common polymorphic methods we'd go through the list of call-sites and figure it out.

It can only be a matter of moments before someone turns that into the new agile virtue of continuous code inspection - automatic refactoring is an evil because it stops programmers reading the code! :-)


> This is sometimes referred to as the "continuous tax" that
> dynamic typing languages you to pay as the size and scope
> of your code expands.

This is sometimes referred to as "name calling" - maybe Google can find an example of juvenile wit that refers to Java as the "continuous tax" :-)


Re: Refactoring Dynamic Code Posted: Nov 1, 2007 2:07 PM
Reply to this message Reply
Posted by: Dick Ford    Posts: 149 / Nickname: roybatty / Registered: Sep, 2003
>
> > This is sometimes referred to as the "continuous tax"
> that
> > dynamic typing languages you to pay as the size and
> scope
> > of your code expands.
>
> This is sometimes referred to as "name calling" - maybe
> Google can find an example of juvenile wit that refers to
> Java as the "continuous tax" :-)

No it's not. Ruby doesn't have feelings. I know you have this insatiable need to troll all the programming forums Isaac, but you're not the defender of Smalltalk or Ruby.

Of course when you're trolling over at James Robertson's Cincom Smalltalk blog you feel that you need to defend Java, so who knows what your problem is.


Re: Refactoring Dynamic Code Posted: Oct 17, 2007 7:11 PM
Reply to this message Reply
Posted by: Kay Schluehr    Posts: 302 / Nickname: schluehk / Registered: Jan, 2005
> This is sometimes referred to as the "continuous tax" that
> dynamic typing languages you to pay as the size and scope
> of your code expands.

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

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

Everyone has to pay some taxes. Poor programmers.


Re: Refactoring Dynamic Code Posted: Oct 18, 2007 5:19 AM
Reply to this message Reply
Posted by: Massimiliano Pagani    Posts: 1 / Nickname: maxpagani / Registered: Oct, 2007

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

>
> Everyone has to pay some taxes. Poor programmers.

That's true. Anyway with more statically typed language you have more chances to catch the non-refactored issue as soon as you try to compile the code. While in a dynamically typed language you risk to let the problem slip into a release.

But I'm a statically-typed sort of guy so, maybe I'm biased ;-)

bye
--
Max


Re: Refactoring Dynamic Code Posted: Oct 22, 2007 3:29 AM
Reply to this message Reply
Posted by: Terje Slettebø    Posts: 205 / Nickname: tslettebo / Registered: Jun, 2004
> > This is sometimes referred to as the "continuous tax"
> that
> > dynamic typing languages you to pay as the size and
> scope
> > of your code expands.
>

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

That's correct; C++ templates has much the same problems as dynamical languages in this respect. That's where the "concept"-proposal (aka restricted generics, as also found in languages like Java and C#) comes in, which will likely be included in the next version of the standard (due in 2009).

Using concepts, you could write the above as:

concept SomeConcept
{
void init();
}

template<SomeConcept T>
void f1(T t)
{
t.init();
}

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

Changing "init()" to "init2()" in the concept definition, a refactoring tool should also be able to find all instances of uses of SomeConcept, and change those places, too.


Re: Refactoring Dynamic Code Posted: Oct 22, 2007 4:33 AM
Reply to this message Reply
Posted by: Kay Schluehr    Posts: 302 / Nickname: schluehk / Registered: Jan, 2005
> Using concepts, you could write the above as:
>

> concept SomeConcept
> {
> void init();
> }
>
> template<SomeConcept T>
> void f1(T t)
> {
> t.init();
> }
>
> template<SomeConcept T>
> void f2(T t)
> {
> t.init();
> }
>

> Changing "init()" to "init2()" in the concept definition,
> a refactoring tool should also be able to find all
> instances of uses of SomeConcept, and change those places,
> too.

That's very nice.

Note that you can annotate Python 3.0 arguments like this:

class SomeConcept:
def init(self):
pass

def f1(t: SomeConcept):
t.init()

def f2(t: SomeConcept):
t.init()

The language will nevertheless be dynamically typed and the annotations are optional and their semantics depends on particular handlers. That says it's not basically an issue about type systems but about abstraction and the provisioning of metadata.


Re: Refactoring Dynamic Code Posted: Oct 22, 2007 11:08 AM
Reply to this message Reply
Posted by: Terje Slettebø    Posts: 205 / Nickname: tslettebo / Registered: Jun, 2004
> > Using concepts, you could write the above as:
> >

> > concept SomeConcept
> > {
> > void init();
> > }
> >
> > template<SomeConcept T>
> > void f1(T t)
> > {
> > t.init();
> > }
> >
> > template<SomeConcept T>
> > void f2(T t)
> > {
> > t.init();
> > }
> >

> > Changing "init()" to "init2()" in the concept
> definition,
> > a refactoring tool should also be able to find all
> > instances of uses of SomeConcept, and change those
> places,
> > too.
>
> That's very nice.
>
> Note that you can annotate Python 3.0 arguments like
> this:
>

> class SomeConcept:
> def init(self):
> pass
>
> def f1(t: SomeConcept):
> t.init()
>
> def f2(t: SomeConcept):
> t.init()
>

> The language will nevertheless be dynamically typed and
> the annotations are optional and their semantics depends
> on particular handlers. That says it's not basically an
> issue about type systems but about abstraction and the
> provisioning of metadata.

Right. However, note that in the C++ case, any violation of the contract (the interface given by the concept) will be caught at compile-time, whereas I assume that the Python annotations - if they are checked - are checked at run-time, so you only find any violation at run-time, if at all.

However, then we get into that static typing vs dynamic typing debate, again. :)

Also note that - for those who may be new to concepts/constrained generics - a "concept" doesn't specify a specific type, only the requirements of the type (at least the compile-time checkable ones), so that instances of both the following classes would match (or "model", in generic programming speak) the concept above:

class A
{
...
void init() { ... }
...
};

class B
{
...
void init() { ... }
...
}

A a;
B b;

f1(a); // Fine
f1(b); // Also fine

In the current concept proposal, you can specify whether a concept would match a type implicitly (without declaring a type to match it, as long as it has the necessary requirements as specified by the concept, or explicityly, where you have to specify that a type matches the concept).

"SomeConcept" in itself is not a type (it might be considered a set of all the types satisfying its requirements), but "T" in the function templates is a specific type ("A" or "B", in this case).

As I understand the Python example above, "SomeConcept" is a type, and in that case, the example isn't analogous to the C++ one, but rather a case of optional (specific) typing, as in:

void f1(SomeConcept t) { ... }

Here, the value passed in must be of type (convertible to) SomeConcept.

A more useful example may make the point of concepts clearer:

concept LessThanComparable<typename T>
{
bool operator<(T,T);
}

template<LessThanComparable T>
const T& min(const T& a, const T& b)
{
return a<b ? a : b;
}

int a=..., b=...;

int result=min(a,b); // Fine

BigInt a=..., b...; // Some user-defined class

BigInt result=min(a,b); // Also fine

But (using the "A" class defined above):

A a(...), b(...);

A result=min(a,b); // Error, "A" doesn't model the LessThanComparable concept


I also need to correct the syntax for the concept definition in my first posting. The actual syntax should be the following:

concept SomeConcept<typename T>
{
T t;

t.init();
}

Anyway, this is a little off topic, perhaps, but I find "concepts" rather interesting. :)


Re: Refactoring Dynamic Code Posted: Oct 26, 2007 9:49 AM
Reply to this message Reply
Posted by: Carson Gross    Posts: 153 / Nickname: cgross / Registered: Oct, 2006
Why is that hard? You look at all the invocation points of f1 and f2 and rename the methods on the set of types currently invoked at them, all of which should be statically knowable.

_shrug_

It's too bad Java gives static typing such a bad name. All we would have to annotate are our fields, method signatures and a few parameterized constructors if they did a bit of work in the compiler.

Cheers,
Carson


Re: Refactoring Dynamic Code Posted: Oct 16, 2007 10:40 PM
Reply to this message Reply
Posted by: Joao Pedrosa    Posts: 114 / Nickname: dewd / Registered: Dec, 2005
Here's some stats from code I care for:

{"count": {
"css_blank": 4,
"css_comment": 6,
"css_css": 229,
"html_blank": 0,
"html_comment": 0,
"html_html": 2097,
"javascript_blank": 64,
"javascript_code": 10584,
"javascript_comment": 156,
"ruby_blank": 15716,
"ruby_code": 51044,
"ruby_comment": 5651},

It's a reasonable size and the way I keep it all working is by always reworking it as I can remove unnecessary lines so I don't have to deal with them in any way. If I had to "spell out" every line of code, it certainly would be much more painful to even look at the code.

Here's how I modularize it:

bases gui_apps libraries models reports services tools web web_apps web_libraries

Also, once I created a Web frontend for my VCS of choice Bazaar, my productivity increased a little more. I created my own line counter as well which has helped me to keep an eye on code. And I even have a custom Web editor which I can use to browse/search/replace/edit the files from the browser itself. One of the things which will help my productivity a little more is a maintenance tool for translations which will be Web based as well (even though I have a small piece of it in GUI).

I have two kinds of search and replace GUI dialogs which are integrated in my text editor. Both use regex, but one searches/replaces only in the file at hand (with previewing of the changes). The other one can search/replace anywhere I choose, multiple files at a time.

Testing is always included in my development cycle. I change and test in any possible way, be it with a unit test or on a live Web site. :-) I'm still adapting myself to unit tests though and eventually I want full reports of it in a Web application as well.

I generally call if "refactoring" if I can see all the code in a computer screen and I know it won't have any side-effects elsewhere. :-) If I'm renaming something in many modules at a time, I might search/replace automatically or do it in a mixed way sometimes, doing it automatically when feasible. It's all about context as well, so standards help to contextualize things and restrict ambiguity/side-effects.

All in all, to the best of my wishful thinking, the best code generation happens at runtime for me. At design time, I hardly want to see any extra code, let alone generated one. Like you say, I still pay a price, but it could be worth it in the end.


Re: Refactoring Dynamic Code Posted: Oct 16, 2007 11:45 PM
Reply to this message Reply
Posted by: Kevin Teague    Posts: 15 / Nickname: wheat / Registered: Mar, 2006
> I wanted to ensure that my refactorings were correctly
> and consistently performed across the entire application
> stack mainly because I felt that in the absence of a
> compile-time type-checking system coding conventions
> became important crutches to lean on for comfort. For the
> same reason, I'm also more reliant on tests in this
> dynamic-language project, and tend to write more tests
> than I would create for, say, a Java application. And, of
> course, refactoring tests is a large part of the effort at
> this point in the project.

Compile-time type-checking can help with some refactoring, but you're going
to need to write a lot of the same tests for both a static or a dynamic language to get the same test coverage.

For example, If you've got an parameter called 'name' and you refactor this from being a username to a full name you are still going to have a string as the input to your method calls ...

Or consider refactoring from 'full_name' and you later decide that you
want to split this out into 'first_name' and 'last_name'. You could still
add a method to your model class that returns 'full_name' as a concatentation
of first and last name - this kind of encapsulation is what you should be using in a dynamic language to avoid having to go through these lengthy
refactoring processes that you are doing.

Rails does lump together functionality in a fairly coarse-grained fashion,
so it can make it a bit more onerous to refactor as the project grows in size.
For example, it tends to produce 'fat Models' where you have a lot of separate
concerns mixed into a single class, and the Views require a level of discipline since they allow arbitrary Ruby code to be embedded in them
(although Rails does have HAML which is quite sexy).

Smalltalk programmers would probably object to the title of this post, as they have some very good refactoring tools.

Also, as a Zope 3 and Grok developer (http://grok.zope.org) I would also have
to object, as using Interfaces in the Zope 3 component architecture can also
avoid some of these problems when using Python.


Re: Refactoring Dynamic Code Posted: Oct 17, 2007 10:06 AM
Reply to this message Reply
Posted by: Kay Schluehr    Posts: 302 / Nickname: schluehk / Registered: Jan, 2005
I'd expect that a proper approach to refactoring of "dynamic code" also requires a shift in perspective which considers the runtime activity ( behaviour | data ) as primary and the code structure as secondary or supportive - at least as far a connectivity graph is concerned that cannot be derived from analyzing source code expressions. The connectivity graph together with type information is created at runtime and its reification serves as hypothetical "static code" that approximates "dynamic code". Maybe one can even go a little further and support live refactoring on a running programming. There are lots of unexplored ideas.


Re: Refactoring Dynamic Code Posted: Oct 17, 2007 5:06 PM
Reply to this message Reply
Posted by: Isaac Gouy    Posts: 527 / Nickname: igouy / Registered: Jul, 2003
Mea Culpa I should have said

"Refactoring Rails Code" would have been a sufficiently bold generalization from your one project ;-)


Re: Refactoring Dynamic Code Posted: Oct 18, 2007 10:35 AM
Reply to this message Reply
Posted by: Rafael Alvarez    Posts: 2 / Nickname: soronthar / Registered: Jan, 2005
The main point (the "tax" that is paid) is not that refactoring is possible/impossible or easy/difficult in dynamic languages. It's how long the refactoring will take, and when you'll know if the change was good or not.

An example on two code bases:
1) One in Java, 320k lines of code, 4k classes, 2k jsp pages.
2) One in Perl, 45k lines of code, about 30 modules.


In Java, rename a method takes 45 seconds to perform, and 3 minutes to check that everything is ok (a full recompile+tests). In Perl, it took 10 minutes looking at a "Find in files" output, analyzing if the method must be renamed or not.

In Java, creating a Base class from an existing class took 40 seconds to create the base class from one class, 5 minutes adjusting things, and 3 minutes to check that everything was ok.

In Perl, it took almost half an hour chasing down the places where the classes where used, changing the references from the subclass to the base class.

I'm sure we can go on and on over all the refactorings in the book, and found that in those cases that they can be automated in static languages and not in dynamic languages, there is a "loss of productivity" of more than a 100%.

Of course, in those static languages that the refactoring support is very poor (poor guys), the gain in productivity and conciseness of some dynamic languages will give a big productivity gain. But for those static language where the refactoring support excels, the productivity gain by the conciseness of the dynamic languages will be more than countered by the loss of productivity when refactoring.

So the problem is that for dynamic languages where the number of refactoring that can be automated or are supported by tools are small, the cost of changing a medium-to-big code base is "big".


Re: Refactoring Dynamic Code Posted: Oct 18, 2007 10:55 AM
Reply to this message Reply
Posted by: Joao Pedrosa    Posts: 114 / Nickname: dewd / Registered: Dec, 2005
Yes, definitely there's no silver bullet with regards to refactoring in all dynamic languages. As a matter of fact, if the dynamic languages depended on refactoring tools to get where they have gotten with regards to progress, they wouldn't have turned their first year as independent languages, let alone growing to powering lots of softwares we depend on on a daily basis. For instance, I use the Bazaar VCS which uses Python for its language, and I don't think those developers have relied on refactoring as you get in Java to get to the point of being very good, close to a blast 1.0 release.


Re: Refactoring Dynamic Code Posted: Oct 18, 2007 11:03 AM
Reply to this message Reply
Posted by: Isaac Gouy    Posts: 527 / Nickname: igouy / Registered: Jul, 2003
Rafael Alvarez wrote
-snip-
> Of course, in those static languages that the refactoring
> support is very poor (poor guys), the gain in productivity
> and conciseness of some dynamic languages will give a big
> productivity gain. But for those static language where the
> refactoring support excels, the productivity gain by the
> conciseness of the dynamic languages will be more than
> countered by the loss of productivity when refactoring.
>
> So the problem is that for dynamic languages where the
> number of refactoring that can be automated or are
> supported by tools are small, the cost of changing a
> medium-to-big code base is "big".

Not knowing anything about Perl the idea that there was refactoring support was really interesting!

But then it turned out you were just comparing a text-editor with a refactoring IDE :-(

You only measured one-side of your comparison - you haven't measured whatever productivity gain dynamic languages may or may not give - so you have no basis for making overall productivity claims.


Re: Refactoring Dynamic Code Posted: Oct 19, 2007 6:44 AM
Reply to this message Reply
Posted by: Eivind Eklund    Posts: 49 / Nickname: eeklund2 / Registered: Jan, 2006
> Of course, in those static languages that the refactoring
> support is very poor (poor guys), the gain in productivity
> and conciseness of some dynamic languages will give a big
> productivity gain. But for those static language where the
> refactoring support excels, the productivity gain by the
> conciseness of the dynamic languages will be more than
> countered by the loss of productivity when refactoring.

Of course, for those cases where you end up reading code at all, the productivity loss due to verbosity of the static languages will more than counter the loss due to increased costs of some kinds of refactoring.

Or at least that is my experience. To me, this obviously depends on how you work, what context you are in, what people you work with, and what codebase you work with - so there is no global answer.

Eivind.


Re: Refactoring Dynamic Code Posted: Oct 19, 2007 8:05 AM
Reply to this message Reply
Posted by: Frank Silbermann    Posts: 40 / Nickname: fsilber / Registered: Mar, 2006
I think you have two issues to sort out. One is the comparative difficulty of refactoring dynamic code, as compared to languages with static typing. The other is the difficulty of refactoring code whose logic is not confined to a single programming language or notation.

As for the first aspect -- refactoring in a dynamic language -- I don't know the answer. I suspect that it the lack of type information may give the IDE less information to work with. On the other hand, there may be more ways to factor out redundancy in a language with dynamic typing.

Aside from the static vs dynamic typic issue, I do think refactoring is going to be very difficult in any framework that scatters programming logic across a variety of technologies -- technologies such as programming language, XML, JSF component definitions, and JSP scriptlets. And this is likely to be no less of a problem with "configuration by convention" -- as the convention also lives outside of the main programming language.

The problem of diverse and redundant notations has two sources: (1) persistance logic and (2) presentation logic.

Persistance logic is difficult to refactor because redundant logic lives in two quite different technologies -- the programming language and the RDBMS. I don't have much to say about this; perhaps a Hibernate expert can elaborate on the issues.

As for the presentation logic, the main thing is to express all of it as Java code, relying on neither XML, scriptlets, custom tags, nor convention. Unfortunately, this rules out use of the vast majority of web frameworks. However, there are (a very few) exceptions.

One such exception is the Wicket web framework. Wicket allows you to put ALL of your presentation logic in POJOs. Add to that the right persistence framework, and your problem is solved.


Re: Refactoring Dynamic Code Posted: Nov 22, 2007 4:04 AM
Reply to this message Reply
Posted by: Daesung Park    Posts: 10 / Nickname: grayger / Registered: Apr, 2006
Renaming a variable or class name is easiest refactoring in Java world. But renaming seems to be a unreachable goal in dynamic languages. Tools don't know a programmer's intention of refactoring and can't predict future execution flow.

I feel more pressure to follow coding convention wriging code in static type language than dynamic type language. When writing Java code, I checks code style or probable bugs with PMD and Findbugs. On the other hand, when writing JavaScript, Python, and TCL code, I even don't care variable naming. In fact, there is no counterpart tools for dynamic languages as far as I know.


Topic: Refactoring Dynamic Code Previous Topic   Next Topic Topic: Aren't C++ Programmers People Too?

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use