Правильная программная архитектура является ключом к созданию проекта, который можно обслуживать. Какое собственное средство на 100% субъективно,
но в последнее время я люблю и пытаюсь следовать Чистая архитектура Роберта Мартина (он же Дядя Боб).
Хотя мне действительно нравится теория, в ней отсутствует какое-то практическое руководство по реализации общих технических проблем, с которыми могут столкнуться разработчики.
Например, одна из вещей, с которыми я боролся, - это правильная реализация уровня презентатора.
Докладчик несет ответственность за принятие «ответа» из моего варианта использования и его форматирование таким образом, чтобы
что он может быть "представлен" моему устройству вывода (независимо от того, является ли это веб-приложением или приложением CLI).
Существует несколько подходов к этой проблеме, но они обычно подпадают под одну из следующих категорий:
- Презентатор вызывается самим сценарием использования через какой-то интерфейс вывода
- Вариант использования возвращает модель ответа, а контроллер (который первоначально назывался сценарием использования) передает эту модель докладчику
Вариант 1 более или менее совпадает с тем, что говорит Чистая архитектура / Дядя Боб (в книге и в различных статьях см. Позже), Вариант 2 - это скорее альтернативный подход, который работает.
Звучит круто, но давайте посмотрим, как мы можем реализовать их в Go.
Вот моя первая версия. Для простоты наш вывод теперь идет в Интернет.
Кроме того, прошу прощения за мою краткость.
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")
}
В основном это происходит точно так же, как описано выше, и в Чистой архитектуре: есть контроллер, который вызывает вариант использования (через границу, которой здесь нет). Вариант использования что-то делает и вызывает презентатора (который не реализован, но это точно вопрос).
Нашим следующим шагом может быть реализация презентатора .... но, учитывая, как вывод работает в обработчиках HTTP HTTP, есть хорошая проблема, которую нужно решить. А именно: объем запроса.
У каждого запроса есть свой собственный обработчик ответов (передаваемый обработчику http), в который должен быть записан ответ. Презентатор не может получить доступ к глобальной области запросов, для этого нужен автор ответов. Поэтому, если я хочу следовать варианту 1 (прецедент вызывает вызывающего), я должен каким-то образом передать его докладчику, который становится областью запроса таким образом, в то время как остальная часть приложения полностью не имеет состояния и не ограничена областью запроса, они создаются один раз .
Это также означает, что я либо передаю сам автор ответов в сценарий использования и докладчику (и я бы предпочел этого не делать), либо создаю нового докладчика для каждого запроса.
Где я могу это сделать:
- В контроллере через фабрики
- В случае использования через фабрики (но опять же: в случае использования в качестве параметра должен был бы быть получатель ответа)
Это приносит еще одну проблему: если докладчик находится в области запроса, также вариант использования?
Если я хочу добавить презентатора в структуру прецедента, то да, это так, и прецедент также должен быть создан в контроллере.
В качестве альтернативы я могу сделать презентатор параметром варианта использования (никто не сказал, что зависимость должна быть введена во «время создания»). Но это все равно несколько связывает докладчика с контроллером.
Существуют и другие неотвеченные проблемы (например, куда мне отправлять HTTP-заголовки, например), но они менее специфичны для Go.
Это теоретический вопрос, так как я еще не уверен, что хочу использовать этот шаблон, но я потратил довольно много времени на обдумывание этой проблемы, пока не нашел идеальный.
На основании статей и вопросов Я читал о теме: у других тоже нет.