Records the move from Scala to Go, the compiled-plugin decision, the Płytarium port as the v1 target, and the Go ecosystem research that backs the choice. No code yet.
46 lines
3.4 KiB
Markdown
46 lines
3.4 KiB
Markdown
---
|
|
title: Why Go, not Scala
|
|
date: 2026-09-16
|
|
context: Exploration session that opened the summercms.go repository. Records the language decision so it is not relitigated.
|
|
---
|
|
|
|
# Why Go, not Scala
|
|
|
|
## Background
|
|
|
|
SummerCMS started in February 2026 as a Scala 3 rewrite of WinterCMS. The stack was direct-style Scala on JDK 21 virtual threads (Tapir, Ox, Magnum, Jig). Three infrastructure modules shipped as independent sbt projects: `summer-compass` (config), `summer-phrasebook` (i18n), `summer-bonfire` (console). They live in the meta repo under `modules/`.
|
|
|
|
The effort stalled before any application ran. It was building Illuminate-shaped infrastructure bottom-up with no real app pulling requirements.
|
|
|
|
## The deciding test
|
|
|
|
We gave both ecosystems the same task: an OAuth2 server with full OIDC support.
|
|
|
|
- **PHP / WinterCMS.** The agent took `league/oauth2-server` as a model, read the existing Golem15 user plugin forks, reused the JWT primitives already in the stack, and produced a plugin. The Płytarium project today runs its own OAuth2 provider on this basis.
|
|
- **Scala.** The agent searched and found nothing reusable. It proposed a from-scratch implementation. The proposal was rejected as too large to fund.
|
|
|
|
The Scala language was never the problem. The ecosystem was. A CMS is mostly glue over solved problems, and glue needs the problems to be solved already.
|
|
|
|
## Why Go passes the same test
|
|
|
|
The Go ecosystem research (see `../research/go-ecosystem.md`) found maintained, widely used libraries for every concern in the Illuminate module map, including the one that failed in Scala: `zitadel/oidc` is an OpenID-certified provider and client library. Go is closer to PHP's situation than Scala is: many small, boring, well-tested libraries, and several Laravel-shaped frameworks and CMSes to read for patterns (Goravel, PocketBase, GoFrame).
|
|
|
|
## What Go changes
|
|
|
|
Go is statically compiled, so "drop a plugin folder and it autoloads" does not exist. The decision:
|
|
|
|
- **Primary: compiled plugins.** Caddy/xcaddy model. `plugins/` is a workspace of Go modules. A generated import list registers them. `summer make:plugin` scaffolds, `summer build` rebuilds, and a watch-rebuild loop in dev makes it feel like WinterCMS. Full type safety, plugins extend each other through ordinary Go interfaces, `go test` works.
|
|
- **Later: WASM extension API.** A narrow, sandboxed surface for untrusted third-party extensions. Only after the core plugin API is stable. See `../seeds/wasm-extension-api.md`.
|
|
- **Rejected:** stdlib `plugin` (Linux-only, toolchain lockstep, no unload), yaegi (lags Go releases, partial generics), RPC plugins (interface too wide to marshal for model extension).
|
|
|
|
## What carries over from the Scala work
|
|
|
|
- The module naming scheme in `IDEA_LIB_NAMES.md` (backpack, compass, phrasebook, bonfire, ...) can be reused as Go package names.
|
|
- The design of compass (config layering and plugin namespaces), phrasebook (CLDR plurals, namespaced keys), and bonfire (command registry, rich output) is language-neutral and worth porting.
|
|
- The open ORM question from `STACK.md` (immutable models vs Eloquent mutation) largely disappears in Go: structs are mutable, and both `ent` and `GORM` support Eloquent-like flows.
|
|
|
|
## Non-goals
|
|
|
|
- Not chasing JVM performance. Go's baseline is enough and deploys as one binary.
|
|
- Not porting Illuminate module by module. The v1 target app pulls what is needed. See `v1-target-plytarium.md`.
|