Developer Self-Service Platform Architecture

Completed

A developer self-service experience relies on a combination of concepts, patterns, and tools, spanning custom-built, off-the-shelf, and open-source technologies. The goal is to empower developers with governed task execution and provisioning while maintaining centralized visibility. Primary focus should be on tasks that are either tedious or too complex for developers to handle independently.

Developer Self-Service Platform Components

A developer self-service foundation consists of several key components that work together to streamline and automate developer workflows. These components include the Developer Platform API, Developer Platform Graph, Developer Platform Orchestrator, Developer Platform Providers, and User Profile and Team Metadata.

The Developer Platform API acts as the central point of interaction, serving as a contractual interface between user experiences and other systems. A developer platform API should enable data access and drive provisioning actions through various user interfaces. It serves as the primary authentication and security layer, restricting access to underlying, raw APIs along with the corresponding data and operations. The API manages user profiles, roles within the platform, and primary identity provider identifiers to ensure proper access control.

Complementing the Developer Platform API is the Developer Platform Graph, a secure, managed data structure that facilitates the discovery and association of entities and templates within the platform. Entities aggregate data from multiple sources, while templates guide user inputs for automation.

The Developer Platform Graph allows you to associate entities and templates from multiple providers into a searchable structure. While the data for these entities doesn't need to be stored directly in a graph database, interactions with providers can be cached along with necessary metadata. This graph becomes especially valuable when working with common entities contributed by multiple providers. For example, APIs may come from Azure API Center, while deployments and environments might be pulled from continuous deployment systems. The graph powers user experiences through a common API, enabling discovery, search, and governance.

To execute template-based actions, the Developer Platform Orchestrator routes and tracks requests, coordinating with specialized Developer Platform Providers that integrate with downstream systems. The orchestrator enables developers or systems to request actions using templates, without performing the actions directly. It coordinates with a task engine, workflow engine, or another orchestrator to execute the actions. This component is essential for enabling self-service, as it allows developers to trigger actions without needing direct permissions. Unlike CI/CD, these actions aren't limited to application source code. Workflow engines like GitHub Actions or Azure Pipelines can serve as orchestrators, but abstraction can be useful to support different engines over time. This flexibility allows for engine migration, supports manual steps for processes that may later be automated, and accommodates actions targeting non-development roles (for example, accounts payable). Additionally, simpler tasks may be handled via HTTP requests, avoiding the need for complex engines.

Developer Platform Providers manage the logic for Create, Read, Update, and Delete (CRUD) operations on entities and the execution of action requests, supporting diverse workflows and services. The providers introduce functionality into the API through an extensible provider model, enabling key features like automation and data aggregation. This model promotes loose coupling, allowing for incremental integration of new functionality and improving maintainability. By fostering an inner-source mentality, platform functionality can be contributed and maintained by different teams, minimizing the maintenance burden on central teams. While it's essential to review provider code and manage access carefully, this pluggable approach helps scale the development effort across the organization.

The foundation also includes capabilities for managing User Profile and Team Metadata, which ties individual and team information to accounts hosted by an identity provider, such as Microsoft Entra ID. This metadata is used for grouping and access control within the developer platform API. While it would be possible to store this information in the Developer Platform Graph, separating it ensures clarity.

A developer self-service foundation is accessible via a centralized user interface/user experience (UI/UX). Offering a unified access point streamlines interactions for developers, facilitating the use of workflows and resources in a seamless and intuitive manner.

Diagram showing the developer self-service foundation, including providers, API, UI and UX.

A developer self-service foundation doesn't need to be fully built from the start. Instead, it serves as a conceptual guide for the capabilities to aim for over time. Initial implementations can be simplified, using existing tools, interfaces, or classes to address the most pressing priorities identified through customer feedback. By starting small and iterating, the foundation can evolve to effectively meet new demands.

Key Developer Platform Provider Concepts

In a developer platform, the effective management and orchestration of resources relies on the use of entities along with their properties and templates. These key concepts provide structure and automation, enabling seamless integration across different providers and facilitating consistent workflows and governance.

Entities

Entities are the key objects that a developer or system needs to track, update, present, or act upon within the internal developer platform. These entities can have relationships with one another, forming a graph that provides crucial information about the platform. Developer platform providers can output entities to support various core capabilities, such as discovering external resources, performing dependency analysis, or surfacing ownership and maintainer information. A well-defined provider interface simplifies integration, testing, and deployment while enabling developer teams to operate independently.

