TNS
VOXPOP
Where are you using WebAssembly?
Wasm promises to let developers build once and run anywhere. Are you using it yet?
At work, for production apps
0%
At work, but not for production apps
0%
I don’t use WebAssembly but expect to when the technology matures
0%
I have no plans to use WebAssembly
0%
No plans and I get mad whenever I see the buzzword
0%
API Management / Microservices / Software Development

Dapr: Create Applications Faster with Standardized APIs

Learn how developer productivity is increased using standard building blocks to create production-ready applications.
Jul 20th, 2023 8:24am by
Featued image for: Dapr: Create Applications Faster with Standardized APIs

Building applications and getting them ready for production is a huge task. Take a look at the Twelve-Factor App that lists many essential aspects involved in creating and running SaaS products. Development teams must be able to understand and implement all of these technical factors in a timely manner. Teams are expected to deliver functionality fast, while operational costs need to be minimized.

Tools and frameworks that lower the boundary of creating and running production-ready applications are essential, since it allows developers to spend more time on implementing business features rather than yak shaving. The runtime framework Dapr is popular for building distributed applications based on microservice architectures.

This article highlights how developer productivity is increased and an agile architecture can be achieved by using Dapr, regardless of the software architecture chosen.

Increasing Developer Productivity

Dapr helps developers be efficient by providing easy-to-understand APIs, also known as building blocks, to start developing applications quickly. Many organizations use Dapr to build microservices on top of Kubernetes. But what if you don’t want or need a microservice architecture? What if you want to build monoliths, modular monoliths or N-tier architecture applications? Dapr building blocks can benefit all kinds of backend applications.

Standard Building Block APIs

Some Dapr building blocks, such as service-to-service invocation, pub/sub and distributed lock, are essential for distributed systems. The majority of building blocks, however, are relevant for any type of software architecture:

  • State management (key/value store): read/write key/value pairs to create stateful services.
  • Secrets management: securely access secrets from your application.
  • Bindings: interface with external systems.
  • Configuration: manage application configuration and have your application subscribed to changes.
  • Workflow: enables stateful and long-running business processes.
  • Actors: self-contained unit that contains state and behavior.
  • Cryptography: perform cryptographic operations without exposing keys to your application.

The diagram below illustrates how an N-tier application or a modular monolith can benefit from using Dapr building blocks in the logic tier.

The logic tier of these architectures usually contains a business logic layer and a data access layer. Building blocks such as Workflow and Actors are meant for business logic development, so they are a great fit here. The Configuration building block is useful when used as a lightweight feature flag solution. The State management, Bindings and Secrets building blocks are particularly useful in the data access layer when external resources are accessed.

All building block APIs are intentionally basic to keep the learning curve as flat as possible. For instance, if you use the state management API for key/value data, these are the methods that you would use:

Create/Insert Key/Value Pair


*<storename> refers to the component name of the state store*

Get a Value by Key

Get Multiple Values by Keys

Delete a Key/Value Pair


By offering these standard APIs that can be used via HTTP, gRPC or one of the Dapr client SDKs, developers can use their favorite language and stay in their integrated development environment (IDE) of choice.

Cross-Cutting Concerns

So besides the standard building block APIs, how exactly can Dapr help speed up development time even more? All applications need to consider cross-cutting concerns such as:

  • Observability
  • Resiliency
  • Security

If no frameworks are used to implement these concerns, these need to be implemented in each application over and over again, which would not be the best use of development time. Some teams roll their own solution to manage these concerns, with the downside of owning and maintaining a larger codebase. With Dapr, all the above cross-cutting concerns come out of the box and are managed with declarative configuration files.

Observability

Dapr has observability builtin; this includes tracing, metrics, and logging.

  • Tracing: captures the flow of a request through a system.
  • Metrics: describes a point-in-time measurement of a system property that can easily be aggregated.
  • Logging: captures discrete events in a richer format to provide context.

Dapr can connect to any observability tools that support OpenTelemetry (OTEL) and Zipkin protocols, such as DataDog, New Relic, Grafana and Jaeger. Tracing is configured as part of a configuration YAML file:


Dapr sidecars expose a Prometheus metrics endpoint that can be used to gain insights of how Dapr itself is behaving. Metric types that are collected include: control plane, application, component and resiliency policies. See the full list with all individual metrics on GitHub.

Resilience

Making applications resilient is hard work. Resiliency is usually applied by implementing well-known architectural patterns such as retry, circuit breaker and timeout.

  • The retry pattern is used when a call to a service fails, and the call is retried several times.
  • The circuit breaker pattern is used to prevent cascading failures when a call to a service fails.
  • The timeout pattern is used to wait for a response from a service that might be slow to respond.

