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 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 easing this burden.
The Existing Approaches
As a developer working on a new project, you’ll be faced with the decision of picking an application architecture and deciding on the frameworks, tooling, and services you’ll need to 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 6 month, 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.
The Power of Component Based Apps
As your applications evolve, their structure often needs to as well. Component based apps encourage the building of modular and loosely coupled parts that enables 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 SPA (single page application) hosted via a 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.
name: my-awesome-app static_sites: name: my-hugo-website - build_command: rm -r ./public; hugo --destination ./public environment_slug: hugo github: branch: master deploy_on_push: true repo: mygituser/my-hugo-website
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.
name: my-awesome-app static_sites: name: my-hugo-website - build_command: rm -r ./public; hugo --destination ./public environment_slug: hugo github: branch: master deploy_on_push: true repo: mygituser/my-hugo-website services: name: golang-api routes: - path: /api run_command: bin/golang-api - environment_slug: go git: branch: master repo_clone_url: https://github.com/mygituser/golang-api.git http_port: 8080 instance_size_slug: professional-s
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 Single Page App. This type of component is typically delivered to end users via a content delivery network (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 Single Page App running as a static site can leverage.
Services are meant to handle the task of acting as a backing API that your static single page app 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.
databases: - cluster_name: my-postgres-db db_name: my-api-database db_user: admin engine: PG Name: my-postgres-db production: true version: "12"
Now that you have a single page app 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!
workers: name: go-worker - environment_slug: go github: branch: master deploy_on_push: true repo: mygituser/go-worker instance_count: 1 instance_size_slug: professional-s run_command: bin/go-worker
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.
jobs: name: go-postdeploy-job - environment_slug: go github: branch: master deploy_on_push: true repo: mygituser/go-postdeploy-job instance_count: 1 instance_size_slug: professional-s kind: POST_DEPLOY run_command: bin/go-postdeploy-job
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.
Component Based Apps with App Platform
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.
App Platform is live now
The App Platform is now generally available and we cannot wait to see the awesome things that users create with the building blocks that we have made available. Make sure to let us know what you think!