Aller au contenu

Architecture orientée services (SOA)

Introduction

Dans une organisation, la gestion des commandes, la facturation et le suivi des livraisons peuvent appartenir à des applications distinctes. Pourtant, ces applications doivent échanger des informations et participer aux mêmes processus métier. L’architecture orientée services, ou Service-Oriented Architecture (SOA), propose de rendre leurs capacités accessibles au moyen de services définis avec des contrats explicites.

L’objectif est de faciliter l’intégration et la réutilisation de fonctionnalités métier, tout en maîtrisant les dépendances entre applications. Cette approche possède les contraintes habituelles d’un système distribué : les exécutions des services peuvent échouer et, lorsque les échanges sont asynchrones, les informations détenues par les différents services peuvent incohérentes (par exemple, on peut demande à un service de traiter une commande dont le statut est incorrect).

Présentation

L'architecture SOA organise un système autour de services qui exposent des fonctionnalités utilisables par d’autres applications. Chaque service publie un contrat définissant les opérations disponibles, les données échangées, les règles d’accès et comportement attendu. Le consommateur connaît ce contrat sans avoir besoin de connaître l’implémentation interne du service. Par exemple, un service de facturation peut proposer l’émission d’une facture et la consultation de son état. Une application de vente peut l'utiliser via une API.

Les échanges peuvent être synchrones (HTTP, parfois SOAP dans un système existant) ou asynchrones (messages et événements). L'architecture SOA n’impose ni protocole de communication unique, ni bus d’intégration central, ni découpage en microservices.

Voici un schéma qui illustre cette présentation :

Architecture Serverless - Schématisation

Les éléments qui structurent les services SOA sont les suivants :

  • Les services : fonctionnalités exposée aux autres applications.
  • Les contrats : description des opérations, des messages et des erreurs possibles.
  • Les consommateurs : applications ou services qui utilise les contrats.
  • Les infrastructures d’intégration : API gateway, broker de messages ou bus, selon les besoins de routage, sécurité et distribution.
  • La gouvernance : règles de propriété, de versionnement, de sécurité et de suivi des échanges.

Un exemple simple en C#

Prenons une entreprise dont le site e-commerce et l’application de gestion utilisent le même service de facturation. Une API ASP.NET Core peut exposer une opération de création de facture ; le site et l’application de gestion la consomment. Après émission de la facture, le service peut publier un événement InvoiceIssued pour prévenir d’autres applications, comme le suivi comptable.

public sealed record CreateInvoiceRequest(Guid OrderId, decimal Amount);
public sealed record InvoiceResponse(Guid InvoiceId, string Status);

app.MapPost("/invoices", async (
    CreateInvoiceRequest request,
    IInvoicingService invoicing,
    CancellationToken cancellationToken) =>
{
    var invoice = await invoicing.CreateAsync(request, cancellationToken);
    return Results.Created($"/invoices/{invoice.InvoiceId}", invoice);
});

Cet extrait illustre le point d’entrée du service. En production, il faut aussi définir l’authentification, la validation de la demande, les erreurs, le comportement en cas de doublon et la persistance. La publication d’un événement après l'enregistrement de la facture nécessite un mécanisme fiable, tel qu'une Outbox (ex : table dans laquelle une application enregistre les messages qu’elle doit publier).

Les avantages

Intégration de systèmes hétérogènes

Des applications développées avec des technologies différentes peuvent échanger des données ou exécuter des traitements, via des contrats communs.

Réutilisation des fonctionnalités métier

Plusieurs applications peuvent utiliser un même service de facturation ou de gestion des clients.

Impacts des évolutions davantage contrôlés

Un contrat bien conçu permet de faire évoluer l’implémentation d’un service sans modifier systématiquement les consommateurs de ce service.

Responsabilités identifiables

Chaque service possède un rôle dans une application définie, ce qui facilite les échanges entre les équipes.

Les limites

Complexité des échanges

La consommation des services via un réseau peut unduire de la latence, des erreurs et un nécessité de superviser.

Évolution des contrats

Changer un message ou une opération demande de tenir compte des applications qui n'utilisent pas la dernière version du service.

Cohérence des données

Un processus réparti entre des services ne bénéficie généralement pas d’une transaction locale unique.

Coût de gouvernance

La sécurité, la documentation, la propriété des services et leur exploitation réclament des conventions partagées.

Risque de centralisation excessive

Un service contenant trop de logique métier peut devenir difficile à faire évoluer et à maintenir.

Quand cette architecture est-elle pertinente ?

L'architecture SOA est particulièrement utile lorsque plusieurs applications doivent partager des fonctionnalités métier, notamment dans un système d’information existant où cohabitent des logiciels et technologies différents. Elle convient aussi lorsque des équipes ont besoin de contrats stables ou d’une intégration progressive, sans réécrire l’ensemble des applications dont elles ont la charge.

Si une seule équipe construit une application de taille modérée, un monolithe modulaire peut offrir un périmètre métier avec moins de coûts réseau et d’exploitation. La décision dépend donc du nombre de consommateurs, de l’existant à intégrer et des moyens disponibles pour exploiter les services.

Bonnes pratiques avec .NET

Délimiter les responsabilités métier

Définir des services et désigner un propriétaire pour chacun de leur contrat.

Concevoir des contrats explicites

Documenter les API avec OpenAPI, stabiliser les messages et prévoir le versionnage des services et de leurs contrats.

Choisir le bon mode d’échange

Utiliser les protocoles HTTP / gRPC pour une réponse immédiate et la messagerie pour les traitements différés ou l'envoi d’événements.

Prévoir les défaillances

Configurer des délais d'expiration, des annulations, en évitant les longues chaînes d’appels synchrones.

Sécuriser les accès

Authentifier les consommateur, vérifier leurs autorisations afin de sécuriser les services ainsi que l'accès / mises à jour de données sensibles.

Observer les parcours

Corréler journaux, métriques et traces afin de suivre une opération lorsqu’elle traverse plusieurs services (via un identifiant de corrélation).