The Architecture
Design Challenges
Designing a muti-scenario application is complex enough. Making it enterprise-grade requires us to keep additional constraints in mind when designing the architecture:
- Ownership - is everything built by one team, or many?
- Prioritization - does one scenario have a dependency on another?
- Extensibility - are scenarios likely to be extended or modified later?
- Quality - is architecture reliable, cost-effective and performant?
We use these questions to determine how we structure our project (repo), implement our scenarios (sequence), and design our architecture (choices) in the Contoso Real Estate app.
Architecture Fundamentals
A good starting point for learners is the Azure Architecture Center. It has extensive resources in design patterns and enterprise scenarios, with guidance on technology choices and workload optimization. It advocates a simple 4-step approach to developing modern apps:
- Architecture Style - identify the right architecture pattern for your scenario.
- Technology Choices - decide your core Compute, Storage & Messaging resources.
- Architecture Design - explore reference arch., design patterns & best practices.
- Assess Quality - review for 5 pillars for software quality: reliability, security, cost optimization, operational excellence and performance efficiency.
For self-guided exploration of relevant architecture concepts and design patterns, bookmark and revisit these two resources from the Architecture Center.
- Azure Architectures Browser - find real-world examples of cloud architectures with solution ideas for common workloads and insights for technology choices.
- Azure Well-Architectured Framework - find guiding tenets for assessing the quality of your workloads, and tools for reviewing and remediating identified issues.
For now, let's dive in with step 1 - identify the right architecture pattern - for the Contoso Real Estate application scenarios.
Composable Architecture
We want to build a reference architecture and implementation for a enterprise-grade application with extensible scenarios, that can be repurposed and evolved rapidly to suit changing needs. A 2020 Gartner keynote identified composable architectures as the growing trend for enterprise applications that were built for resilience and agility.
Generally speaking, composable architectures focus on design patterns and principles where more complex solutions are assembled (in build-deploy pipelines) from simpler components that can be developed by independent teams, using best-in-class tools and technologies. This addresses our design challenges in ownership, prioritization, extensibility and quality, making it a good architecture style for the Contoso Real Estate app
More concretely, we have industry initiatives like the MACH Architecture which promotes a composable architecture design based on four technology pillars:
- Microservices - where the backend is built as loosely-coupled distributed services.
- API-first - where service functionality is exposed as API (contracts) defined up front.
- Cloud-native - where apps & services are pre-designed to take advantage of cloud scale.
- Headless - where frontend choices are decoupled from backends to support flexible UI/UX.
In the rest of this section, we'll explore what these pillars mean in the context of our reference implementation. The Contoso Real Estate reference implementation is the first JavaScript on Azure sample that demonstrates a composable enterprise architecture pattern.
Cloud-native Technology
Cloud-native is one of the four technology pillars of the composable enterprise architecture. The Cloud Native Computing Foundation defines cloud-native as:
- technologies that empower organizations to build and run scalable applications in modern, dynamic environments such as public, private, and hybrid clouds. Ex: Containers, service meshes, microservices, immutable infrastructure, and declarative APIs.
- techniques that enable loosely coupled systems that are resilient, manageable, and observable. Combined with robust automation, they allow engineers to make high-impact changes frequently and predictably with minimal toil.
The simpler definition is that cloud-native enables solutions to be built in the cloud and take full advantage of the cloud computing model as visualized by five core technology pillars in Azure.
In the Develop section of this guide, we'll dive into more details on the specific cloud-native technologies and techniques used in our Contoso Real Estate App reference implementation.
Microservices
Microservices are the second pillar of the composable enterprise architecture - and a core part of cloud-native solutions on Microsoft Azure. They are defined as
the architectural process of building a distributed application from separately deployable services that perform specific business functions and communicate over web interfaces
As illustrated above, this allows us to replace tightly-coupled monolithic apps with loosely-coupled microservices, breaking up complex functionality into simpler distributed components with well-defined APIs that enable remote service invocations. With this pattern, application backends can be broken down into functionally-complete parts that are owned and evolved by different teams - while delivering a reliable and cohesive application experience to users.
Micro-frontends
Micro-frontends is a newer term that captures the natural evolution of the microservices pattern to frontend architectures. Here, a 'monolithic' frontend app is split into "micro-frontend" apps that are owned and evolved by potentially different teams. The core frontend application is then composed from the micro-frontends in production, as shown in this figure taken from this 2019 article that describes the pattern in more detail.
The key question now is: "How do we 'split' the monolithic frontend app into micro-frontends?. The figure below from microfrontends.dev illustrates the two main approaches that typically reflect team ownership of the UI/UX:
- Horizontal Split (left) assumes team ownership at the level of view components within a page of the application. For example: A "search micro-frontend" would now be a widget that could be embedded in different pages to activate search behaviors in context.
- Vertical Split (right) assumes team ownership at the level of page components within the application. For example: A "search micro-front-end" would be now be a page tied to a
/search
route, linked from other pages that pass in the query context as route params.
Both options are valid - but vertical approach is the simpler to adopt, and more extensible to new requirements (with less disruption). Micro-frontends are often motivated by organizational needs, where each micro-frontend app (feature) is owned by a distinct team that manages a related product. As a best practice for micro-frontends design, avoid horizontal teams that cut across vertical teams as illustrated below (source: martinfowler.com) - and keep it simple.
API-First Design
API-first (also called contract-first) is the third pillar of the composable enterprise architecture. In traditional "implementation-first" approaches, the API specification is derived from the component implementation. With the "API-first" approach, the contract is defined first, decoupling the implementation (microservice) and usage (service clients) pieces - allowing different teams to own and evolve them independently. This is key to headless solutions and micro-frontend apps - both of which decouple user experience from backend implementation.
The Open API initiative is an industry standard for promoting such contract-first development. It comes with opinionated guidelines on API design, and a growing set of tools and libraries (e.g., "Swagger") to streamline development and documentation of your solution API.
Check out the API link above for a peek at the Open API compliant specification (and Swagger-generated documentation) for this Contoso Real Estate reference sample.
Reference Architecture
With this, we've completed the first step of our reference architecture design process - identifying the architecture style (composable enterprise). Now it's time to make technology choices and define the architecture iteratively, from our prioritized scenarios.
Here is a sneak peek at the final reference architecture across all prioritized scenarios. In the next section (Develop), we break this down into smaller scenarios, and explore the reference architecture iteratively, composing the solution one scenario at a time.