Software development and deployment best practices continue to evolve at a rapid pace. It can be challenging to understand whether you are making the right choices to ensure that you’re going to deliver a great experience for your end users while maintaining a workflow that keeps your team unblocked and productive. Traditional Platform as a Service (PaaS) offerings make it easy and cost effective to get started, but as your application begins to grow in complexity and scale, and your needs from the offering become more diverse, it can become difficult to manage. Taking a component-based approach to your architecture can go a long way to ease this burden.
As a developer working on a new project, you’ll face the decision of picking an application architecture and deciding on the frameworks, tooling, and services you’ll utilize to be successful. It can often feel overwhelming to make sense of all of the options and decide on the right approach. Should you be building a 12 factor app? Should you be focused on building with the JAM stack? Are you backing yourself into a corner if you decide on one over the other? What if your needs change in six months, or business takes you in a new direction with a new set of requirements?
With component-based applications you can layer on the building blocks of all of these approaches in a succinct specification that is easy to understand, manage, and expand upon.
As your applications evolve, their structure often needs to as well. Component-based apps encourage the building of modular and loosely coupled parts that enable independent scaling, management, and maintenance of the various pieces of software needed to deliver your application. Modern apps are typically made up of a static single page application (SPA) hosted via a content delivery network (CDN), a backing set of dynamic APIs, and a database. Adopting a component-based design lets members of your team focus on the parts of the app that are most important at that moment, while retaining flexibility and accelerating how quickly they can iterate.
An example of a platform that enables the creation and management of component-based apps is DigitalOcean App Platform. The app specification allows for adding component building blocks as they are needed.
An example of a simple application that only contains a CDN-backed static site.
Perhaps I also want to deploy my golang based API that my static site can utilize to serve up dynamic content. If I was hosting on most platforms, I would be forced to take a look at potentially adding another hosting platform in order to run my API. In a component-based platform, I can simply expand on my app specification declaration to define my dynamic service.
Let’s take a look at some of the various components that make up a modern app and how you might leverage them as your application evolves.
As you’re just getting started building your application, it often makes sense to deploy a static website. Perhaps this is a landing page or marketing website that you are using to gauge interest in your idea before you fully commit to building it out, or maybe you’re already well underway when it comes to writing code, and you’re looking for a cost effective way to deploy your SPA. This type of component is typically delivered to end users via a CDN to ensure the fastest response time no matter where the user is located globally.
As your needs evolve and you need to move from a strictly static website to something more dynamic, you will want to deploy an API that your static site can interact with. With services, you are able to deploy long running internet facing web services. Services can be written in many different programming languages and frameworks. Once your service is built and running, resizing the service vertically to add more resources, or scaling out horizontally is a simple way to increase the amount of horsepower and capacity available to serve your end users. Services are a great way to deploy an API or any other supporting service that your SPA running as a static site can leverage.
Services are meant to handle the task of acting as a backing API that your static SPA can consume to provide dynamic functionality. In order to provide that dynamic content, services will need to be hooked up to a database where all of that data is held. There are many options available for databases, some of the most commonly used being MongoDB, PostgreSQL, and MySQL. Being able to scale out your database as your application grows is important to ensure that your services can quickly get access to the data needed to support your end users.
Just as we saw in the previous sections, If I need a database to back my API, I do not need to go hunting for a managed database provider to host it for me; I can simply update my app specification. Environment variables will be automatically injected into my other components so that I can easily access it.
Now that you have a SPA running, dynamic services powering an API, and a database backing it, it often becomes a necessity to have a type of service that is not internet accessible, but runs in the background doing processing or handling interactions with the database. This is where workers come in very handy. Workers can be scaled vertically and horizontally just like a regular service, but cannot be accessed by the public internet and run internally to your app. Workers can be used to process various records in your database, or to handle populating your database with data fetched from third party APIs or from records that have been queued for batch processing.
Workers can be added to your app specification as well quite easily!
Sometimes it is necessary to kick off a one-off task, or a scheduled task, to run a script or make a change to some part of an application. Jobs are designed for just that purpose. Jobs can typically support both pre and post-deploy hooks, which are great for making a change before or after a new deployment of your code is rolled out. For example, these types of jobs can be used to handle a database migration during your software deployment. Scheduled jobs are similar to a Linux cron job and are configured to run on a schedule you set to handle housekeeping or other common repeatable tasks.
Jobs are defined as follows in the app specification.
With these sets of components it’s possible to go from an extremely simple static site, to a highly complex and scalable environment designed to help you bring your ideas to market faster and delight your users.
App Platform was developed from the ground up to be as open as possible. That is why when we were designing the product, we made sure to leverage as many industry standard cloud-native technologies as possible. The core of App Platform is built on top of a fleet of multi-tenant DigitalOcean Kubernetes clusters with gVisor for isolation, utilizes DigitalOcean Container Registry, and layers on tools such as Kaniko for image builds, Fluent Bit for logging, Prometheus for metrics and alerting, and so much more. App Platform has been designed to be simple to start with but able to grow with you as your business scales by fully adhering to building modern component based apps.
Everything in the App Platform is built around a declarative spec that defines the applications’ desired state. This makes it simple to clone, reuse, and share apps easily, and also makes it easy to maintain parity between staging and production environments. The application spec can be either created from scratch, or can be downloaded from the Setting tab within your app. Once you have your app spec available, you have all of the features that are present in the UI available to you from the command line interface, as well as the API.
We are also running an App Platform Hackathon in partnership with DEV.to. Build an app using App Platform and get an opportunity to win some seriously sweet prizes (e.g. $2,000 USD gift card or equivalent, a Zoom meet-and-greet with our CEO, Yancey Spruill, and of course some cool swag!) The hackathon ends on Jan 10th and we hope you participate in it.
Senior Product Manager