Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement the presenter in Golang according to the Clean Architecture?

Proper software architecture is key to create a project that is maintainable. What proper means is 100% subjective, but lately I like and try to follow Clean Architecture by Robert C. Martin (aka Uncle Bob).

Although I really like the theory, it lacks some sort of practical implementation guide for common technical challenges developers may face. One of the things I've been struggling with for example is properly implementing the presenter layer.

The presenter is responsible for accepting the "response" from my use case and formatting it in a way that it can be "presented" to my output device (regardless if it is a web or a CLI application).

There are multiple approaches for this problem, but they usually fall under one of these categories:

  1. The presenter is called by the use case itself through some sort of output interface
  2. The use case returns the response model and the controller (which originally called the use case) passes this model to the presenter

Option 1 is more or less the same as what Clean Architecture/Uncle Bob says (in the book and in various posts, see later), Option 2 is rather an alternative approach which works.

Sounds cool, but let's see how we can implement them in Go.

Here is my first version. For simplicity, our output goes to the web now.

Also, please excuse my brevity.

package my_domain

import "http"

type useCase struct {
    presenter presenter
}

func (uc *useCase) doSomething(arg string) {
    uc.presenter("success")
}

type presenter interface {
    present(respone interface{})
}

type controller struct {
    useCase useCase
}

func (c *controller) Action(rw http.ResponseWriter, req *http.Request) {
    c.useCase("argument")
}

Basically it does exactly as described above and in Clean Architecture: There is a controller which calls a use case (through a boundary, which is not present here). The use case does something and calls the presenter (which is not implemented, but it's exactly the question).

Our next step could be implementing the presenter....but given how output works in Go HTTP handlers there is a nice problem to solve. Namely: request scope.

Every request has it's own response writer (passed to the http handler) where the response should be written. There is no global request scope that can be accessed by the presenter, it needs the response writer. So if I want to follow option 1 (use case calling the presenter), I have to pass it somehow to the presenter which becomes request scoped this way, while the rest of the application is completely stateless and not request scoped, they are instantiated once.

That also means that I either pass the response writer itself to the use case and the presenter (and I would rather not do that) or create a new presenter for each request.

Where can I do that:

  1. In the controller via factories
  2. In the use case via factories (but then again: the use case would have to receive the response writer as a parameter)

This bring in another problem: if the presenter is request scoped, is the use case too?

If I want to inject the presenter into the use case struct, then yes it is and the use case has to be created in the controller as well.

Alternatively I can make the presenter a parameter of the use case (noone said a dependency must be injected at "construction time"). But that would still somewhat couple the presenter to the controller.

There are other, unanswered issues (like where should I send HTTP headers for example), but those are less Go specific.

This is a theoretical question as I'm not yet sure that I want to use this pattern, but I've spent quite an amount of time thinking about this problem without finding the perfect one so far.

Based on the articles and questions I've read about the topic: others haven't either.

like image 571
mark.sagikazar Avatar asked Jul 01 '18 01:07

mark.sagikazar


People also ask

What is presenter in clean architecture?

Presenter is the mediator and directs the information to either Interactor or Router. You do not need Reactive Programming like RxSwift in Clean Architecture. Complex business logic can be added into Worker that is invoked from Interactor. Clean Architecture is an unidirectional flow of controls.

What is clean architecture in Golang?

Clean Architecture is a design pattern that uses the concept of "separation of layers," a technique used for many years by software engineers. Using abstraction will make it easier for us to do unit testing, and by applying Domain-Driven Design (DDD), one applies a domain layer that holds just the business logic.

What is clean code Architecture?

Clean architecture is a software design philosophy that separates the elements of a design into ring levels. An important goal of clean architecture is to provide developers with a way to organize code in such a way that it encapsulates the business logic but keeps it separate from the delivery mechanism.


1 Answers

I can tell you about my experience according to Clean Architecture. I spent time on that issue, reading articles and testing code. So I'd like to suggest you the following post and the source code attached, it helped me a lot:

  • Applying The Clean Architecture to Go applications

It's a really good starting point, I'm designing my software in that way developing restful web app up to the presentation to the user passing through jQuery and Bootstrap. I can claim that now my software is really diveded into indipendent layers. Also it helped me to undestand the power of te golang interfaces and finally make simple testing each part of software. Hope this help you too.

like image 175
Danilo Avatar answered Oct 07 '22 10:10

Danilo