Refactoring Views

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Refactoring Views

Martin Rubi
Hello everyone.

I wish to do some refactoring on a class widely used by some of my views.
The refactoring consists in renaming the class WindowBackPainter, making it
a subclass of a new abstract class ViewPainter, pushing up some of it's
intance variables and methods, removing others and changing some of it's
publishedAspectsOfInstances.

I have already done many views that have an instance variable holding an
instance of WindowBackPainter, and I've read in the archives that doing this
kind of changes on Views can result in a headache.
For what i've read, my alternatives are:
- increase the version number of WindowBackPainter class, and write the
stbConvertFromX: to make old instances become new ones.
- open every view that holds a WindowBackPainter, refactor, and save them
again.

Am I making a problem out of nothing, or this kind of refactoring really are
problematic ? What would you say is the simplest way to deal with this ?
Thanks in advance.

Martin


Reply | Threaded
Open this post in threaded view
|

Re: Refactoring Views

Schwab,Wilhelm K
Martin,

> I wish to do some refactoring on a class widely used by some of my views.
> The refactoring consists in renaming the class WindowBackPainter, making it
> a subclass of a new abstract class ViewPainter, pushing up some of it's
> intance variables and methods, removing others and changing some of it's
> publishedAspectsOfInstances.

Afterward, you might want to assign a global named WindowBackPainter
that points to the renamed class.  You will still have to keep the STB
versions correct, etc.


> I have already done many views that have an instance variable holding an
> instance of WindowBackPainter, and I've read in the archives that doing this
> kind of changes on Views can result in a headache.

Is WindowBackPainter not a View subclass?  If it is indeed not, then STB
versioning, as you describe below, if probably going to be sufficient.
Note that you might want to load/save all of your view resources to
avoid their invoking the conversions every time they are reloaded.  They
will do it happily (if it all works), but you can avoid any resulting
inefficiency by resaving.


> For what i've read, my alternatives are:
> - increase the version number of WindowBackPainter class, and write the
> stbConvertFromX: to make old instances become new ones.

Don't forget the boiler plate #stbConvertFrom:.  Incremental conversions
are they way to go.


> - open every view that holds a WindowBackPainter, refactor, and save them
> again.
>
> Am I making a problem out of nothing, or this kind of refactoring really are
> problematic ? What would you say is the simplest way to deal with this ?
> Thanks in advance.

You appear to be on top of it; either should work.  My recommendation is
to make a backup and try the STB conversion; then open and resave views
(both as a test and for efficiency in the future).

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Refactoring Views

Martin Rubi
Bill, I will try the STB conversion as you recommened.
I haven't thought about the global poiting the new class nor about loading
and saving all my views at once after increasing the version. This will let
me definitly forget about the versioning.
Thanks !

Martin

"Bill Schwab" <[hidden email]> escribió en el mensaje
news:cte6sf$r5a$[hidden email]...
> Martin,
>
> > I wish to do some refactoring on a class widely used by some of my
views.
> > The refactoring consists in renaming the class WindowBackPainter, making
it

> > a subclass of a new abstract class ViewPainter, pushing up some of it's
> > intance variables and methods, removing others and changing some of it's
> > publishedAspectsOfInstances.
>
> Afterward, you might want to assign a global named WindowBackPainter
> that points to the renamed class.  You will still have to keep the STB
> versions correct, etc.
>
>
> > I have already done many views that have an instance variable holding an
> > instance of WindowBackPainter, and I've read in the archives that doing
this

> > kind of changes on Views can result in a headache.
>
> Is WindowBackPainter not a View subclass?  If it is indeed not, then STB
> versioning, as you describe below, if probably going to be sufficient.
> Note that you might want to load/save all of your view resources to
> avoid their invoking the conversions every time they are reloaded.  They
> will do it happily (if it all works), but you can avoid any resulting
> inefficiency by resaving.
>
>
> > For what i've read, my alternatives are:
> > - increase the version number of WindowBackPainter class, and write the
> > stbConvertFromX: to make old instances become new ones.
>
> Don't forget the boiler plate #stbConvertFrom:.  Incremental conversions
> are they way to go.
>
>
> > - open every view that holds a WindowBackPainter, refactor, and save
them
> > again.
> >
> > Am I making a problem out of nothing, or this kind of refactoring really
are

