A great number of enterprises seek to modernize their applications for Amazon Web Services (AWS). Many find it can be challenging on which approach to embrace. Do they leverage the cloud for its capabilities or use an abstraction layer? How should product teams be organized and which practices should they adopt?
In this post, we’ll share some of the principles and practices of what we’ve seen work best sprinkled with our opinions informed by years in helping enterprises get the most from AWS.
The scope considers the time between someone having an idea for a new feature or fix until it’s deployed and running in production. In other words, the full stack.
To get things cranking, create an app modernization enablement team. This team might begin with a couple of engineer coaches who embed with teams with the idea of upskilling their capabilities to use modern practices and AWS services to enable them to accelerate the delivery of value to end users. Their mission should be to instill knowledge – through example – on modern practices for the engineers and others on these 6-8 person product teams.
These engineer/coaches are both “doers” and “advisors”. Depending on how much needs to be re/architected for the application/service, these engineer coaches might embed for 1-3 months. These engineer coaches are committing code by pairing with others on a product team, participating in daily standups, retrospectives, and are a part of the backlog. The key difference is that they’re seeking to instill their knowledge by working with others on delivering meaningful features. So, it’s neither outsourcing the work nor only advising as the latter can lead to “ivory tower” consulting.
This enablement team is usually helping product teams onboard to a software delivery platform and imbue modern practices onto the team through pairing, workshops, and other on-the-job work. The workshops help product teams grok DevOps practices and might last a full day and cover specific subjects such as deployment pipelines, security & compliance, and coding practices.
The engineer coaches help support the full lifecycle – from idea to running software in production. This implies developing user stories, building, deploying, testing, running, and supporting software systems.
These engineer coaches help enable telemetry – through dashboards and the like – so that measurement for improvement maintains focus. For example, measuring success against the 4 DevOps metrics to ensure improvement (all metrics are for production):
- Lead time for changes
- Deployment frequency
- Time to restore service
- Change failure rate
As a way to scale the knowledge from working with the individual teams, you can have one engineer from each of the first pilot teams join the enablement team to help other product teams. This is known as a cell-division model in which you scale from 1 to 2 to 4 to 8 teams and more.
There are three core compute architectures on AWS: Serverless, Containers (via ECS), and EC2. The difference lies in the abstraction and, thus, what is managed for you. The Serverless architecture is the most abstracted and with it you don’t need to specifically manage for scale, availability, or fault tolerance. Since it’s still a relatively new programming paradigm altogether, there’s a learning curve. Containers look familiar to a programming model that’s existed for decades while making it easy to create and recreate environments. With ECS, you’re still responsible for scale, high availability, or fault tolerance. However, you can integrate ECS with a service like AWS Fargate so you you don’t need to manage scale, availability, or reliability for the underlying compute clusters.
With EC2, you’re fully responsible for scale, availability, and reliability. It looks very similar to virtualization solutions such as VMWare but because you can run EC2 in an AWS ecosystem, you can leverage the numerous solutions including elastic load balancing, auto scaling, and CloudWatch – to name a few.
What we’ve seen work well is a Serverless first model in which each app/service team considers using Serverless services such as Lambda, API Gateway, and DynamoDB for their app. There are still many reasons not to use Serverless including the learning curve, architecture, and the skillset of the team so if Serverless isn’t viable, seek to use ECS with Fargate or some other abstracted variation. If ECS won’t work or – more generally – Containers won’t work, then choose an EC2-based architecture. In many enterprises today, a “Serverless first” model leads to zero applications using Serverless for the various stated reasons, but the idea is to at least consider the model and then move down the stack in terms of abstraction.
System Architectures Using Managed Services
We’ve found that teams get the most benefit from the AWS platform when they use managed AWS services. By “AWS Managed Service”, we’re referring to an abstracted service that does not require the enterprise to be responsible for the scale, availability, and reliability of the service. For example, consider using an AWS Managed Service (e.g. AWS Fargate) first unless there’s a reason why it won’t meet your needs. The reason is because it’s less hassle for everyone involved and let’s people better focus more on solving problems for their end users.
While the figure below is not meant to serve as a comprehensive list, I’m cataloging the key managed services from AWS that handle much of the scale, availability, and reliability for you. This can serve as a starting point when modernizing application/services for AWS.
- Amazon Aurora Serverless – An on-demand, auto-scaling configuration for Amazon Aurora (MySQL-compatible edition), where the database will automatically start up, shut down, and scale capacity up or down based on your application’s needs.
- Amazon DynamoDB – Fast and flexible NoSQL database service for any scale. Pay only for the throughput and storage you need.
- Amazon RDS – Managed relational database service with a choice of six popular database engines.
- Amazon ElastiCache – Managed, in-memory data store services. Choose Redis or Memcached to power real-time applications.
- Developer Tools
- AWS CodePipeline – Fully managed service that orchestrates a release workflow for continuous integration, continuous delivery, and continuous deployment.
- AWS CodeBuild – Fully managed service for building and testing code
- AWS CodeDeploy – Fully managed service for deploying software onto environments
- Management & Governance
- Security & Compliance
- Amazon GuardDuty – Intelligent threat detection and continuous monitoring to protect your AWS accounts and workloads.
- Amazon Inspector – Automated security assessment service to help improve the security and compliance of applications deployed on AWS.
- Amazon Macie – Security service that uses machine learning to automatically discover, classify, and protect sensitive data in AWS.
The overarching application architecture pattern that many teams use in modernizing existing monolith applications is the strangler pattern. This pattern advocates maintaining the monolith application while decomposing it into small, independent services (i.e. microservices) that can be deployed without relying on people from other teams or other services. Lots of teams get hung up on the best microservices patterns and while it’s fine to focus on these things, the key point to remember is that each app/service is capable of being managed and independently deployable by a small team (no more than 6-8 people).
These re/architecture efforts usually involved decomposing monolith databases in smaller databases that are available through small service teams. These databases might still be relational and move to something like RDS Aurora or to a NoSQL database system such as DynamoDB.
Key DevOps Practices
A few of the more crucial DevOps practices are listed below. If you think about DevOps in terms of how you can better accelerate feedback between end users and engineers, it helps align which practices on which you focus. These might be organization, process, culture, or tooling practices that accelerate this feedback.
- Two-pizza service teams – “you build it; you own it”. These small product teams (no more than 6-8 people) are capable of deploying their service to production. They own the whole lifecycle – build, test, deploy, run, and support.
- Secure Pipeline – take any part of the software system and figure out a way to codify it into a deployment pipeline to production . This goes for accounts, environments, security and compliance, and even the deployment pipelines themselves. Then, ensure you can secure it.
- Trunk-based development – Everyone commits all their code to master/trunk at least once a day and it’s automatically integrated with the rest of the software system.
- Stop the line – As soon as a failure is introduced as part of the deployment pipeline, it becomes a top priority to fix it in 10 minutes or less.
- Feature Toggles – Turn parts of your code on/off based on which features you want users to see without explicitly branching your entire code base. Works well with trunk-based development
- Good Software Engineering Practices Across the Full Stack – for any part of the software system (accounts, network, application, configuration, infrastructure, database, etc.), consider how to codify documentation, test-driven development, codify it, version it, make it continuous, and codify its monitoring
While teams don’t embrace all of these practices on day one, over time and with a focus on accelerating feedback, these and other practices are incorporated into their daily habits.
In this post, we described how to use enablement teams with engineer coaches who help onboard teams to a modern way of building, testing, deploying, running, and supporting full stack software systems on AWS. Then, we covered the three types of compute architectures on AWS and how a Serverless-first model can help shape the modern architecture you choose in re/architecting your application or service. You learned some of the AWS managed services to consider that are “service full” in nature and reduce the need to manage scale, availability, and reliability. You also learned what you might consider when moving existing applications to AWS using the strangler pattern. Finally, we went over some of the key DevOps practices that accelerate feedback between engineers and end users. This helps teams conduct many more experiments in order to deliver more features that their end users actually want.
Stelligent Amazon Pollycast