Header BackgroundHeader BackgroundHeader BackgroundHeader BackgroundSebastian

Clean Architecture Without Ceremony

AuthDeck is small, but it’s not trivial. It deals with multiple providers, two OAuth flows, concurrent requests, and expiring tokens. Without some structure, that turns into a tangle of HTTP handlers doing everything at once.

I reached for Clean Architecture, but pragmatically. The goal wasn’t purity—it was making the moving parts obvious. The layout ended up borrowing from a sibling project of mine, and it’s held up well.

The Layout

The split is deliberately modest:

cmd/authdeck/main.go        # composition root
internal/
  core/entities/            # Token, Provider — no dependencies
  core/usecases/            # use cases + interfaces.go (ports & DTOs)
  state/                    # in-memory read model (token cache, request queue)
  infrastructure/           # config, oauth client, browser, forwarder
  api/                      # HTTP adapter
  tui/                      # terminal UI adapter
  • entities know nothing about HTTP or YAML.
  • use cases orchestrate: TokenService resolves, refreshes, and exchanges tokens; ProviderSelector drives the TUI decision; ProxyService forwards requests.
  • ports live next to the use cases (interfaces.go): TokenClient, TokenStore, Browser, Forwarder.
  • adapters implement them, and main wires everything together.

Entities depend on nothing. Use cases depend on entities and the read model. Adapters depend inward. That’s the whole rule.

Use Cases as Collections

Not every operation deserves its own type. A use case is a struct that groups related operations—TokenService exposes Obtain, Authorize, Exchange, and AutoRefresh. One cohesive object, several methods. Splitting each into its own struct and file is ceremony, not architecture.

Staying Pragmatic

No interfaces for the sake of interfaces. No repository abstraction over a map. No dependency injection framework. The standard library does the heavy lifting—net/http, context, sync.

The one external dependency that earns its place is a YAML parser, because configuration should be readable by humans.


Clean Architecture isn’t about layers and ceremony—it’s about knowing where things belong. For a small tool, that means just enough separation to stay honest, and not a single abstraction more.

AI Insights: Just Enough Structure
Source Code: MPL-2.0 · Content: CC BY-SA 4.0 · Credits & AI Disclosure