Typically, combining these patterns is preferred to obtain a good overall system resiliency.

There are some libraries out there that can help, such as Polly (.NET) or Resilience4j (Java), but they’re typically available for only one programming language or runtime and must be built into your application. With Dapr, resiliency is configured using resiliency spec files that contain policies and targets that the policies apply to. Resiliency spec files have the following structure:


If a constant retry policy is required that will retry 10 times with an interval of 5 seconds, this can be configured as follows:


Policies are applied to targets, which can be applications, actors or components. This example configures the pubsubRetry outbound policy for a component named messageBrokerA:


See a full example of a resiliency spec in the Dapr docs. Applying Dapr resiliency is language-agnostic and not limited to Dapr applications; they can also be applied when calling external (non-Dapr) endpoints.

Security

Dapr provides end-to-end security by using mTLS encryption and security policies where access to Dapr APIs, Dapr applications and components are explicitly configured.

In this configuration example, access to the state management HTTP API is allowed:


Access to components can be scoped to specific Dapr applications. In this component file example, the statestore component can be accessed by app1 and app2:


If the solution is exposing web APIs, endpoint authorization can be implemented using Dapr OAuth middleware to use the Authorization Code Grant flow or Client Credentials Grant flow. In addition, the use of authentication tokens can be required for accessing the Dapr API via a reverse proxy.

Agile Architecture

When a new software project starts in an agile organization, usually a combination of emergent and intentional architectural design is done. This combination is known as the architectural runway. This runway is in contrast with big design up front (BDUF), which is commonly done when doing waterfall-style project management. BDUF takes a long time to complete, leaves no room for changes and is therefore often a limiting factor later in the project.

There should be just enough intentional architecture design to get the development going and deliver usable features each sprint. The rest of the architectural design emerges while the team is building and makes further decisions. It helps to postpone some decisions as long as possible to allow more time to explore options during development.

One of the intentional architecture decisions could be to use a framework such as Dapr that allows postponing other architectural decisions that will later emerge. Frequently, the development team is not in control of certain decisions.

For instance, the procurement department is still in negotiation with several cloud providers, so there’s no decision yet which one to use. The development team can still proceed with Dapr since Dapr applications can run on any cloud that offers Kubernetes or VMs.

Or the application requires state management for key/value storage, but the decision of the exact store is under review by the security team. The development team can continue with application development using the Dapr state management API since that is a standard building block, and its implementation can be switched easily between a locally hosted solution and a cloud provider, one that is under review, by selecting a different state store component.

The diagram below illustrates the flexibility in application hosting and provides an example of various components that can be used via the standard API for state management.

Flexibility with Components

Since Dapr applications use a standard API to access features such as state management, pub/sub messaging, bindings, configuration stores, secrets stores etc., these APIs and their underlying implementation are decoupled by Dapr components. Dapr has over 115 built-in components across the 11 building block APIs. Components of the same type are interchangeable without changing the application code. A component file that contains the name of the component, the type and metadata about how to connect to the underlying resource is the only required change.

This example shows a component file where Redis is used as the state store:


The only thing the application requires to use this component is the metadate.name value (<storename> in this example):


At the component level, there is flexibility when it comes to the resources used by the building block APIs, so developers are not stuck with the lowest denominator across all resources. For instance, although the state management API has no methods to configure time to live (TTL) for the key/value pairs, at the component level (declarative configuration), this can be specified for resources that support this natively:


In case the built-in components are not sufficient, Dapr allows the creation of pluggable components for state management, pub/sub messaging and bindings. This allows development teams to use the well-known building block APIs while providing maximum flexibility in the resources they require.

Closing

Many applications need some form of state management, access to configuration and secrets, and integration with external systems. Since Dapr offers building blocks for these features, development teams benefit significantly by using Dapr, even if this doesn’t involve microservices initially. The standard API for the building blocks has a modest learning curve, and combined with the implementation of cross-cutting concerns for observability, security, and resiliency, Dapr helps developers build production-ready applications faster. The decoupling of the APIs with the components allows architectural decisions to be postponed, which ensures the application architecture is flexible and portable.

Want to learn more about Dapr? Take a look at the learn-dapr repository on GitHub, and please join the Dapr Discord, with over 6,000 members, to ask for help and share your knowledge.

Group Created with Sketch.
TNS owner Insight Partners is an investor in: Pragma.
THE NEW STACK UPDATE A newsletter digest of the week’s most important stories & analyses.