Design Patterns Tutorial 0/70 lessons ~6 min read Lesson 31

    Structural Patterns in Microservices

    Structural Patterns in Microservices maps GoF structural patterns onto network boundaries.

    Course progress0%
    Focus
    21 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Structural Patterns in Microservices maps GoF structural patterns onto network boundaries. Anti-Corruption Layer is Adapter for upstream services. API Gateway is Facade + Proxy. Service mesh sidecar is transparent Proxy. Aggregator is Composite. Mesh filters are Decorators. Same vocabulary — new failure modes (latency, partial failure, ownership).

    The story

    An e-commerce team split a monolith into 14 services. Clients saw requests per page climb from 1 to 27. An aggregator (Composite + Facade) collapsed "view product" to one round trip; sidecar Proxies added retries and TLS uniformly.

    The business problem

    Microservice splits without structural boundaries create client and ops pain:

    • Chatty clients: 22+ calls per screen — mobile battery and latency suffer.
    • Foreign vocabulary: legacy ERP terms leak into every consumer.
    • Repeated cross-cutting: auth, rate-limit, mTLS reimplemented per service.
    • Client-specific shapes: mobile, web, partner need different aggregations.

    The problem teams faced

    Apply structural patterns at boundaries when:

    • Clients suffer N+1 round trips across services.
    • Upstream services expose domain-foreign vocabulary.
    • Operational concerns must be uniform without editing every service.
    • Different client types need different aggregated response shapes.

    Understanding the topic

    Intent: Apply Adapter, Facade, Proxy, Decorator, Composite across service boundaries.

    • API Gateway (Facade + Proxy) — single entry; routes, auth, rate-limits.
    • ACL (Adapter) — translates between bounded contexts / legacy.
    • BFF (Facade) — per-client aggregator returning shaped responses.
    • Sidecar (Proxy) — mTLS, retries, metrics transparently.
    • Aggregator (Composite) — assembles tree of service responses.

    Internal architecture

    Structural layers at service boundary:

    text
    Clients
    API Gateway (Facade + Proxy — auth, route, rate-limit)
    Mobile BFF (Facade — client-specific aggregation)
    ├── Catalog Service
    ├── Cart Service
    └── ACL → Legacy ERP (Adapter — domain ↔ vendor translation)
    [Envoy sidecar] (Proxy — mTLS, retries, metrics)

    Visual explanation

    Three diagrams map GoF patterns to microservice layers:

    GoF → microservice mapping
    Adapter
    Anti-Corruption Layer
    Facade
    Gateway · BFF
    Proxy
    Sidecar · mesh
    Composite
    Aggregator
    Same pattern vocabulary — network hop adds latency budget concern.
    Request path (mobile home screen)
    Mobile app
    1 call
    Mobile BFF
    Facade
    Fan-out
    Catalog · Cart · Recs
    Sidecar proxy
    mTLS · retry
    BFF collapses 22 calls to 1 client round trip.
    ACL placement
    Your service
    Domain language
    ACL service
    Adapter owned by you
    Legacy ERP
    Foreign vocabulary
    Never leak ERP
    Inward only
    ACL owned by calling bounded context — not scattered in every consumer.

    Informative example

    Before / after — chatty client to BFF + ACL:

    ts
    // ❌ Mobile app orchestrates 22 service calls per home screen
    const catalog = await fetch("/catalog/featured")
    const cart = await fetch("/cart/summary")
    const recs = await fetch("/recommendations/user")
    // ... 19 more — 1.9s p95
    // ✅ Mobile BFF — one call, server-side Facade + Composite
    // GET /mobile-bff/home
    class MobileHomeBff {
    async getHome(userId: string) {
    const [catalog, cart, recs] = await Promise.all([
    this.catalog.featured(),
    this.cart.summary(userId),
    this.recs.forUser(userId),
    ])
    return { catalog, cart, recs } // mobile-shaped DTO
    }
    }
    // ACL wraps legacy ERP — consumers never see ERP types
    class ErpInventoryAdapter implements InventoryPort {
    async reserve(sku: string, qty: number) {
    const erpResponse = await this.erp.POST_INVENTORY_HOLD({ SKU: sku, QTY: qty })
    return mapToDomainReservation(erpResponse) // Adapter translation
    }
    }

    Execution workflow

    1Pick structural pattern at boundary
    1 / 4

    Identify pain

    Chattiness, foreign vocabulary, repeated ops concerns.

    Trace mobile home screen request count.

    Real-world use

    Netflix Zuul/Spring Cloud Gateway, Kong, AWS API Gateway; Istio/Envoy/Linkerd sidecars; GraphQL gateways (Composite); Stripe expand parameter; Strangler-Fig migrations with ACLs.

    Production case study

    Mobile home screen BFF:

    • Scenario: Mobile app 22 calls per home screen; p95 1.9s.
    • Decision: Mobile BFF + aggregator; deprecate direct service calls.
    • Outcome: p95 460ms; one client retry policy.
    • Lesson: each layer is a hop — budget latency deliberately.

    Trade-offs

    • Pro: one place per cross-cutting concern; coherent client API.
    • Pro: internal services evolve without breaking clients.
    • Con: each layer adds hop — latency budget shrinks.
    • Con: gateways/BFFs can become new monoliths without governance.

    Decision framework

    • Use BFF when multiple clients need different response shapes.
    • Use ACL when legacy upstream vocabulary must not leak.
    • Use sidecar when ops concerns must be uniform across languages.
    • Avoid layers when single client and few services — direct calls simpler.

    Best practices

    • ACL owned by calling bounded context — one service, not scattered adapters.
    • BFF per client type (mobile, web) — not one BFF for everything.
    • Aggregator composes — if business logic appears, push down to owning service.
    • Latency budget per layer documented in ADR.

    Anti-patterns to avoid

    • God BFF with business rules for all domains.
    • ACL copy-pasted into every consumer instead of shared service.
    • Gateway that becomes transaction script for entire platform.

    Common mistakes

    • BFF fan-out to all 40 services for any request.
    • Sidecar memory/latency cost ignored in capacity planning.
    • No ownership — gateway team becomes bottleneck for all features.

    Debugging tips

    • Distributed trace across gateway → BFF → services → ACL.
    • Count fan-out per BFF endpoint — alert on growth.

    Optimization strategies

    • Parallel fan-out in BFF where dependencies independent.
    • Cache aggregated responses with short TTL for read-heavy screens.

    Common misconceptions

    • BFF ≠ API Gateway. Gateway is shared infra; BFF is client-specific Facade.
    • Sidecar is Proxy — not a second copy of business logic.
    • GraphQL gateway is Composite + Facade at field level.

    Advanced interview questions

    Interview Prep

    Practice concise answers, then expand each card for the explanation.

    4 questions
    1IntermediateQuestionBFF vs Gateway?+

    Answer

    Gateway: shared infra (auth, routing) for all clients. BFF: client-specific aggregation — different per mobile/web/partner.

    Follow-up

    One BFF per client overkill?
    2AdvancedQuestionWhere does ACL live and who owns it?+

    Answer

    Service owned by bounded context calling legacy/external. Speaks domain out, vendor in. Not inside every consumer.

    Follow-up

    ACL anti-pattern?
    3IntermediateQuestionSidecar vs in-process library?+

    Answer

    Sidecar: uniform Proxy across languages; SRE controls without app deploy. Library: lower latency but version coupling per service.

    Follow-up

    Latency/memory cost?
    4AdvancedQuestionWhen aggregator becomes problem?+

    Answer

    When it accumulates business logic, fans out to all services for every request, or grows cross-team ownership.

    Follow-up

    Governance rules?

    Summary

    You can map Adapter/Facade/Proxy/Composite to gateways, BFFs, ACLs, and sidecars — and explain trade-offs at network scale. Tell the 27-requests-per-page story — if you can do that, you own the Structural section.

    Ready to mark this lesson complete?Track your journey across the entire course.