Notes

Complete index of all notes and documentation

All Notes

Below is a complete index of all available notes and documentation, organized by project. Click on any title to view its full content.

Projects

  • Dev Day — Notes from development conferences and workshops
  • Golang — Go language projects and technical documentation
  • JUG — Notes from Java User Group talks and events

Complete Index

Philosophy & Idioms

What Go optimises for

Go was designed at Google for large teams, code that lives a long time, and fast builds. Most of its decisions follow from that.

Principle In practice
Simplicity Few keywords and features. If there were two ways to do something, one was removed.
Readability first Code is read far more often than it is written. Clear beats clever; “boring” is a compliment.
Composition No class hierarchies. You combine small types and small interfaces.
Explicit over magic No annotations and no hidden control flow. Errors are ordinary return values.
Concurrency built in Goroutines and channels are part of the language, not a library.
Fast tooling Builds take seconds, the output is one static binary, and there is one official formatter.
Useful zero values nil, "", 0, false; well-designed types work without initialisation.
Batteries included A rich standard library (HTTP, JSON, crypto, testing, profiling) and small third-party libraries instead of frameworks.

Object orientation without classes

Go has types, methods and interfaces, but no classes and no inheritance. The usual concepts still have a place:

Last updated: 2026-10-04

Docs-as-Code trifft GenAI

  • Vortrag: JUG Saxony Day 2026, Radisson Blu Park Hotel & Conference Centre, Radebeul bei Dresden, 25. September 2026
  • Sprecher: Stefan Zörner (Softwarearchitekt bei embarc, Hamburg) — vorher Bayer AG, Mummert + Partner, IBM, oose
  • Schwerpunkte: methodische Softwarearchitektur (Entwurf, Bewertung, Dokumentation), Architektur-Reviews
  • Folien: https://embarc.de/download/ · Kontakt: https://linkedin.com/in/stefan-zoerner

Abstract

Bei keiner anderen Tätigkeit in der Architekturarbeit liegt es so nahe, Generative AI einzusetzen, wie beim Dokumentieren der Softwarelösung. Es ist ohnehin ein eher unbeliebtes Thema, die Arbeitsergebnisse sind oft textlastig — wie schön wäre es, wenn “die KI” dem Team dort das Leben erleichtern würde.

Last updated: 2026-09-25

Types, Interfaces & Composition

Syntax at a glance

Types come after names, there are no semicolons, and nothing has to live in a class.

package domain

// CodeAlphabet omits visually ambiguous characters (0/O, 1/I/L).
const CodeAlphabet = "ABCDEFGHJKMNPQRSTUVWXYZ23456789"
const CodeLength = 6

type RandomCodes struct{}

func (RandomCodes) Generate() string {
    b := make([]byte, CodeLength)
    rand.Read(b)
    for i := range b {
        b[i] = CodeAlphabet[int(b[i])%len(CodeAlphabet)]
    }
    return string(b)
}
  • := declares and infers the type, inside functions only.
  • var x T declares a variable holding the zero value of T. Zero values are meant to be useful: an empty bytes.Buffer or sync.Mutex works without initialisation.
  • Exported = starts with a capital letter. That’s the only visibility rule.

Structs + methods instead of classes

Data and behaviour are declared separately. Constructors are plain functions.

Last updated: 2026-10-04

Do You Really Need an SPA?

  • Vortrag: JUG Saxony Day 2026, Radebeul bei Dresden, 25. September 2026
  • Sprecher: Vasco Schwarze (Software-Entwickler bei sciota GmbH) — Master HTW Dresden, viele Jahre Web-Entwicklung, größtenteils mit React
  • Erfahrungshintergrund: Umbau der sciota-Website von WordPress auf Astro, seitdem weitere Projekte mit Astro
  • Folien & Code: https://github.com/VascoSchwarze/do-you-really-need-an-spa · Kontakt: vasco.schwarze@sciota.io · GitHub: VascoSchwarze

