While many of the facets of early Drupal 8 version have been optimized and chiseled out, updates remain a constant problem. I constantly read even from experienced developers, how they have conflicts and issues when trying to update the code base. Composer is a tool from outside of Drupal team's control, and having delegated management to it, Drupal has lost control over much of its update process complexity. THere has been a security release recently, that some called Drupalgeddon. Many web sites had to be updated ASAP. This is where I came up with my lessons that I want to share below.
1. Update your sites frequently.
The longer it takes between the updates, the higher the chances that dependency issues will store up in a way that Composer won't be able to resolve. If you left your site unattended between 8.3 and then decide it to update to 8.5, you will give Composer a hard task, that it does not always handle well.
$ composer update --with-dependencies
2. Update composer and clear composer cache before updating.
I had cases, when older composer version and older caches prevented a successful update. Update composer and clear cache:
$ sudo composer self-update
$ composer clear-cache
3. Prefer the lowest common PHP version.
If you are updating websites from different servers, you want to watch out for PHP versions. If you run PHP 7.1 locally and your server runs php 7.0, you can end up updating your code base to library versions incompatible with production. You should either switch between PHP CLI versions, or keep your cli to the lowest common PHP version. In my case, it's 7.0.
$ sudo update-alternatives --set php /usr/bin/php7.0
4. Check for outdated required libraries.
You are lucky if you have not had a situation when you wait for composer to compute dependencies for half an hour, and then have an output the size of War and Peace of the conflicting libraries and versions. In my case, I had some outdated doctrine packages that I had installed from the early days of the drupal-projects and that I no longer needed. I removed those libraries and it resolved everything else in seconds. Of course, this means you have to have some understanding what those libraries are to identify the outdated ones...
5. Check for hardcoded versions of libraries.
Sometimes you may discover, that some library versions have been hardcoded in such a way as to prevent update. For example, if you updated your site from 8.2 to 8.3, you may find a hardcoded "~8.2.1" version in composer.json. In such cases, it should be corrected to a notation like "~8.2" or "^8.2". Caret version is almost always better for compatibility.
6. Try to update individual conflicts.
Sometimes you will see or two dependencies preventing the update. In some cases, requiring an upper version of those dependencies can resolve the issue. You can also try to identify and temporarily remove the offenders from the requirements, and require it after the whole setup has been updated.
7. If nothing helps, hard-rebuild the requirements.
This is a last methods, since in applying it, you are destroying the previous resolved consensus. However, for smaller projects, and in some very tough cases, this can be the only way out. You delete the lock file and the vendor folder, thus brute-forcing Composer to reinstall everything from the scratch. This can break compatibility between development instances that have some sensitive peculiarities, so try to avoid this.
$ rm composer.lock
$ rm vendor
$ composer require