Architecture d'application Encore
Concevez le modèle logique de l'application avant de choisir les répertoires et les déclarations. Appliquez le même raisonnement architectural à Encore.ts et Encore.go ; utilisez encore-service ou encore-go-service pour l'implémentation spécifique à une langue.
Lire l'application
Inspectez le code existant et le modèle d'application Encore quand il est disponible. Identifiez :
- Les opérations utilisateur et système
- Les APIs, les tâches cron et les handlers Pub/Sub
- Les modèles de données et le code qui les modifie
- Les ressources d'infrastructure et les services qui les utilisent
- Les appels synchrones existants et les flux d'événements
- Les exigences de défaillance, de scalabilité, de déploiement et de sécurité
Préservez les concepts d'application établis à moins que le changement demandé ne nécessite de les redéfinir.
Séparer les services des processus
Traitez un service Encore comme une limite de code et d'API, pas comme une unité de déploiement fixe. La plateforme Encore peut exécuter tous les services dans un seul processus ou placer chaque service dans un processus séparé, configuré par environnement sans modifications de code.
Utilisez les limites de service pour exprimer les responsabilités de l'application. Utilisez l'allocation de processus pour modifier l'isolation et la scalabilité sans redessiner ces responsabilités.
Gardez le backend dans une seule application Encore quand c'est pratique, de sorte que le modèle d'application englobe ses services, ressources, IAM, tracing et diagramme Flow.
Choisir les limites de service
Commencez une nouvelle application avec un seul service à moins qu'une limite stable ne soit déjà connue. Organisez le code à l'intérieur avec des modules, des répertoires ou des sous-packages Go.
Envisagez un service séparé pour une capacité métier cohésive avec ses propres opérations et données. L'isolation des défaillances, la scalabilité ou le déploiement indépendants, une surface de sécurité plus petite ou une limite de système externe existante peuvent renforcer le cas.
Tenez compte du coût du fractionnement : défaillance réseau, coordination entre services, cohérence distribuée et une interface que les deux côtés doivent maintenir. Gardez le comportement ensemble quand la plupart des changements affectent les deux côtés ou qu'aucun côté ne peut effectuer de travail utile de manière indépendante.
Évitez les services qui représentent des couches techniques telles que les handlers, la logique métier ou l'accès à la base de données. Exposez les opérations de capacité telles que ReserveInventory, pas l'accès générique aux tables d'un autre service.
Traitez les appels séquentiels répétés sur une limite et les longues chaînes de services de renvoi comme une preuve que les services proposés pourraient être trop étroits.
Assigner la responsabilité des données
Assignez à un service la responsabilité de chaque modèle de données, ses règles métier et ses changements de schéma. Préférez les appels ou événements quand un autre service a besoin que le service propriétaire applique ces règles.
Encore supporte l'accès partagé à la base de données via SQLDatabase.named en TypeScript et sqldb.Named en Go. Utilisez-le délibérément pour les rapports, les migrations progressives ou les cas où une autre interface de service ajouterait plus de complexité qu'elle n'en supprime. Définissez la propriété de la migration et l'accès en écriture avant de partager une base de données.
N'imposez pas une base de données par service comme exigence Encore. Évaluez le couplage créé par l'accès partagé au schéma par rapport au couplage créé par une autre interface de service.
Choisir la communication
Utilisez une API de service typée quand l'appelant a besoin d'un résultat avant de continuer, quand l'opération doit signaler la réussite ou l'échec, ou quand un service possède la capacité demandée.
Utilisez Pub/Sub quand l'appelant n'a pas besoin d'attendre, quand plusieurs consommateurs réagissent indépendamment, ou quand les retry des consommateurs ne doivent pas répéter la demande d'origine. Tenez compte de la cohérence éventuelle et rendez les handlers idempotents quand la livraison en double affecterait la correction.
Gardez les flux de travail immédiats en requête/réponse synchrones. Gardez les consommateurs d'événements indépendants plutôt que de recréer une chaîne d'appels synchrones à travers des événements ordonnés.
Quand un changement de base de données et une publication d'événement doivent rester cohérents, concevez pour la défaillance entre eux. Encore.go fournit un outbox Pub/Sub transactionnel ; les autres cas nécessitent un mécanisme de cohérence spécifique à l'application.
Définir les interfaces et l'autorisation
Classifiez les opérations comme publiques, authentifiées ou privées. Gardez les opérations de capacité interne privées sauf si un client externe en a besoin.
Placez l'authentification et la politique cross-origin à la passerelle. Gardez les décisions d'autorisation concernant une capacité ou un enregistrement spécifique avec le service qui les possède.
Organiser et évoluer
Les services Encore ne peuvent pas être imbriqués. Regroupez les grands ensembles de services connexes dans des répertoires système ; les systèmes organisent le code source et ne sont pas des ressources Encore ou des unités de déploiement.
Quand vous divisez un service, identifiez les opérations et les données qui se déplacent ensemble, ajoutez le nouveau service, remplacez les appels directs par des APIs ou des événements, et définissez la propriété des données pendant la transition. Inspectez le modèle résultant dans Encore Flow et testez les appels qui traversent maintenant la limite de service.
Quand vous recommandez une architecture, nommez les services proposés, leurs responsabilités, les ressources possédées et les chemins de communication. Expliquez la raison concrète de chaque fractionnement de service et notez les compromis importants en matière de cohérence ou de défaillance. Préférez la plus petite architecture qui satisfait les exigences énoncées.
Voir App Structure pour le guide complet et les exemples spécifiques à chaque langue.