Abstract

Websites laden im Median über 700 KB JavaScript, im 75. Perzentil über 1,2 MB — auch dann, wenn der Inhalt zu 99 % statisch ist. Der Vortrag stellt die zentrale Frage: „Brauchen wir dafür wirklich eine SPA?" — und beantwortet sie nicht dogmatisch, sondern anhand zweier funktional identischer Rezept-Apps: einmal als klassische React-SPA, einmal mit Astro (Islands Architecture, SSG).

Last updated: 2026-09-25

Errors

Errors are values, not exceptions

Failure is part of the function signature and is handled right where it happens.

code, err := s.allocateCode(ctx)
if err != nil {
    return nil, fmt.Errorf("create session: %w", err)
}
return s.openSession(ctx, code)

error is just an interface:

type error interface {
    Error() string
}

Sentinels, wrapping, and matching

Sentinel errors are package-level values callers can compare against:

var (
    ErrNotFound      = errors.New("not found")
    ErrNicknameTaken = errors.New("nickname already taken")
)

Wrap with %w to add context while keeping the original reachable:

Last updated: 2026-10-04

AI Instead of Software Architects – Really?

  • Vortrag: JUG Saxony Day 2026, Radebeul bei Dresden, 25. September 2026
  • Sprecher: Eberhard Wolff (Head of Architecture bei SWAGLab)
  • Links: https://swaglab.rocks/ · https://ewolff.com/
  • Folien & mehr: E-Mail an jugsaxony2026@ewolff.com (automatische Antwort via Amazon Lambda; E-Mail-Adresse wird 14 Tage geloggt, falsch adressierte Mails werden manuell bearbeitet)

Abstract

Die wichtigste Fähigkeit in der IT ist Kommunikation, die größte Herausforderung in der Softwarearchitektur sind Soft Skills — wie sollen LLMs genau diese Probleme lösen? Der Vortrag geht der Frage nach, ob KI Softwarearchitekt:innen ersetzen kann. Ausgangspunkt ist ein KI-gestütztes Architektur-Review mit einem sachlich falschen Ergebnis. Daraus folgen zwei Fragen: Lassen sich Menschen zu leicht von KI überzeugen? und Können LLMs zuverlässig sein?

Last updated: 2026-09-25

Concurrency

Don’t communicate by sharing memory; share memory by communicating.

Building blocks

Tool What it is
go f() Starts a goroutine: a function running concurrently, with a few KB of stack. Thousands are cheap.
chan T Typed pipe between goroutines. Unbuffered = handoff, buffered = queue.
select Wait on several channel operations at once; default makes it non-blocking.
context.Context Carries cancellation, deadlines and request-scoped values down the call tree.
sync.Mutex / RWMutex Plain locks, for when shared state is simpler than channels.
sync.WaitGroup Wait for a group of goroutines to finish.
sync.Once / OnceValue Lazy one-time initialisation.
errgroup (golang.org/x/sync) WaitGroup + first error + cancel the rest.
ch := make(chan int)
go func() { ch <- compute(1) }()
result := <-ch

Pattern: fan-out with a slow-consumer policy

One channel per subscriber, and a non-blocking send so a slow client can never stall the publisher.

Last updated: 2026-10-04

Web Services with the Standard Library

Since Go 1.22, net/http.ServeMux handles methods and path parameters, so a typical JSON API needs no router library. Frameworks like gin or chi still work, but are no longer required.

Routing with ServeMux

mux := http.NewServeMux()

mux.HandleFunc("GET /healthz", health)
mux.HandleFunc("POST /api/join", join)
mux.HandleFunc("GET /api/quizzes/{id}", getQuiz)
mux.HandleFunc("PUT /api/quizzes/{id}", updateQuiz)
mux.HandleFunc("GET /files/{path...}", serveFile) // wildcard rest-of-path
mux.Handle("/", spaHandler)                       // catch-all

