Hi all,
I noticed an issue in the way we deal with class renames and instance migrations in our application upgrades. In summary, when we left an ‘old’ class (which was ‘renamed' to a ‘new’ class) in the code base during future upgrades, we could inadvertently trigger a migration of the instances of the 'new’ class back to the ‘old’ class. This is because both the ‘old’ and ‘new’ classes share their classHistory and we load application upgrades with Metacello/Monticello and GsDeployer, which also handles classHistory. Perhaps there are better ways of handling class renames than what we do? How do other people on the mailinglist handle these? What we do to handle a class rename in a upgrade of our application code: 1) We keep both the ‘old' class (with the old name) and the ‘new' class (with the new name) in our code base. 2) We load the application code upgrade in our database using Metacello and GsDeployer bulkmigrate. 3) We handle the class rename and migrate all instances as follows: SomeOldClass addNewVersion: TheNewClass. SomeOldClass migrateInstancesTo: TheNewClass. 4) We remove the old class from the system: SomeOldClass removeFromSystem When we do not do step 4 and we keep SomeOldClass in our code base, subsequent class changes on TheNewClass could trigger the GsDeployer bulk migration to migrate instances of TheNewClass back to SomeOldClass before migrating to the last version of TheNewClass. When we inspect the classHistory of both classes, we notice they are shared and can look like this: SomeOldClass -> TheNewClass -> SomeOldClass -> TheNewClass -> SomeOldClass. It all depends on the changes to SomeOldClass and TheNewClass, package load order, etc… wether or not this would eventually end up in a good state (but most probably not). So, we avoid this issue by explicitly removing the class now in step 4. So, we only figured this out because we had not done step 4 in migrations in early years and we kept the old classes for ‘legacy’ in our code base. The main question is: is this a good way to deal with class renames in application upgrades? thanks for any thoughts! Johan _______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass |
Hi,
I attach a package with all our migration code if you want to dig. You're welcome to use it or copy some bits. > Perhaps there are better ways of handling class renames than what we do? How do other people on the mailinglist handle these? Not sure if what we do is really better; perhaps we can come up with something better after some discussion. > What we do to handle a class rename in a upgrade of our application code: > > 1) We keep both the ‘old' class (with the old name) and the ‘new' class (with the new name) in our code base. We do not keep the old class name in our code base. Essentially we use Metaclass3 allInstances to find all the classes in the system and work from there. > 2) We load the application code upgrade in our database using Metacello and GsDeployer bulkmigrate. Also load using Metacello, but do not use GsDeployer. We load all the code first and then do migrations with the attached code. Here's how we call it: Migrator new packageNames: BaselineOfWonkaProjects allPackageNames; "all our packages / the ones we're interested in migrating" migrateAll; "the main entry point" nilFields. "To help GC" > 3) We handle the class rename and migrate all instances as follows: > > SomeOldClass addNewVersion: TheNewClass. > SomeOldClass migrateInstancesTo: TheNewClass. The attached code does this kind of thing automatically if you implement a hook (class) method: TheNewClass class >> classNamesToRenameFrom ^ #(#SomeOldClass) You can have multiple old names if you're consolidating more than one class into a new one > 4) We remove the old class from the system: > > SomeOldClass removeFromSystem Have never used this. We have old classes in our systems. Some time ago, I tried hard to figure out how to get a class garbage collected. Never could. Perhaps this will work. We do checks at the end of the migration process that detached classes should not have instances. > When we do not do step 4 and we keep SomeOldClass in our code base, subsequent class changes on TheNewClass could trigger the GsDeployer bulk migration to migrate instances of TheNewClass back to SomeOldClass before migrating to the last version of TheNewClass. When we inspect the classHistory of both classes, we notice they are shared and can look like this: SomeOldClass -> TheNewClass -> SomeOldClass -> TheNewClass -> SomeOldClass. It all depends on the changes to SomeOldClass and TheNewClass, package load order, etc… wether or not this would eventually end up in a good state (but most probably not). So, we avoid this issue by explicitly removing the class now in step 4. We are a bit more pedantic about cleaning up the classHistory (see tearDownClassHistoryForMigratingFromClass:). After a migration run, all classes should have only itself in its own classHistory. > > So, we only figured this out because we had not done step 4 in migrations in early years and we kept the old classes for ‘legacy’ in our code base. The main question is: is this a good way to deal with class renames in application upgrades? Our way of working is to remove the legacy class from the code base asap HTH Otto _______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass Wonka-Migrations-Core-otto.1235.mcz (13K) Download Attachment |
Thanks for the feedback Otto. I’m going to take a look at your migration code. Thanks for sharing.
> On 27 Apr 2016, at 16:16, Otto Behrens <[hidden email]> wrote: > > Hi, > > I attach a package with all our migration code if you want to dig. > You're welcome to use it or copy some bits. > >> Perhaps there are better ways of handling class renames than what we do? How do other people on the mailinglist handle these? > > Not sure if what we do is really better; perhaps we can come up with > something better after some discussion. > >> What we do to handle a class rename in a upgrade of our application code: >> >> 1) We keep both the ‘old' class (with the old name) and the ‘new' class (with the new name) in our code base. > > We do not keep the old class name in our code base. Essentially we use > > Metaclass3 allInstances > > to find all the classes in the system and work from there. > >> 2) We load the application code upgrade in our database using Metacello and GsDeployer bulkmigrate. > > Also load using Metacello, but do not use GsDeployer. We load all the > code first and then do migrations with the attached code. Here's how > we call it: > > Migrator new > packageNames: BaselineOfWonkaProjects allPackageNames; > "all our packages / the ones we're interested in migrating" > migrateAll; "the main entry point" > nilFields. "To help GC" > >> 3) We handle the class rename and migrate all instances as follows: >> >> SomeOldClass addNewVersion: TheNewClass. >> SomeOldClass migrateInstancesTo: TheNewClass. > > The attached code does this kind of thing automatically if you > implement a hook (class) method: > > TheNewClass class >> classNamesToRenameFrom > ^ #(#SomeOldClass) > > You can have multiple old names if you're consolidating more than one > class into a new one > >> 4) We remove the old class from the system: >> >> SomeOldClass removeFromSystem > > Have never used this. We have old classes in our systems. Some time > ago, I tried hard to figure out how to get a class garbage collected. > Never could. Perhaps this will work. > > We do checks at the end of the migration process that detached classes > should not have instances. > >> When we do not do step 4 and we keep SomeOldClass in our code base, subsequent class changes on TheNewClass could trigger the GsDeployer bulk migration to migrate instances of TheNewClass back to SomeOldClass before migrating to the last version of TheNewClass. When we inspect the classHistory of both classes, we notice they are shared and can look like this: SomeOldClass -> TheNewClass -> SomeOldClass -> TheNewClass -> SomeOldClass. It all depends on the changes to SomeOldClass and TheNewClass, package load order, etc… wether or not this would eventually end up in a good state (but most probably not). So, we avoid this issue by explicitly removing the class now in step 4. > > We are a bit more pedantic about cleaning up the classHistory (see > tearDownClassHistoryForMigratingFromClass:). After a migration run, > all classes should have only itself in its own classHistory. > >> >> So, we only figured this out because we had not done step 4 in migrations in early years and we kept the old classes for ‘legacy’ in our code base. The main question is: is this a good way to deal with class renames in application upgrades? > > Our way of working is to remove the legacy class from the code base asap > > HTH > Otto > <Wonka-Migrations-Core-otto.1235.mcz> _______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass |
In reply to this post by GLASS mailing list
Otto,
I noticed that you mentioned that you don't use GsDeployer --- and that makes perfect sense. With that said, I've created a subclass of GsDeployer called GsNonmigratingDeployer[1] that can be used to make GsDeployer a little more friendly for folks who want to manage their own migrations by unconditionally bypassing the standard GsDeployer migration logic ... The main rationale is to allow you (and others) to "disable" GsDeployer so that accidental invocation in scripts or tools won't undo any carefully laid migration plans. One "permanently disable GsDeployer" with the following: GsNonmigratingDeployer select; System commit. or temporarily disable migrations by using GsDeployer class>>noMigrationDuring:. Dale [1] https://github.com/GsDevKit/GsDevKit/issues/91 On 04/27/2016 07:16 AM, Otto Behrens
via Glass wrote:
Hi, I attach a package with all our migration code if you want to dig. You're welcome to use it or copy some bits.Perhaps there are better ways of handling class renames than what we do? How do other people on the mailinglist handle these?Not sure if what we do is really better; perhaps we can come up with something better after some discussion.What we do to handle a class rename in a upgrade of our application code: 1) We keep both the ‘old' class (with the old name) and the ‘new' class (with the new name) in our code base.We do not keep the old class name in our code base. Essentially we use Metaclass3 allInstances to find all the classes in the system and work from there.2) We load the application code upgrade in our database using Metacello and GsDeployer bulkmigrate.Also load using Metacello, but do not use GsDeployer. We load all the code first and then do migrations with the attached code. Here's how we call it: Migrator new packageNames: BaselineOfWonkaProjects allPackageNames; "all our packages / the ones we're interested in migrating" migrateAll; "the main entry point" nilFields. "To help GC"3) We handle the class rename and migrate all instances as follows: SomeOldClass addNewVersion: TheNewClass. SomeOldClass migrateInstancesTo: TheNewClass.The attached code does this kind of thing automatically if you implement a hook (class) method: TheNewClass class >> classNamesToRenameFrom ^ #(#SomeOldClass) You can have multiple old names if you're consolidating more than one class into a new one4) We remove the old class from the system: SomeOldClass removeFromSystemHave never used this. We have old classes in our systems. Some time ago, I tried hard to figure out how to get a class garbage collected. Never could. Perhaps this will work. We do checks at the end of the migration process that detached classes should not have instances.When we do not do step 4 and we keep SomeOldClass in our code base, subsequent class changes on TheNewClass could trigger the GsDeployer bulk migration to migrate instances of TheNewClass back to SomeOldClass before migrating to the last version of TheNewClass. When we inspect the classHistory of both classes, we notice they are shared and can look like this: SomeOldClass -> TheNewClass -> SomeOldClass -> TheNewClass -> SomeOldClass. It all depends on the changes to SomeOldClass and TheNewClass, package load order, etc… wether or not this would eventually end up in a good state (but most probably not). So, we avoid this issue by explicitly removing the class now in step 4.We are a bit more pedantic about cleaning up the classHistory (see tearDownClassHistoryForMigratingFromClass:). After a migration run, all classes should have only itself in its own classHistory.So, we only figured this out because we had not done step 4 in migrations in early years and we kept the old classes for ‘legacy’ in our code base. The main question is: is this a good way to deal with class renames in application upgrades?Our way of working is to remove the legacy class from the code base asap HTH Otto _______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass |
Free forum by Nabble | Edit this page |