 			uuid = uuid.value
 
 			deviceId = device.getID()
-
-			remoteApps = cachedResinApi.get
-				resource: 'application'
-				options:
-					select: [
-						'id'
-						'git_repository'
-						'commit'
-					]
-					filter:
-						commit: $ne: null
-						device:
-							uuid: uuid
-				customOptions:
-					apikey: apiKey
-
-			remoteAppEnvs = {}
-			Promise.join deviceId, remoteApps, (deviceId, remoteApps) ->
-				return Promise.map remoteApps, (app) ->
-					getEnvironment(app.id, deviceId, apiKey)
-					.then (environment) ->
-						app.environment_variable = environment
-						utils.extendEnvVars(app.environment_variable, uuid)
-					.then (env) ->
-						remoteAppEnvs[app.id] = env
-						env = _.omit(env, _.keys(specialActionEnvVars))
-						return {
-							appId: '' + app.id
-							commit: app.commit
-							imageId: "#{config.registryEndpoint}/#{path.basename(app.git_repository, '.git')}/#{app.commit}"
-							env: JSON.stringify(env) # The env has to be stored as a JSON string for knex
-						}
-			.then (remoteApps) ->
-				remoteApps = _.indexBy(remoteApps, 'appId')
-				remoteAppIds = _.keys(remoteApps)
-
-				apps = _.indexBy(apps, 'appId')
-				localAppEnvs = {}
-				localApps = _.mapValues apps, (app) ->
-					localAppEnvs[app.appId] = JSON.parse(app.env)
-					app.env = JSON.stringify(_.omit(localAppEnvs[app.appId], _.keys(specialActionEnvVars)))
-					app = _.pick(app, [ 'appId', 'commit', 'imageId', 'env' ])
-				localAppIds = _.keys(localApps)
-				appsWithChangedEnvs = _.filter remoteAppIds, (appId) ->
-					return !localAppEnvs[appId]? or !_.isEqual(remoteAppEnvs[appId], localAppEnvs[appId])
-
-				toBeRemoved = _.difference(localAppIds, remoteAppIds)
-				toBeInstalled = _.difference(remoteAppIds, localAppIds)
-
-				toBeUpdated = _.intersection(remoteAppIds, localAppIds)
-				toBeUpdated = _.filter toBeUpdated, (appId) ->
-					return !_.isEqual(remoteApps[appId], localApps[appId])
-
-				toBeDownloaded = _.filter toBeUpdated, (appId) ->
-					return !_.isEqual(remoteApps[appId].imageId, localApps[appId].imageId)
-				toBeDownloaded = _.union(toBeDownloaded, toBeInstalled)
-
-				allAppIds = _.union(localAppIds, remoteAppIds)
+			remoteApps = getRemoteApps(uuid, apiKey)
+
+			Promise.join deviceId, remoteApps, uuid, apiKey, getEnvAndFormatRemoteApps
+			.then ([ remoteAppEnvs, remoteApps ]) ->
+				{ localApps, localAppEnvs } = formatLocalApps(apps)
+				resourcesForUpdate = compareForUpdate(localApps, remoteApps, localAppEnvs, remoteAppEnvs)
+				{ toBeRemoved, toBeDownloaded, toBeInstalled, toBeUpdated, appsWithChangedEnvs, allAppIds } = resourcesForUpdate
 
 				# Run special functions against variables if remoteAppEnvs has the corresponding variable function mapping.
 				Promise.map appsWithChangedEnvs, (appId) ->

				.return(allAppIds)
				.map (appId) ->
					Promise.try ->
						fetch(remoteApps[appId]) if _.includes(toBeDownloaded, appId)
					.then ->
						if _.includes(toBeRemoved, appId)
							Promise.using lockUpdates(apps[appId], force), ->
								# We get the app from the DB again in case someone restarted it
								# (which would have changed its containerId)
								knex('app').select().where({ appId })
								.then ([ app ]) ->
									if !app?
										throw new Error('App not found')
									kill(app)
								.then ->
									knex('app').where('appId', appId).delete()
							.catch (err) ->

							app = remoteApps[appId]
							# Restore the complete environment so that it's persisted in the DB
							app.env = JSON.stringify(remoteAppEnvs[appId])
							Promise.try ->
								fetch(remoteApps[appId]) if needsDownload
							.then ->
								start(app)
						else if _.includes(toBeUpdated, appId)
							app = remoteApps[appId]
							# Restore the complete environment so that it's persisted in the DB
							app.env = JSON.stringify(remoteAppEnvs[appId])
							forceThisApp = remoteAppEnvs[appId]['RESIN_SUPERVISOR_OVERRIDE_LOCK'] == '1'
							strategy = remoteAppEnvs[appId]['RESIN_SUPERVISOR_UPDATE_STRATEGY']
							timeout = remoteAppEnvs[appId]['RESIN_SUPERVISOR_HANDOVER_TIMEOUT']
							updateUsingStrategy(strategy, apps[appId], app, needsDownload, force || forceThisApp, timeout)
					.catch(wrapAsError)
		.filter(_.isError)
		.then (failures) ->
