encore-architecture

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Encore application architecture

Encore 应用架构

Design the logical application before choosing directories and declarations. Apply the same architectural reasoning to Encore.ts and Encore.go; use
encore-service
or
encore-go-service
for language-specific implementation.
先设计应用的逻辑结构,再选择目录和声明方式。对 Encore.ts 和 Encore.go 采用相同的架构设计思路;使用
encore-service
或
encore-go-service
实现对应语言版本。

Read the application

了解应用

Inspect the existing code and the Encore application model when available. Identify:
  • User and system operations
  • APIs, cron jobs, and Pub/Sub handlers
  • Data models and the code that changes them
  • Infrastructure resources and the services that use them
  • Existing synchronous calls and event flows
  • Failure, scaling, deployment, and security requirements
Preserve established application concepts unless the requested change requires redefining them.
检查现有代码以及可用的 Encore 应用模型。识别:
  • 用户操作与系统操作
  • API、cron job 和 Pub/Sub handler
  • 数据模型及修改这些模型的代码
  • 基础设施资源及使用这些资源的 service
  • 现有同步调用与事件流
  • 故障、扩缩容、部署和安全要求
除非请求的变更需要重新定义,否则应保留既有的应用概念。

Separate services from processes

区分 service 与进程

Treat an Encore service as a code and API boundary, not a fixed deployment unit. The Encore platform can run all services in one process or place each service in a separate process, configured per environment without code changes.
Use service boundaries to express application responsibilities. Use process allocation to change isolation and scaling without redesigning those responsibilities.
Keep the backend in one Encore application where practical so the application model spans its services, resources, IAM, tracing, and Flow diagram.
将 Encore service 视为代码和 API 边界,而不是固定的部署单元。Encore 平台可以在一个进程中运行所有 service,也可以让每个 service 运行在独立进程中;这种方式可按环境配置,无需修改代码。
使用 service 边界表达应用职责。使用进程分配调整隔离性和扩缩容方式,无需重新设计这些职责。
在可行的情况下,将后端保留在同一个 Encore 应用中,使应用模型能够统一涵盖其中的 service、资源、IAM、tracing 和 Flow 图。

Choose service boundaries

选择 service 边界

Start a new application with one service unless a stable boundary is already known. Organize code inside it with modules, directories, or Go subpackages.
Consider a separate service for a cohesive business capability with its own operations and data. Failure isolation, independent scaling or deployment, a smaller security interface, or an existing external-system seam can strengthen the case.
Account for the cost of the split: network failure, cross-service coordination, distributed consistency, and an interface that both sides must maintain. Keep behavior together when most changes affect both sides or neither side can complete useful work independently.
Avoid services that represent technical layers such as handlers, business logic, or database access. Expose capability operations such as
ReserveInventory
, not generic access to another service's tables.
Treat repeated sequential calls across one boundary and long chains of forwarding services as evidence that the proposed services may be too narrow.
除非已经明确稳定的边界,否则新应用应从单个 service 开始。在该 service 内使用 module、目录或 Go 子包组织代码。
对于拥有自身操作和数据的内聚业务能力,可考虑使用独立 service。故障隔离、独立扩缩容或部署、更小的安全接口,或与现有外部系统衔接,都可以强化拆分理由。
同时考虑拆分带来的成本:网络故障、跨 service 协调、分布式一致性,以及双方都必须维护的接口。如果大多数变更会同时影响双方,或任何一方都无法独立完成有价值的工作,则应将相关行为保留在一起。
避免按 handler、业务逻辑或数据库访问等技术层来划分 service。应暴露
ReserveInventory
这样的能力操作,而不是对另一个 service 表格的通用访问权限。
如果同一边界上反复出现顺序调用,或形成很长的转发 service 链,这通常说明拟议的 service 划分过窄。

Assign data responsibility

分配数据职责

