Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Differentiate between upgrade and new install #3

Open
Sjors opened this issue Mar 29, 2013 · 17 comments
Open

Differentiate between upgrade and new install #3

Sjors opened this issue Mar 29, 2013 · 17 comments

Comments

@Sjors
Copy link

Sjors commented Mar 29, 2013

A common use case for me is to distinguish new installs from updates. Often I need to correct something in the database of old users, but don't touch it for fresh installs (because it's fixed out of the box for them).

Perhaps something like this would make sense:

[MTMigration migrateToVersion:@"1.1" block:^{
    if([[MTMigration firstVersionKnownOnThisDevice] isEqualToString:@"1.1"]) {
        // Treat new users differently
    }
    [obj doSomeDataStuff];
}];

I try to avoid this situation; if often happens when you ship some initial data with the app and the app doesn't sync with a server.

@pwightman
Copy link
Member

This is a great point, I've been thinking about this for a while too. I had been thinking about an API like:

[MTMigration migrateFromVersion:@"1.0" block:^{ ... }];

That way you could use migrateFromVersion when you need to correct something from a previous version, and migrateToVersion when it's something related to the new version (database migrations, etc.)

Does that work for the situations you are thinking? Or is it not granular enough?

@Sjors
Copy link
Author

Sjors commented Mar 29, 2013

It doesn't always make sense to "blame" a specific previous version, so although this would work for me, it might be confusing.

@pwightman
Copy link
Member

True, both have their uses. If you have time to make a pull request with this change, that'd be great, otherwise I can look into it sometime next week. The only change I'd make is to name the method firstKnownVersion.

@Sjors
Copy link
Author

Sjors commented Mar 29, 2013

Another solution is to only run a migration if MTMigration knows that there has been a previous version. So if a user installs version 1.1 from the app store, migrateToVersion:@"1.1" should not run. It should only run if he updated from an earlier version.

This means that it should track each new version, even if there is no migration. It's also not backwards compatible, so you'd need a new method name for it.

@Sjors
Copy link
Author

Sjors commented Mar 29, 2013

I'd like to use it in some other projects first before I change anything.

@pwightman
Copy link
Member

I'd have to flesh out the details a bit of whether I like the idea of not migrating on fresh installs. Initially, I can't see a problem though, since migrating on v1.0 of your app doesn't really make sense/isn't necessary.

@Sjors
Copy link
Author

Sjors commented Mar 29, 2013

Many apps do something specifically on their first run, such as creating the sqlite file for Core Data and populating it with some initial data. I don't think that belongs in a migration. I also think it makes sense to improve such code on each version, so that new users get the latest version instantly. I think that's better than the alternative: always starting with the initial version and then applying fixes one by one through migrations. Mostly because that's very error prone and partially because it could be slow.

That would be my argument in favor for not migrating on fresh installs.

I also suspect that Core Data works this way too; i.e. it won't look at old versions unless it needs to migrate.

On the other hand, all past Ruby on Rails migrations are run even when you install it on a fresh server. Of course that doesn't happen very often and it's also a best practice to delete these migrations every once in a while and replace them with what's in schema.rb (if you're sure none of your servers or colleagues still needs those migrations). You're also not supposed to populate a database using migrations in Rails.

But it's probably a good idea to sleep on this for a while :-)

@jeddison
Copy link

jeddison commented Jun 5, 2013

Have you had any further thought on this topic?

Whilst initially thinking that a migration on a new install was inefficient, I realised that in practise I can remove old intermediate migrations from the code as there is only ever the one new version available. That reduces the potential errors and slow down for me at least.

However I think it would still be useful to be able to distinguish between a new install or upgrade, so would welcome a - (BOOL) firstVersionKnownOnThis Device (or similar) method. Beyond data updates, a scenario for using this could be as simple as displaying a different welcome message.

@peymano
Copy link

peymano commented Jul 8, 2013

👍 to not running migrations on first install.

@pwightman
Copy link
Member

@jeddison That was exactly my thinking, that if you don't want migrations to run anymore then they should just be removed.

