Migrating Applications to SaaS: Rethinking Your Design
In my previous blog post in this series, I outlined some strategies for migrating applications to the software as a service (SaaS) model. That first post focused on minimally invasive approaches that allowed organizations to move existing solutions to AWS without altering the fundamentals of their application’s design or architecture.
While limiting the moving parts represents an appealing migration strategy, it also limits your ability to realize the full potential of SaaS and AWS. Leaving your design and architecture largely unchanged can make it challenging to embrace the full spectrum of agility and automation that’s often associated with SaaS applications that are born in the cloud.
The goal of this blog post is to look at SaaS migration models that allow you to stop and reconsider the design and architecture of your applications. The emphasis shifts from minimizing change to putting your solution on a path where it can begin to align itself with AWS and SaaS best practices and design principles. This will also put your solution in a much better position to adopt the agility and automation values that enable your business to more rapidly respond to market and competitive pressures.
The theme of incremental migration that was advocated in the previous post carries forward into this discussion. Even as you consider making more invasive changes to your application’s design, you still need to move forward in small steps. This approach will allow you quickly assess and reshape your design based on the knowledge that is captured during the migration of your system.
The sections that follow outline some of the general considerations that accompany this migration approach, and highlight some of the key considerations that often accompany transformations of this nature.
Granularity Drives Agility
Before we dig into the specifics of any particular strategy, we have to consider the value system that will shape and guide your migration. After all, if you’re going to actually dig into your code and change it in some substantial way, you’ll want to be sure you’re aligning with design principles that will maximize your opportunity to fully realize the benefits of SaaS.
Granularity and service decomposition are often at the center of this discussion. Many of the agility goals you’ll be targeting are commonly achieved through the adoption of a microservices model where our application is decomposed into a series of small, autonomous services. These services are at the heart of enabling a broader set of options for automating deployments, increasing resiliency, optimizing performance and scale, and so on. Essentially, the movement toward a multi-tenant aware microservice model becomes a foundational concept that will likely impact how you approach migration. The boundaries of your services will now likely be influenced by their resiliency, scalability, and deployment profile. What was a logical service in your prior environment may not represent a valid service in your new model. The potential to leverage the strengths of AWS services combined with your ability to adopt more modern design principles represents an opportunity to reconsider the fundamental composition of your system and its supporting services.
The reality is, each organization is likely to have its own unique migration path. The demands of your domain, the state of your existing technology stack, and your business pressures will all have a significant effect on how your migration will unfold. The key here is to find a way to embrace these realities while still charting a course that ultimately aligns you with your broader technical, operational, and agility objectives. Striking that balance is always at the center of the tension for SaaS migration projects.
Selecting an Execution Model
Even as you consider a move to microservices, you also have to think about the infrastructure and architecture that will be used to host these microservices. AWS allows you to run your services in a variety of environments, including Amazon Elastic Compute Cloud (Amazon EC2), Amazon EC2 Container Service (Amazon ECS), and as AWS Lambda functions.
Any one of these models would represent a completely valid path for your SaaS services. The infrastructure profile and development models will vary, but the value system for each model remains largely unchanged. Your migration path should simply evaluate these options and determine how your team, your business needs, and the long-term path of your architecture align with the profiles of each service.
You might also consider a hybrid of these models for your SaaS solution. For example, some event-driven or batch workloads from your domain might map nicely to Lambda, while other bits might be a better fit for ECS.
The following section outlines a few basic themes that are often associated with migrating a SaaS system’s architecture to a new model. It’s likely that you’ll mix and match these based on the unique requirements of your own environment.
SaaS Design Migration Themes
The models for migrating your design fall into a few camps. Some approaches are driven by the need to achieve an in-place migration while others are influenced by the need to create some isolated, parallel path for migration.
For all cases, the main approach is to carve out some slice of a system or some new capability and deliver that portion of the system with new multi-tenancy, design, and architectural principles. Once the new area is carved out, we’ll look ways to cut over or merge additional components of the system with the new model. This may result in all of the system being rewritten, or it may involve strategically migrated services running in some hybrid model. It’s important to note that there is no preferred solution. The dynamics and business realities of your environment will dictate what strategy best aligns with your needs.
The sections that follow highlight three examples of design migration strategies: service-by-service migration, parallel systems migration, and new product migration.
Service-by-Service Migration Model
If our goal is to decompose our system into microservices, and these services essentially run in an autonomous model, then you should be able to leverage this autonomy to facilitate the incremental migration of your design. The idea here would be to start with some high-level notion of how you expect to decompose your system into services. With this rough model in place, you can then identify one or more services that would represent good candidates for migration.
When identifying these initial candidates, we tend to look for services or functionality that represent some non-critical capability of your system. For example, if you were migrating an e-commerce solution, you might start with a ratings engine service. This service would fit our profile nicely because its existence could be considered optional. If, for some reason, the ratings engine started to experience difficulties, the system could continue to function with this particular feature disabled (or cached by a client).
The following diagram provides a conceptual view of how we might put the service-by-service migration strategy into action.
On the left of the diagram is a single-tenant infrastructure (presumably deployed in a silo model). On the right is a destination architecture that leverages Amazon ECS to host multi-tenant aware microservices. These new services are brought to life based on the system’s target state, and should be coded and deployed in a model that embodies our preferred design and architecture.
This transition often means rethinking the fundamentals of how you are constructing the services of your system. Tackling microservice values and SaaS best practices in one move often requires examination and adoption of a broad range of new practices. This is your chance to think about the SLAs, metering, security, logging, analytics, and fault tolerance models that are realized in each of your new services. You’ll also need to think about how tenancy will be applied in these services—especially if you’re moving to a fully shared model.
Microservices may also own their own storage models. In fact, in the diagram, you’ll notice that the two microservices that are represented by the green and black circles have their own storage footprints. One service uses the Amazon Relational Database Service (Amazon RDS) and the other uses Amazon DynamoDB. You should use this migration effort to figure out which storage services best align with the demands of each service profile. What’s good for one service may not be a good fit for another.
As you can imagine, establishing the baseline environments for these initial services will represent a huge step forward in your migration. A single service running in this new model will require you to put many of the foundational elements of your service and infrastructure into motion. It will also force key elements of your build and deployment environment to the surface.
Once this foundation is in place, more services can begin to migrate at a faster pace. This is represented by the services that are shown as moving from left to right in the diagram. During this transition you would operate in a hybrid model where some aspects of the solution would be serviced by the existing model and some would be serviced by the new microservice model.
For this example, I happened to select an ECS-based target environment. However, there’s nothing about this approach that is bound to ECS. You can imagine this same scenario playing very similarly using Amazon EC2 or AWS Lambda-hosted microservices. The details would vary, but the concepts and strategy would be very much the same. The key point here is that—as part of defining these new microservices—you should also be considering which AWS compute construct best aligns with the needs of your solution. You may actually find that some services fit better with the EC2 model while others are a better fit for Lambda.
While this migration model is relatively straightforward, it doesn’t represent a magic bullet, and it comes with its own set of challenges. Still, it provides a natural bridge from the old to the new that allows you to establish your microservice footing and evolve your shared infrastructure environment on a service-by-service basis.
Parallel Systems Migration Model
Some organizations prefer to make a cleaner break from their existing systems. Supporting interoperability between the old and new environments introduces a level of complexity that might slow the transition to a new model. Also, the need to support side-by-side execution of the new and the old environments could be viewed as added overhead.
To free themselves of this side-by-side baggage, teams might consider a parallel migration model where, they essentially carve out a completely parallel development path that will be used to construct the new version of their SaaS product. With this approach, the team will incrementally bring up a new, entirely standalone product to life that adopts the new architecture, delivery, and agility goals.
At some point, when this new version’s features and functions reach an acceptable level of maturity and functionality, the SaaS organization will begin to direct some set of their tenants toward this new system. For example, tenants who meet a certain profile or new tenants could be onboarded to the new system.
There’s nothing exotic about this approach. It does create more risk because more time and energy could be required before the new system can support live tenants. Also, the lack of incremental evolution driven by user and operational feedback could make it difficult to assess your design and architecture assumptions.
The value of parallel systems migration is that it allows the team and the entire organization to explore a new SaaS foundation without concern for how these changes might impact the stability of existing products. This can bring a degree of freedom to the development and promote a more rapid adoption of some of the cultural dynamics associated with developing and delivering a SaaS application.
New Product Migration Model
In an ideal scenario, you would want to balance the merits of the two options we’ve explored. The preferred approach would be one that allowed us to realize the benefits of iterative migration without requiring any integration with our existing solution.
This path usually means starting with an entirely new product offering. So, instead of trying to find a hybrid bridge from the old to the new, you can identify a brand new product and use that product as the greenfield opportunity for your SaaS model.
This approach often represents the ideal balance. It gives you the freedom to pursue your SaaS goals and architectural vision without any constraints. It can also free you from having to match all the features offered in your existing product. More importantly, this approach allows you to solidify and evolve the fundamentals of your multi-tenant architecture and delivery model without impacting existing customers. Once the foundation is established with this new product, you’ll be in a much better position to determine how best to migrate other SaaS offerings to the new model.
There are obvious challenges associated with this approach. First, you simply may not have a clear, new product that could be carved out and offered to your customers. It also delays bringing new SaaS capabilities to your existing products and customers, which may be of more business value.
Data Migration Considerations
Migrating your application’s design to a new model will also force you to reconsider how you are storing tenant data. There are a whole host of considerations associated with partitioning tenant data on AWS. Those considerations are outside the scope of this blog post.
Regardless of how you partition your data, you must also consider how to manage the migration of this data to a potentially new representation. If you adopt a microservices model, for example, you may be moving from a single, unified representation of data to a more distributed model where services will be autonomous and own their own view of the data.
Data representation, optimization, and migration must play a key role in your overall application decomposition strategy. As you design the new services of your application, you’ll want to think about how different storage strategies and AWS storage options might influence your approach. AWS offers a wide variety of storage solutions, and each solution has strengths and features that you’ll need to align with your SaaS services.
Staying Focused on the Big Picture
As you tackle the design and architecture of your solution, it’s essential that you remain focused on your overall agility goals. In every step of your migration, you should consider how your architecture changes are going to influence the operational and agility footprint of your business. If you migrate your SaaS architecture to a more decomposed microservice model and you don’t put the pieces in place to promote continuous delivery, you will have missed the mark.
Keeping these values front and center often means picking a strategy that evolves all of the moving parts of your environment in parallel. Build and deployment automation, infrastructure automation, security, versioning, data migration, operations tooling—all of these foundational bits should be delivered in small slices along with the actual services of your application. Seeing these pieces emerge collectively will put you in much better position to bake agility into the fabric of your approach from the outset.
Maximizing your Opportunity
In many respects, SaaS applications represent an ideal candidate for AWS. The business, technical, and agility needs of SaaS are closely aligned with the tools, services, and value proposition of AWS. AWS and its ecosystem offer SaaS providers a broad landscape of options that can be applied to maximize the success of their SaaS offerings.
As you set out on this revolutionary migration path, you should step back and consider how the needs of your application and business best align with the broad menu of available options. As your application transitions to a more decomposed model, you’ll find yourself considering which combination of AWS services and configuration options best fit the needs of that service. You’re also likely to start thinking more granularly about how you want to configure the scaling and resiliency polices of these services.
Migration also gives you the chance to look at how you might use third-party tools to fill some of the common needs of your SaaS environment. AWS partners offer a number of products that help address some of the core needs of your solution (security, monitoring, metering, and so on). These offerings can bring a rich set of capabilities to your solution, freeing you up to focus more of your attention on delivering the features of your application.
Ultimately, the goal of migration shouldn’t be to get everything just right. The tools and AWS services will always be evolving and adding new capabilities that you’ll want to consider. Migration should be more about putting yourself in a position to leverage what’s currently available while building a foundation that will support the continually evolving needs of your customers.