For one of my clients, I am overseeing the development of a large scale global web application. The UX is implemented in Angular and is backed by AWS serverless resources. It is a very neat architecture with a true RESTful backend and runs at an extremely low cost for the client — especially in relation to how much some other EC2 based appplications cost. One of key features of the development effort is the complete automation of Continuous Delivery. Automation is core to what we do at FastUp. This automation is 100% native to AWS — no third party products, and is declared in CloudFormation. Developers do not have any permissions in the AWS console (except for read-only permissions) and we do not have any of our usual Operations staff deploying anything anywhere.
Anyway, to focus on the topic at hand. When we started this project, other than I, no one else had the skill set or experience with anything AWS, let alone API Gateway, Lambda or DynamoDB. To get a team started on new technology was the first challenge I had to overcome. Luckily, the development team is very smart and showed keen interest. In the first few weeks, we setup our API gateway manually in the AWS console as a learning experience. Once the first draft of our API configuration was ready, we exported that as a swagger file and used that in a CloudFormation AWS::ApiGateway::RestApi resource. This was an easy way to get started. We also made another decision in the beginning that we would use stage variables to route RESTful API requests to Lambda functions. These two decisions meant one thing that, at first, looked very useful, but, later, looked like a nightmarish bottleneck. At first, we thought it would be nice to have one central location (a file) in which we could go and manage all API endpoints and also manage all routing of API requests. Indeed, if one comes from a shared services application design environment (like we all come from), this centralization of api configuration and routing really does sound good. Little did we know what a bottleneck that could be.
A centralized process does not go too well with process automation. Let me explain. In most cases, there is a division of responsibilities and concerns between system architecture and application development. Architecture defines the confines within which applications must be written. For example, if the architecture is Windows and ASP.Net, then, you probably cannot write python efficiently without changing architecture. However, when one is in the cloud, especially, serverless, there are almost no self imposed architecture confines. When it comes to an automated process, Developers write code and that code goes into the Cloud Architecture. The cloud is already architected. An in house architect cannot do much other than come in the way. When using AWS Lambda, the developer already has 5 different execution environments with low to very high CPU and RAM variations. When the automated build pipeline runs, it is best to decentralize things and not create artificial process elements. We learnt that by centralizing API gateway configuration and API Routing, we had created such an artificial bottleneck.
The fix is trivial, but, difficult to implement in a large project. The fix was to stop using the Swagger file and instead have developers create their own API endpoints. One day, we decided, we will no longer use the Swagger file and simply stopped updating the AWS::ApiGateway::RestApi resource in our cloudformation templates. Any new APIs and changes were to be declared right alongside the Lambda function declaration. This way, each developer who was closest to the code was able to configure incoming requests, which versions of functions should these be routed to.
For developers, this meant a bit more work, but, also meant a lot of new power. Where, previously, they had to wait on a central, manual step for the code to be deployed and integration tested, now, they were able to say “OK I wrote my code, deployed to DEV, tested it, and have pushed it into QA. Can you test in QA?” Boom. just like that, we gained the ability to release software into QA at will. Whenever a piece of functionality was ready, it just made it’s way to QA. Some QA testers would cringe at the thought that software can change while they test. However, that is a different battle for which there is a different fix (namely, automated regression testing in the delivery pipeline).
This transition was a big speed booster for us. We now realize the true gains of AWS cloud native architecture. The speed and economy of cloud native architecture is unbeatable. It can be realized by good decentralization and 100% automation.