Re: refactoring AP_*Frame


Subject: Re: refactoring AP_*Frame
From: Paul Rohr (paul@abisource.com)
Date: Thu Apr 26 2001 - 06:37:51 CDT


At 10:09 AM 4/26/01 +0200, Hubert Figuiere wrote:
>According to Paul Rohr <paul@abisource.com>:
>>
>> I'm curious. If it's "just" a bunch of cut-and-paste code, why would we
>> need to break the tree to get it refactored? In theory, it should be safe
>> to replace the N duplicate references with the relevant XP call, no?
>>
>Just because in those cut & paste code, the only difference comes
>from platform object instantiation.

Hmm. I guess I'm still missing something here, because this still sounds
like a tree-wide change to me. The most important work in this kind of
refactoring is guaranteeing that each platform can still do what it already
does.

To start with a simple hypothetical example, say that we have six platform
implementations of a particular virtual method that all look more or less
like this:

OS::doFoo(...)
{
    /* 50 lines of XP cut-n-paste code */
   
    /* 10 lines of platform-specific code */

    /* 100 more lines of XP cut-n-paste code */
}

The idea of refactoring would be to move that identical code out of the OS
implementations into a single XP spot *without* breaking any of them. Thus
a naive end result might be:

XP::doFoo1(...)
{
    /* 50 lines of XP cut-n-paste code */
}

XP::doFoo2(...)
{
    /* 100 more lines of XP cut-n-paste code */
}

OS::doFoo(...)
{
    XP_doFoo1(..)
   
    /* 10 lines of platform-specific code */

    XP_doFoo2(..)
}

Note that in this case, the change to each platform would be to delete big
chunks of cut-and-paste code and replace it with an XP call.

However, since we're C++, we could refactor the code differently using
virtual methods, to wind up with something much cleaner, like:

XP::doFoo(...)
{
    /* 50 lines of XP cut-n-paste code */
   
    /* call virtual method implemented in platform code */
    _doFoo();

    /* 100 more lines of XP cut-n-paste code */
}

OS::_doFoo(...)
{
    /* 10 lines of platform-specific code */
}

Again, the change needed on each platform is to delete the code which got
removed to XP land, and wrap the remaining logic inside the new APIs
required. Other than that, is there anything inherently platform-specific
about such a change?

The only way to know that any such refactoring will work for all platforms
is to *look* at all the existing platform implementations, and then actually
remap the code to make sure it can fit inside the proposed new API.

In particular, whoever's doing the refactoring needs to notice that the
implementation for platform 6, say, doesn't fit the pattern described above,
because it actually looks like this:

OS6::doFoo(...)
{
    /* 50 lines of XP cut-n-paste code */
   
    /* 10 lines of platform-specific code */

    /* 60 more lines of XP cut-n-paste code */

    /* 5 lines of platform-specific code */

    /* 40 more lines of XP cut-n-paste code */
}

Thus, the XP refactoring actually needed [1] would be more like:

XP::doFoo(...)
{
    /* 50 lines of XP cut-n-paste code */
   
    _doFoo1();

    /* 60 more lines of XP cut-n-paste code */

    _doFoo2();

    /* 40 more lines of XP cut-n-paste code */
}

OS::_doFoo1(...)
{
    /* 10 lines of platform-specific code */
}

OS::_doFoo2(...)
{
    /*
        5 lines of platform-specific code on OS6,
        and nothing on the other platforms
     */
}

If so, I can't think of any reason why whoever does the XP implementation
shouldn't just do the necessary changes for all platforms, because they
simply can't get the refactoring "right" any other way.

Admittedly, there might be some cut-and-paste errors, but that's what
Tinderbox is for.

>For this we need to provide a static
>constructor for the xp class that is implemented by the platform class.
>So until the platform maintainer implements it, the link will fail.

The hypothetical refactorings I described above didn't use static
constructors, but wouldn't the same principle apply?

Some amount of existing platform code should survive the refactoring, but be
located in new spots. The only *new* code needed on each platform *is* a
cut-and-paste job, and thus should be done once for all platforms at
refactoring time.

What am I missing here?

Paul,
who's made more than his share of tree-wide changes

[1] Note that the variation here *could* be gratuitous, so it might be
worth asking the OS6 maintainer whether all the platform-specific logic
could be called in a single _doFoo() spot. However, from past experience
with this kind of thing, the answer is often "no".



This archive was generated by hypermail 2b25 : Thu Apr 26 2001 - 06:30:18 CDT