Common Properties

To effectively manage entities, it’s helpful to define a set of common properties. Some suggested properties include a unique identifier, name, originating provider, and optional associations to users, teams, or other entities. These properties are important for role-based access control (RBAC), discovery, and data aggregation. Implementing RBAC from the start is critical for security and scaling the platform over time. The user and team associations are especially valuable as they help with discovery and collaboration, enabling efficient reuse, support, and inner sourcing within the platform.

Common and Provider Specific Entities

You should also define a set of common, high-level, normalized entities that multiple providers can output. These might include environments, resources, APIs, repositories, components, and tools. These entities should be conceptual, focusing on the broad categorization (such as environments) rather than the granular technical details (for example, internal infrastructure). This high-level view facilitates discovery, enabling data aggregation over time while pointing to lower-level details outside the system. Additionally, as your platform evolves, you may need to accommodate a growing set of provider-specific entity types to meet diverse use cases.

Templates

Templates are designed to drive actions like infrastructure provisioning, repository creation, or other long-running processes. These templates are available through developer platform providers and include common properties such as entity associations and required inputs (for example, resource names). Templates can represent various formats, including Infrastructure-as-Code (IaC) templates, application templates, or parameterized scripts. They're often provider-specific, with different representations depending on the technology in use. Examples of these representations include Terraform or Bicep templates, Helm charts, parameterized GitHub Actions workflows, Azure Pipelines, simple scripts, or custom formats tailored to specific provider ecosystems.

Although templates don't need to be stored centrally, they must be accessible via a provider to ensure consistent access across the platform. They can exist in different repositories, registries, or catalogs depending on the use case. For instance, GitHub template repositories might be used for application templates, while IaC templates could reside in a restricted catalog repository that developers access indirectly through tools like Azure Deployment Environments. Other IaC templates might be stored in an Open Container Initiative (OCI) artifact registry, such as Helm charts. In some cases, a template might simply reference a parameterized HTTP endpoint.

Platform engineers or domain specialists typically author these templates and share them with development teams for reuse. Centralizing the use of templates within a system facilitates their access while enforcing organizational standards and policies. This process helps maintain control and compliance across the platform while empowering developers to work more efficiently.

GitHub Actions as Platform Providers

To illustrate how a provider works, let's consider GitHub Actions and Azure Pipelines. Either of them can serve as a developer platform provider by triggering workflows or pipeline runs through their respective APIs, such as GitHub Actions REST API or Azure DevOps Pipeline API. These workflows or pipelines aren't required to be housed in application source code repositories, allowing platform engineers to maintain them in central, private repositories. In this model, developers don't have direct access to the workflows but can use a developer platform provider to interact with them. The provider can manage necessary secrets, such as credentials or API keys, by integrating with services like Azure Key Vault. As workflows execute, the provider tracks their state, using webhooks for GitHub Actions and service hooks for Azure Pipelines to monitor progress. Once the workflow completes, any artifacts produced, such as build or deployment results, are captured and published. These artifacts, along with input parameters and references to the workflows, can be added to the developer platform graph. This approach also allows for flexibility in using arbitrary CLIs, supporting a wide range of automation tasks over time. Additionally, the use of GitHub Actions or Azure Pipelines in this context is independent of their traditional role in CI/CD, providing broader applicability for managing various processes and templates.

Diagram showing the Developer Platform API, Developer Platform Orchestrator and GitHub Actions Provider.

There are other types of developer platform providers, which can handle various tasks through templates. For source control operations, providers can help manage Git tasks like creating repositories, submitting PRs, or other Git operations without relying on general workflow engines. Infrastructure provisioning can be streamlined through dedicated providers such as Azure Deployment Environments or Terraform Cloud, focusing on Infrastructure as Code (IaC) with security and efficiency. Application scaffolding providers, like Azure Developer CLI, support creating application source trees and pushing them to source repositories, adding flexibility for different ecosystems. Manual processes, such as generating pull requests (PRs) or automating workflows for non-developers, can also be managed through template-based providers, allowing for gradual automation. These examples highlight how extensibility and adaptability in developer platform providers can enhance automation capabilities over time.