Assign one service responsibility for each data model, its business rules, and its schema changes. Prefer calls or events when another service needs the owning service to enforce those rules.
Encore supports shared database access through
SQLDatabase.named
in TypeScript and
sqldb.Named
in Go. Use it deliberately for reporting, incremental migrations, or cases where another service interface would add more complexity than it removes. Define migration ownership and write access before sharing a database.
Do not impose one database per service as an Encore requirement. Evaluate the coupling created by shared schema access against the coupling created by another service interface.
每个数据模型、对应业务规则及其 schema 变更,都应由一个 service 负责。当其他 service 需要由数据所属 service 执行这些规则时,优先使用调用或事件。
Encore 支持通过 TypeScript 中的
SQLDatabase.named
和 Go 中的
sqldb.Named
共享数据库访问。仅在报告、增量迁移,或相较于新增 service interface,共享访问更加简单的情况下使用这种方式。在共享数据库前,明确 migration 所有权和写访问权限。
不要将“一个 service 一个数据库”视为 Encore 的强制要求。应比较共享 schema 访问造成的耦合与新增 service interface 造成的耦合。

Choose communication

选择通信方式

Use a typed service API when the caller needs a result before continuing, the operation must report success or failure, or one service owns the requested capability.
Use Pub/Sub when the caller need not wait, several consumers react independently, or consumer retries should not repeat the originating request. Account for eventual consistency and make handlers idempotent where duplicate delivery would affect correctness.
Keep immediate request/response workflows synchronous. Keep event consumers independent rather than recreating a synchronous call chain through ordered events.
When a database change and event publication must remain consistent, design for failure between them. Encore.go provides a transactional Pub/Sub outbox; other cases require an application-specific consistency mechanism.
当调用方需要先获得结果才能继续、operation 必须报告成功或失败,或某项能力由一个 service 独占时,使用 typed service API。
当调用方无需等待、多个 consumer 需要独立响应,或 consumer 重试不应重复发起原始请求时,使用 Pub/Sub。考虑最终一致性;如果重复投递会影响正确性,应让 handler 具备幂等性。
保持即时请求/响应工作流同步。保持 event consumer 相互独立,不要通过有序事件重新创建同步调用链。
当数据库变更与事件发布必须保持一致时,应针对两者之间可能发生的失败进行设计。Encore.go 提供事务性 Pub/Sub outbox;其他情况需要使用适合具体应用的一致性机制。

Define interfaces and authorization

定义接口与授权

Classify operations as public, authenticated, or private. Keep internal capability operations private unless an external client needs them.
Place authentication and cross-origin policy at the gateway. Keep authorization decisions about a specific capability or record with the service that owns it.
将 operation 分类为 public、authenticated 或 private。除非外部 client 需要,否则应将内部能力操作保持为 private。
将 authentication 和跨源策略放在 gateway。将针对特定能力或记录的授权决策保留给拥有它的 service。

Organize and evolve

组织与演进

Encore services cannot be nested. Group large sets of related services in system directories; systems organize source code and are not Encore resources or deployment units.
When splitting a service, identify the operations and data moving together, add the new service, replace direct calls with APIs or events, and define data ownership during the transition. Inspect the resulting model in Encore Flow and test calls that now cross the service boundary.
When recommending an architecture, name the proposed services, their responsibilities, owned resources, and communication paths. Explain the concrete reason for each service split and note important consistency or failure tradeoffs. Prefer the smallest architecture that satisfies the stated requirements.
See App Structure for the full guide and language-specific examples.
Encore service 不能嵌套。将大量相关的 service 归入 system 目录;system 用于组织源代码,本身不是 Encore resource 或 deployment unit。
拆分 service 时,应识别需要一起迁移的 operation 和数据,添加新的 service,使用 API 或事件替换直接调用,并在过渡期间定义数据所有权。在 Encore Flow 中检查最终模型,并测试现在跨越 service 边界的调用。
提出架构建议时,应列明拟议的 service、其职责、拥有的 resource 和通信路径。解释拆分每个 service 的具体理由,并说明重要的数据一致性或故障权衡。优先采用满足所述需求的最小架构。
有关完整指南和语言特定示例,请参阅 App Structure。