Differentiating between new install and upgrade is certainly helpful, I agree. The one hard part about it is that I couldn't think of a way to make the method 100% reliable in all cases because it's hard to distinguish between an upgrade and a fresh install. MTMigration keeps track of it, so as long as you had MTMigration in your app from your first release, then a migrateOnFreshInstall method (or whatever) would be reliable. However, if you added MTMigration on your second release (or anytime thereafter) then I couldn't think of a way to distinguish between an upgrade and a fresh install since from MTMigration's point of view, they would both look like fresh installs.

It's also worth noting that this has implications on whether to run general migrations on first install or not for the same reasons. /cc @peymano

If you have any thoughts on ways around this, I'm more than willing to hear it. I hesitate to add a method that only sometimes works as advertised, but if there's really no possible way around this, then it's probably worth adding the method anyway with clear disclaimers. Discussions and pull requests welcome if this is something you're currently working on in your apps.

@ageorgios
Copy link

+1 for migrateFromLowerVersionThan

or

(BOOL)shouldPerformMigration

@fechu
Copy link
Contributor

fechu commented Jan 3, 2014

Or we chould just add a method like this

+ (BOOL)isCleanInstall;

and let the users do whatever they want with it. 😄
I would like to see this in MTMigration and would also implement it. Just tell me, what you want.

@timshadel
Copy link

I think it's backwards to ask MTMigration to figure out if it's a new install. Instead, we can avoid old migrations if we can tell MTMigration that this is a new install. One way is to look at the app store receipt (search pods), but really you can look at the file system or NSUserDefaults or Keychain or really anything you want. From there, we tell MTMigration that all the migrations up through the current version have been run.

This is workable even now with class extension to expose the methods. It'll avoid running older migrations.

[MTMigration setLastMigrationVersion:[MTMigration appVersion]];

We could hide the detail behind a new method.

[MTMigration markAsNewInstall];

We can use the existing applicationUpdateBlock: to run the install check before any of our migrateToVersion: calls.

[MTMigration applicationUpdateBlock:^{
    // Check if this is a new install
    if (freshInstall) {
      // also run install steps here
      [MTMigration markAsNewInstall];
    }
}];

[MTMigration migrateToVersion:@"0.9" block:^{
    // Some 0.9 stuff
}];

[MTMigration migrateToVersion:@"1.0" block:^{
    // Some 1.0 stuff
}];

Thoughts?

@peymano
Copy link

peymano commented Aug 24, 2014

I've been using MTMigration for a while now and while I originally thought
I needed this feature, I've done without it and I don't think it's
necessary. It's been easy to write migrations that become no-ops for
first-time installs.

On Aug 23, 2014, at 6:00 PM, Tim Shadel notifications@github.com wrote:

I think it's backwards to ask MTMigration to figure out if it's a new
install. Instead, we can avoid old migrations if we can tell MTMigration
that this is a new install. One way is to look at the app store receipt
(search pods), but really you can look at the file system or NSUserDefaults
or Keychain or really anything you want. From there, we tell MTMigration
that all the migrations up through the current version have been run.

This is workable even now with class extension to expose the methods. It'll
avoid running older migrations.

[MTMigration setLastMigrationVersion:[MTMigration appVersion]];

We could hide the detail behind a new method.

[MTMigration markAsNewInstall];

We can use the existing applicationUpdateBlock: to run the install check
before any of our migrateToVersion: calls.

[MTMigration applicationUpdateBlock:^{
// Check if this is a new install
if (freshInstall) {
// also run install steps here
[MTMigration markAsNewInstall];
}}];
[MTMigration migrateToVersion:@"0.9" block:^{
// Some 0.9 stuff}];
[MTMigration migrateToVersion:@"1.0" block:^{
// Some 1.0 stuff}];

Thoughts?


Reply to this email directly or view it on GitHub
#3 (comment)
.

@ajmccall
Copy link
Contributor

Hi, I created a pull-request for this. #25

I agree though with @pwightman concerns, mostly that

I hesitate to add a method that only sometimes works as advertised, but if there's really no possible way around this, then it's probably worth adding the method anyway with clear disclaimers.

I can't for the life of me workout how to detect a try first install, or the first time MTMigration has been used in the project.

Thoughts?

@revolter
Copy link

Is this maintained anymore?

@XabierGoros
Copy link

I miss to the same option in this library. It would be nice to include this check to avoid unnecessary migration blocks or custom boiler plate checks in our AppDelegate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants