Migrating to Microservices from a Monolithic App

When starting with a legacy, monolithic application, you must find parts that
can be carved off and moved to separate microservices. Often, a well-structured
monolithic app will have very natural divisions, and a service class will
already function as an interface to a layer of data storage and business logic.
Such classes are the ideal place to connect the client calls to the
microservice.

Separating classes in a monolithic app

Look for classes that have CRUD-style interfaces and a few other business
methods. Try first to find classes that don't have dependencies on other
classes, apart from the code necessary to communicate with external services
such as Cloud Datastore, Memcache, or Task Queue. If necessary, you can use static
code analysis tools to try to identify sections of your code that are naturally
isolated from others. However, you might first need to refactor your code to
remove unnatural dependencies. Circular dependencies are the most difficult to
address. We recommend that you perform refactoring within your legacy codebase
and deploy it to production before attempting the move to microservices.

Common areas for microservices include the following:

User or account information

Authorization and session management

Preferences or configuration settings

Notifications and communications services

Photos and media, especially metadata

Steps for Migrating an App

After a set of classes has been identified as a candidate to become a
microservice, the next steps include:

Leaving the existing code in place and operational in the legacy application to facilitate rollback

Creating a new code repository, or at least a sub-directory in your existing repository

Copying the classes into the new location

Writing a view layer that provides the HTTP API hooks and formats the response documents in the correct manner

Formulating the new code as a separate application (create an app.yaml)

Deploying your new microservice as a service or separate project

Testing the code to ensure that it is functioning correctly

Migrating the data from the legacy app to the new microservice (see below for a discussion)

Altering your existing legacy application to use the new microservices application

Deploying the altered legacy application

Verifying that everything works as expected and that you don't need to roll back to the legacy application

Removing any dead code from the legacy application

Migrating data on a live application

Data migration on a live application can be tricky and highly dependent on your
situation. Often, to facilitate roll-forward and rollback, you will need to
write code that populates both the old and new Cloud Datastore entities, possibly by
using a temporary API on the microservice, and then write code that migrates
the existing set of data, for example as a MapReduce. This process will usually
involve some amount of temporary code and redundant data. Depending on the
specifics of your situation, you may also need to execute a catch-up data
migration after you release. Be careful not to overwrite newer data with older
data.

While this seems like a lot of work, it's a common occurrence and is important
to allow for rolling forward and rolling back in the event that the cutover to
the new microservice does not succeed. You can remove your temporary code and
delete the data from the old storage location only after you have verified that
everything is migrated correctly and everything is operating as expected. Be
sure to make backups along the way.