> > problematic ? What would you say is the simplest way to deal with this ?
> > Thanks in advance.
>
> You appear to be on top of it; either should work.  My recommendation is
> to make a backup and try the STB conversion; then open and resave views
> (both as a test and for efficiency in the future).
>
> Have a good one,
>
> Bill
>
> --
> Wilhelm K. Schwab, Ph.D.
> [hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Refactoring Views

Schwab,Wilhelm K
Martin,

> Bill, I will try the STB conversion as you recommened.
> I haven't thought about the global poiting the new class nor about loading
> and saving all my views at once after increasing the version. This will let
> me definitly forget about the versioning.

I'm not sure what you mean.  With the global, I am assuming that you
will still version the changed class, because the serialized instances
will have the old instance variable layout and the old version number.
All the global does is allow them to work after the rename - and I've
never actually tried it :)

Make a backup first and have fun.

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Refactoring Views

Blair McGlashan-3
In reply to this post by Martin Rubi
"Martin" <[hidden email]> wrote in message
news:[hidden email]...

> Hello everyone.
>
> I wish to do some refactoring on a class widely used by some of my views.
> The refactoring consists in renaming the class WindowBackPainter, making
> it
> a subclass of a new abstract class ViewPainter, pushing up some of it's
> intance variables and methods, removing others and changing some of it's
> publishedAspectsOfInstances.
>
> I have already done many views that have an instance variable holding an
> instance of WindowBackPainter, and I've read in the archives that doing
> this
> kind of changes on Views can result in a headache.
> For what i've read, my alternatives are:
> - increase the version number of WindowBackPainter class, and write the
> stbConvertFromX: to make old instances become new ones.
> - open every view that holds a WindowBackPainter, refactor, and save them
> again.
>
> Am I making a problem out of nothing, or this kind of refactoring really
> are
> problematic ? What would you say is the simplest way to deal with this ?
> Thanks in advance.

During development by far the simplest option is to open all referencing
view resources in View Composers. Then make your changes, and resave all the
edited views. For many shape changes you won't need to do anything else
since the system's normal instance migration capabilities will do all that
is needed, but you may have to patch up some of the open instances depending
on how you approach it, e.g. you might add new instance variables that you
need to initialise. When I get a chance I'll post up a little script that
opens VCs on all view resources that either contain instances of a a
particular class or which reference it in some other way.

You only need to bother writing STB conversions when there are pre-existing
view resources that you can't load up, or in cases where you don't know
whether any resources in packages you do not have loaded might contain such
instances. Assuming that you aren't developing classes that are used in
other projects, it is possible to avoid the need to write STB conversions at
all if you are careful.

If you do need to write STB conversions, then typically this is
straightforward, particularly if the class you are modifying has no
subclasses. Things get more complicated when one modifies a class with
subclasses where one or more of the subclasses have their own pre-existing
STB conversions, but it can be managed with care. You can find examples of
differing levels of complexity of conversion, and different approaches, in
the standard image.

A useful tip when renaming a class is to create an aliasing global that
retains the old name to the class. The package system recognises such
aliased class names and can store them correctly.

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: Refactoring Views (and models too)

Louis Sumberg-3
Blair McGlashan wrote:

> During development by far the simplest option is to open all referencing
> view resources in View Composers. Then make your changes, and resave all the
> edited views.