func getQuiz(w http.ResponseWriter, r *http.Request) {
    id := r.PathValue("id")
    ...
}
  • Method in the pattern: wrong method → automatic 405 with an Allow header.
  • Most specific pattern wins, regardless of registration order.
  • Ambiguous patterns panic at registration, so conflicts surface at startup, not in production:
panic: pattern "GET /" conflicts with pattern "/api/":
  GET / matches fewer methods than /api/, but has a more general path pattern

Middleware is a function

No framework concept needed: a middleware takes a handler and returns a handler.

Last updated: 2026-10-04

Toolchain: Build, Check, Ship

One binary ships with the language and covers dependency management, building, testing, formatting and static checks. ./... means “this package and everything below it”.

The go command

Task Command
Create a project go mod init example.com/app
Add a dependency go get github.com/x/y@v1.4.0
Sync deps with imports go mod tidy
Why is a dep here? go mod why -m github.com/x/y
Run without building go run ./cmd/server
Build a binary go build -o bin/app ./cmd/server
Install a CLI tool go install github.com/air-verse/air@latest
Pin a dev tool in the project go get -tool ... → go tool ...
Test go test ./...
Format gofmt -w . / go fmt ./...
Static checks go vet ./...
Docs in the terminal go doc net/http.ServeMux
Multi-module workspace go work init ./svc-a ./svc-b
Generate code go generate ./...

Modules

  • go.mod declares the module path, Go version and direct dependencies; go.sum pins checksums. Commit both.
  • The go line is the minimum language version; a toolchain line can require a newer toolchain, which is downloaded automatically.
  • Major versions ≥ 2 are part of the import path: github.com/jackc/pgx/v5.

Build

# Cross-compile: just set two env vars
GOOS=linux GOARCH=arm64 go build -o bin/app-linux-arm64 ./cmd/server

# Static, reproducible, stripped, with an injected version
CGO_ENABLED=0 go build -trimpath \
  -ldflags="-s -w -X main.version=1.4.2" -o bin/app ./cmd/server
Flag Effect
CGO_ENABLED=0 No libc dependency → fully static, runs on scratch / distroless
-trimpath Removes local file paths from the binary
-ldflags="-s -w" Strips symbol table and DWARF (smaller binary)
-X pkg.var=value Sets a string variable at link time

go version -m bin/app shows the module versions and build settings baked into any Go binary.

Last updated: 2026-10-04

Testing & Profiling

No framework required: tests are plain functions in _test.go files next to the code, run by go test.

The building blocks

