Very well written post! Thank you for this. I do have a question, however. Begging your patience — I am slightly dubious of the value added by the kit. I was with you all the way through the service layer. It looks exactly like any service layer I would have implemented would look — right down the to the constructor-like function returning an interface, etc. (And I never cared that that isn’t idiomatic Go, btw. From my point of view, exported interfaces with unexported implementations and a constructor-like function that ensures the service cannot be initialized improperly is just good defensive coding.) The point about being able to decorate the service with middleware that implements the same interface is a wonderful one, but it’s not exactly a capability that is coming to us courtesy of the kit…
Moving up to the endpoint and transport layers, I’m struggling to identify the value of those being two separate layers instead of one. Whether implemented as one layer or two, you have to write code to decode requests, call your service, and encode responses. The decoding of requests and encoding of responses changes from transport to transport, so we can assume that stuff is never reusable. The reusable part then is the endpoint, right? With the call into the service basically being a one-liner, how much are these reusable endpoints really buying us?
I understand that endpoints can be decorated with middleware (just like services can be), but again… this isn’t something that couldn’t be done already. There’s a well-established pattern for decorating HTTP handlers — which are all functions with a common, well-known signature.
Maybe the real value, then, comes in cases not using HTTP for transport? I stopped to think about how I’d decorate endpoints if I were using gRPC for transport instead. In Go, gRPC services fulfill an exported interface. So that’s already a decorate-able thing, in the same way services are, however, I suppose that can’t be decorated quite as easily as an endpoint could be because you’d have to re-implement your decorator for every gRPC service — each of which will have a different interface. So maybe this is where the kit really shines? In supporting transports that don’t already have as solid a middleware story as HTTP handlers already have natively in Go?