FWIW, this _type_ of approach also works when saving models to file
using STB.  In particular, I use alot of shells descended from
DocumentShell, which has builtin #fileSave that uses STB.  If I make a
change to my model definition, i.e., add/remove instance variables, I
will first open an instance of my app on each saved model file (during
development there's usually only one or two), then make the class
definition change and then save each model file.  That allows me to
avoid defining stb version methods.

As Blair pointed out, one thing to remember is that the state of new
variables will be nil, so if the model expects a non-nil value, I'll set
these values by hand (or define a lazy accessor) before saving things
back.  E.g., let's say I add a boolean instance variable named
isSomething to the model.  In the model's #initialize method I'll add a
line like
     isSomething := true.
Then, in a browser, I'll execute something like
     MyModel allInstances do: [:e | e isSomething: true]
and then do a #fileSave.

-- Louis


Reply | Threaded
Open this post in threaded view
|

Re: Refactoring Views

Martin Rubi
In reply to this post by Blair McGlashan-3
Hello Blair.

Your explanations are very clear, thanks a lot.

So, if I understood correctly, opening all the involved Views during the
refactoring and saving them back again will be enough.

Since suspect I will want to do this same procedure quite often, I have done
a tool to let me select the resources I will want to keep opened during the
refactoring. The tool is very raw and I think it needs some more work, but
I've tested a little and the results were good enough for me. I can now open
a shell that let's me filter resources by packages and classes, then select
some or all of them and load them without actually opening any ViewComposer.
Then, when I'm done changing things, I can just save them or unload them
all, and that's it.
Currently I'm using it to load every resource in every package of my own.
It's not sutil, but I'm sure every view is updated this way.
If anyone is interested in this incipient tool, let me know and I'll just
send it.

Regards and thanks again.
Martin

> > Hello everyone.
> >
> > I wish to do some refactoring on a class widely used by some of my
views.

> > The refactoring consists in renaming the class WindowBackPainter, making
> > it
> > a subclass of a new abstract class ViewPainter, pushing up some of it's
> > intance variables and methods, removing others and changing some of it's
> > publishedAspectsOfInstances.
> >
> > I have already done many views that have an instance variable holding an
> > instance of WindowBackPainter, and I've read in the archives that doing
> > this
> > kind of changes on Views can result in a headache.
> > For what i've read, my alternatives are:
> > - increase the version number of WindowBackPainter class, and write the
> > stbConvertFromX: to make old instances become new ones.
> > - open every view that holds a WindowBackPainter, refactor, and save
them
> > again.
> >
> > Am I making a problem out of nothing, or this kind of refactoring really
> > are
> > problematic ? What would you say is the simplest way to deal with this ?
> > Thanks in advance.
>
> During development by far the simplest option is to open all referencing
> view resources in View Composers. Then make your changes, and resave all
the
> edited views. For many shape changes you won't need to do anything else
> since the system's normal instance migration capabilities will do all that
> is needed, but you may have to patch up some of the open instances
depending
> on how you approach it, e.g. you might add new instance variables that you
> need to initialise. When I get a chance I'll post up a little script that
> opens VCs on all view resources that either contain instances of a a
> particular class or which reference it in some other way.
>
> You only need to bother writing STB conversions when there are
pre-existing
> view resources that you can't load up, or in cases where you don't know
> whether any resources in packages you do not have loaded might contain
such
> instances. Assuming that you aren't developing classes that are used in
> other projects, it is possible to avoid the need to write STB conversions
at

> all if you are careful.
>
> If you do need to write STB conversions, then typically this is
> straightforward, particularly if the class you are modifying has no
> subclasses. Things get more complicated when one modifies a class with
> subclasses where one or more of the subclasses have their own pre-existing
> STB conversions, but it can be managed with care. You can find examples of
> differing levels of complexity of conversion, and different approaches, in
> the standard image.
>
> A useful tip when renaming a class is to create an aliasing global that
> retains the old name to the class. The package system recognises such
> aliased class names and can store them correctly.
>
> Regards
>
> Blair
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Refactoring Views

Blair McGlashan-3
"Martin" <[hidden email]> wrote in message
news:41fe4c71$[hidden email]...
> Hello Blair.
>
> Your explanations are very clear, thanks a lot.
>
> So, if I understood correctly, opening all the involved Views during the
> refactoring and saving them back again will be enough.

It will be enough to ensure that any schema changes you make that can be
applied through the standard schema migration performed by the ClassBuilder
are reflected in the resources as well as any other instances. What this
means is that the shape of the objects will be correct after the change, but
it doesn't necessarily mean the objects will be valid. For example you might
introduce new instance variables; these will be nil in any pre-existing
instances, which might not be a valid state for the object.

>
> Since suspect I will want to do this same procedure quite often, I have
> done
> a tool to let me select the resources I will want to keep opened during
> the
> refactoring. The tool is very raw and I think it needs some more work, but
> I've tested a little and the results were good enough for me. I can now
> open
> a shell that let's me filter resources by packages and classes, then
> select
> some or all of them and load them without actually opening any
> ViewComposer.
> Then, when I'm done changing things, I can just save them or unload them
> all, and that's it.
> Currently I'm using it to load every resource in every package of my own.
> It's not sutil, but I'm sure every view is updated this way.

You can identify all view resources that reference a class like this:

    aClass := TextEdit. "for example"
    SessionManager current resourceManager allResourceIdentifiers
        select: [:each | each resource hiddenClassReferences includes:
aClass]


> If anyone is interested in this incipient tool, let me know and I'll just
> send it.

Good idea. Of course this suggests an obvious enhancement to the system,
i.e. to identify and load resources that might be affected automatically
before making any changes to the shape of classes, saving the resources
again after the change. I think a confirmation prompt would be appropriate
where resources are found. Also there is potential to render the resources
unloadable, so it would have to be undoable as part of the composite class
change. I don't know why we didn't think of it before!

Thanks

Blair