Need Go
A test func TestSave(t *testing.T) in store_test.go
Assertions if got != want { t.Errorf(...) } (or testify, if you like)
Parameterized tests Table-driven test + t.Run subtests
Test doubles Hand-written fake of a small, consumer-side interface
HTTP servers/clients in tests net/http/httptest
Per-test setup / teardown Helper function + t.Cleanup
Per-package setup / teardown TestMain(m *testing.M)
Temp files, env vars t.TempDir(), t.Setenv()
Separating slow suites Build tags (//go:build integration)
Real dependencies in Docker testcontainers-go
Browser tests playwright-go
Coverage, parallelism go test -cover, t.Parallel()

Package choice: package foo tests internals; package foo_test (black-box) only sees the exported API.

Last updated: 2026-10-04

Gotchas

No overloading, no default arguments

One name, one signature. Use an options struct or functional options:

type Option func(*Server)

func WithTimeout(d time.Duration) Option { return func(s *Server) { s.timeout = d } }

func NewServer(addr string, opts ...Option) *Server {
    s := &Server{addr: addr, timeout: 30 * time.Second}
    for _, o := range opts {
        o(s)
    }
    return s
}

srv := NewServer(":8080", WithTimeout(5*time.Second))

A nil pointer in an interface is not a nil interface

func find() error {
    var e *MyError // nil
    return e       // interface holding (*MyError, nil)
}

find() == nil // false (!)

An interface is (type, value); it’s only nil when both are. Return a literal nil on success.

Last updated: 2026-10-04

OpenAPI Code Generator

Overview

Two generators run in sequence against a single OpenAPI spec:

Generator Owns Output
oapi-codegen Types, enums, nested structs, optional pointers generated/types.go
gen/main.go Per-tag interfaces, route registration, strict glue generated/interfaces.go, routes.go, routes.go, requests.go

The result is a clean boundary: generated code you never touch, and handler files you fully own.


Prerequisites

make install-tools

Installs oapi-codegen into $(go env GOPATH)/bin.


Project layout

spec/
  api.yaml              ← source of truth, edit this

cfg/
  types.yaml            ← oapi-codegen config (types only)

gen/
  main.go               ← custom splitter — generates per-tag interfaces + routes

generated/              ← never edit, safe to delete and rebuild
  types.go
  interfaces.go
  routes.go
  requests.go           ← strict mode only

server/
  middleware/           ← hand-written
  handlers/             ← hand-written, implement generated interfaces
  server.go             ← wires router + middleware + handlers

Makefile

Usage

Standard mode

Handlers receive *gin.Context directly. Full manual control.

Last updated: 2026-06-08

Architektur Dokumentation – Structured Notes

Architecture Documentation


The Core Problem

Why architecture docs fail:

Problem Why it happens
Too much too early Spec written before code — outdated by first sprint
No time during development Devs skip it under pressure, never catch up
No ownership Nobody is explicitly responsible → everyone assumes someone else does it
Unclear scope “What actually goes in there?” — no shared answer

Solution framing: Don’t ask “how do we document everything?” — ask “what and how do we document?” Less is more. Document decisions and context, not implementation details the code already tells you.

Last updated: 2026-05-05

Keynote – Structured Notes

ESDM – Event-Sourced Domain Modeling

Website: https://www.esdm.io/
Core idea: Domain-first modeling language (YAML) that captures DDD, CQRS, and Event Sourcing building blocks in a machine- and human-readable format.


The Core Message

Talk about domain first — technology is secondary.

Common mistake: teams jump to “we’ll use Kafka / PostgreSQL / microservices” before defining what the system actually does. ESDM flips this:

  1. Describe what happens in the domain (events, commands, rules)
  2. Model who triggers what and what results are needed
  3. Only then decide on tech stack

This makes conversations with domain experts productive — they don’t need to understand Kafka to participate.

Last updated: 2026-05-05

Observability: Monitoring & Logging – Structured Notes

Observability: Does My App Work?


Core Principle

Balance: Not too much, not too little. Every metric and log must answer a real operational question.


Monitoring

The Right Amount

Use Icinga (as already deployed in your infrastructure) and focus on:

  • Where can we take action if something breaks?
  • Where is the signal-to-noise ratio actually worth it?

Question every metric: If this threshold fires, can we do something about it in 30 seconds? If not, it’s noise.

Last updated: 2026-05-05

Workshop – Structured Notes

Spring, DDD & Architecture Workshop Notes


Spring Security: Upcoming Fixes (May 18)

Rollout date: 18. Mai

Spring releases a batch of security fixes discovered via the Mythos vulnerability check. All branches up to Spring 2.7 are affected.

  • Blog post with full details drops next week
  • If you run anything ≤ 2.7, plan the upgrade now
  • Full talk at DevOps Antwerpen covers this in depth

Domain-Driven Design (DDD)

Extensional vs. Intensional

Term Meaning Examples
Extensional Represents external reality — maps things from outside the domain DTOs, API models, database rows
Intensional Expresses domain concepts from within — gives things meaning Value Objects, Entities, Aggregates

The goal: code that reads like the domain language, not like database schema.

Last updated: 2026-05-05

Dev Day

Notes and learnings from development conferences and workshops

Golang

Go language concepts, idioms, tooling and testing

JUG

Notes from Java User Group talks and events