Skip to content

ADR-007 - Technologies (Backend)

Statusaccepted
Date2025-04-11
Decision MakersDardan Bujupaj (AX), Marc Gähwiler (AX), Philipp Egli (Griesser)

Context

The Sunny Calculator Add-On Application requires robust a backend service that can:

  • Process calculation requests reliably and efficiently
  • Integrate with Sunny API and other third-party systems
  • Scale to handle variable load patterns
  • Be maintainable by both AX (development) and Griesser teams (primary support)

All applications and services will run in Griesser’s Azure cloud environment. Support is structured with Griesser providing primary support, while AX handles issues that need deep intervention or code changes as per ADR-005 - Support and Operations.

Our application architecture divides into frontend (Web UI) and backend components as documented in ADR-006 - Application Architecture.

Decision

Runtime

The backend will run on as a Docker container as an Azure Container App.

Main Technical Decisions

TechnologyDescription
DockerUsed to containerize the backend application, ensuring consistency between development, testing, and production.
Azure Container AppsAzure-managed service to deploy and run Docker containers, offering scalability and seamless integration with Azure.
Python 3.13Chosen for its latest features, performance improvements, and compatibility with modern libraries.
UvicornLightweight, high-performance ASGI server for running FastAPI applications.

Frameworks / Packages

Use CaseFramework / PackageDescription
Web FrameworkFastAPIUsed to build fast, robust APIs with built-in OpenAPI documentation support and asynchronous capabilities.
ValidationpydanticIntegrated with FastAPI for request/response validation and data parsing.
API Client Generationopenapi-python-clientGenerates API clients based on OpenAPI specifications and internally uses httpx.
Logginglogging or structlogLogs will be sent to Azure Blob Storage for monitoring and diagnostics. (see ADR-005 - Support and Operations: Logging)

Developer Tooling

Use CaseFramework / PackageDescription
Command RunnerJustjust is a handy way to save and run project-specific commands.
Pre-Commit Hookspre-commitA framework for managing and maintaining multi-language pre-commit hooks.
Package ManagementuvAn extremely fast Python package and project manager, written in Rust.
Linter & Code FormaterRuffAn extremely fast Python linter and code formatter, written in Rust.
Type CheckingPyrightPyright is a full-featured, standards-compliant static type checker for Python. It is designed for high performance and can be used with large Python source bases.
TestingpytestThe pytest framework makes it easy to write small, readable tests, and can scale to support complex functional testing for applications and libraries.
Test Coveragepytest-covThis plugin produces coverage reports. Compared to just using coverage run this plugin does some extras:
Network Interaction Recorderpytest-recordingA pytest plugin that allows you recording of network interactions via VCR.py.
Mockspytest-mockThin-wrapper around the mock package for easier use with pytest
AsyncIO Testspytest-asynciopytest-asyncio is a pytest plugin. It facilitates testing of code that uses the asyncio library.
Abort Hanging Testspytest-timeoutpytest plugin to abort hanging tests.
Distributed Testingpytest-xdistpytest xdist plugin for distributed testing, most importantly across multiple CPUs

Consequences

Chosen Approach

  • Adoption of Python and FastAPI:

    • By choosing Python 3.13 and FastAPI, the development team benefits from a well-documented, developer-friendly framework with built-in OpenAPI support, allowing for quick development cycles.
    • The asynchronous capabilities of FastAPI and Uvicorn ensure robust performance for handling concurrent requests, which is essential for the processing-heavy calculation tasks required by the Sunny Calculator Add-On.
  • Containerized Application Deployment:

    • Using Docker for containerization ensures consistency across development, testing, and production environments.
    • Deploying on Azure Container Apps provides managed scalability, seamless integration with Azure services, and minimizes administrative overhead for setup, maintenance, and scaling.
  • Familiarity vs. Expertise:

    • The AX team has significant experience with Python, making development, debugging, and future maintenance more efficient.
    • A possible downside is that Griesser’s team, primarily responsible for support, may face a slight learning curve due to their primary expertise in C# and .NET.

Drawbacks

  • While this approach leverages AX’s expertise, Griesser’s team might need additional training to autonomously support the application.
  • Complex business logic or critical integrations might require more collaboration between the AX and Griesser teams.

Alternatives

C#/ASP.Net

  • Griesser’s development team has strong expertise in the ASP.Net ecosystem.
  • Migrating the backend to C# with ASP.Net Core would make the application more aligned with Griesser’s existing technology stack and simplify future troubleshooting and onboarding for their support team.

Drawbacks

  • AX developers have limited experience with C#/.NET, leading to a potential learning curve.
  • With tight project deadlines, this alternative would pose a significant risk of delays and lead to increased initial development effort.
  • Missteps due to unfamiliarity with the technology could introduce defects or inefficiencies into the codebase.

Azure Functions

  • Running the backend on Azure Functions would simplify certain operational aspects, including scaling and reducing infrastructure management.
  • This approach aligns with the serverless architecture principles, reducing the burden of managing containerized systems.

Drawbacks

  • Azure Functions have inherent limitations for long-running processes or features relying on persistent open connections (e.g., streaming, WebSockets).
  • Administering distributed functions would add complexity in debugging and monitoring, as the logic might become fragmented across many small units.
  • Hosting a more complex backend on Azure Functions could lead to challenges in implementing synchronous operations or handling intricate processing pipelines.