--- layout: blog title: "Developer Experience Cleanup: One Way to Do Things" permalink: /blog/5 description: "Unified service creation, cleaner handler registration, and modular monolith support — the Go Micro DX overhaul" --- # Developer Experience Cleanup: One Way to Do Things Developer Experience Cleanup: One Way to Do Things *March 4, 2026 — By the Go Micro Team* Go Micro has always prioritized getting out of your way. But over time, the API accumulated multiple ways to do the same thing — `micro.New(name)`, `micro.NewService(micro.Name(...))`, `service.New()`, three different handler registration patterns. If you're building something for AI agents or running a modular monolith, you shouldn't have to choose between equivalent APIs. We've cleaned it up. Here's what changed and why. ## One Way to Create a Service Before, there were three ways to create a service: ```go // Old: three equivalent patterns service := micro.NewService("greeter") // name only service := micro.NewService(micro.Name("greeter")) // options only service := service.New(service.Name("greeter")) // internal package ``` Now there's one canonical pattern: ```go service := micro.NewService("greeter") service := micro.NewService("greeter", micro.Address(":8080")) ``` Name is always the first argument. Options follow. `micro.New` still works as a deprecated alias, but every example, doc, and guide now uses `micro.NewService("name")`. ## Clean Handler Registration Registering handlers used to require reaching through to the server: ```go // Old: verbose, leaks abstraction handler := service.Server().NewHandler( &TaskService{tasks: make(map[string]*Task)}, server.WithEndpointScopes("TaskService.Create", "tasks:write"), ) service.Server().Handle(handler) ``` Now `service.Handle()` accepts handler options directly: ```go // New: clean, one call service.Handle( &TaskService{tasks: make(map[string]*Task)}, server.WithEndpointScopes("TaskService.Create", "tasks:write"), ) ``` For the common case with no options, it's just: ```go service.Handle(new(Greeter)) ``` ## Modular Monoliths with Service Groups Run multiple services in a single binary. Each service gets isolated state (server, client, store, cache) while sharing infrastructure (registry, broker, transport): ```go users := micro.NewService("users", micro.Address(":9001")) orders := micro.NewService("orders", micro.Address(":9002")) users.Handle(new(Users)) orders.Handle(new(Orders)) g := micro.NewGroup(users, orders) g.Run() ``` Start as a monolith, split into separate binaries when you need independent scaling. The Group handles signals and coordinated shutdown — all services start together and stop together. ## MCP Integration in One Line Every service is automatically an MCP tool. Add a gateway alongside your service with one option: ```go service := micro.NewService("greeter", micro.Address(":9090"), mcp.WithMCP(":3000"), ) service.Handle(new(Greeter)) service.Run() ``` Your Go comments become tool descriptions. Your struct tags become parameter schemas. No glue code. ## Bug Fixes - **Stop() error handling**: Previously, `Stop()` would silently swallow errors from `BeforeStop` hooks. Now all errors are properly propagated. - **Store initialization**: Fatal-level log on store init failure changed to error-level — a store init failure shouldn't crash your service. - **Service interface**: The internal implementation is now properly unexported. Users interact through the `service.Service` interface, not a concrete type. ## What This Means for You If you're building new services, use `micro.NewService("name", opts...)` and `service.Handle()`. That's it. If you have existing code using `micro.New("name")` or `service.Server().Handle()`, it still works. For v6, update name-less `micro.NewService(opts...)` calls to `micro.NewService("name", opts...)`. The docs, examples, and guides all point to the new patterns now. The goal is simple: when someone asks "how do I create a service?", there should be exactly one answer. See the updated [Getting Started guide](https://go-micro.dev/docs/getting-started.html) and the [agent demo](https://github.com/micro/go-micro/tree/master/examples/agent-demo) for working examples.