Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Продумать архитектуру проекта #1

Open
stanislav-az opened this issue Sep 16, 2020 · 6 comments
Open

Продумать архитектуру проекта #1

stanislav-az opened this issue Sep 16, 2020 · 6 comments

Comments

@stanislav-az
Copy link

Сейчас не очень понятно устройство приложения, так как все модули в одной папке. Нужно выделить ядро, чтобы была ясна основная цель приложения, а также инфраструктурные слои, которые занимаются доступом к базе данных, и т.д. В целом, вертикальное и горизонтальное разделение смешано, или его нет.
Можно почитать статью по теме, если не очень понятно что требуется http://aspiringcraftsman.com/2008/01/03/art-of-separation-of-concerns/

@sirewix
Copy link
Owner

sirewix commented Sep 21, 2020

Придумывать названия очень сложно. Разделять целые модули чтобы избежать циклических зависимостей и orphaned instances, придумывая в какой модуль и в какую папку это закинуть -- тоже сложно. Совершенно не уверен в исправленной мною структуре и нейминге модулей, тем не менее выделил два основных слоя: App.Prototype, который содержит ядро (интерфейс) и App.Implementation с реализацией. Все json api методы переместил в API.*. Теперь вместо IO везде mtl-style монада (ReaderT + ExceptT)

@stanislav-az
Copy link
Author

В целом все хорошо, над названиями можно поработать, ага :)
Еще бы Entities я бы не сваливал в один модуль, плюс обычно сущности доменки это часть ядра, причем самая центральная.

@kelizarov
Copy link

Скорее надо подумать как можно разделить работу АПИ от работы с базой данных. В текущем варианте получается что эндпойнты прямо совершают действия на базами данными и тут же возвращают джейсончик ее клиенту. Проекту явно не хватает слой бизнес логики, в которой бы было описаны чистые сущности (юзеру, посты, авторы итд). Имея чистые сущности можно было написать мапперы для АПИшки и для БД представлений, таким образом код можно будет легче понять :)

@sirewix
Copy link
Owner

sirewix commented Sep 27, 2020

Еще бы Entities я бы не сваливал в один модуль, плюс обычно сущности доменки это часть ядра, причем самая центральная.

В моем случае, название модуля, вероятно, не совсем верное, потому что единственная цель содержащихся в нем типов -- парсинг query параметров. Я вижу тут два варианта:

  1. Раскидать по тематике (авторы, теги, новости, ...) в API.*, или в отдельный модуль QueryParams.* (или как то так), с зеркальной к API.* структурой. Проблема в том, что некоторые параметры используются не только в одном модуле (Page, Token), поэтому изначально и свалил все в единый модуль со всеми типами (Entities)
  2. На каждый тип по модулю в QueryParams.* (или как то так). В целом, наверно, это лучший вариант, но не уверен

Относить эти типы к ядру (по крайней мере к самой его основе) я не совсем считаю обоснованным, потому что там хранится как бы "движок програмы", а что с его помощью написано это уже другой архитектурный слой (к которому относятся типы из Entities, все эндпоинты и Entry)

Скорее надо подумать как можно разделить работу АПИ от работы с базой данных. В текущем варианте получается что эндпойнты прямо совершают действия на базами данными и тут же возвращают джейсончик ее клиенту. Проекту явно не хватает слой бизнес логики, в которой бы было описаны чистые сущности (юзеру, посты, авторы итд). Имея чистые сущности можно было написать мапперы для АПИшки и для БД представлений, таким образом код можно будет легче понять :)

Основная проблема у меня была вроде в том, что при возврате вложенной структуры придется ее "выпрямлять" (возможно я выбрал плохую либу для sql (postres-simple)), что не очень удобно, а в случае с массивом произвольной длины бывает и невозможно (например, категория в посте это массив произвольной длины (от рут категории, до текущей), при этом каждый элемент массива это пара из category id и имени, я это десериализовать удобно не смог). Поэтому я от этого отказался в пользу сериализации в json на стороне бд.

Вообще, немножко плевался с sql'я, когда писал, потому что чтобы хорошо абстрагироваться, придется уйти в кодогенерацию sql'я, что чревато нетестируемыми багами. Ну и с вложенностями очень неудобно работать

Есть конечно вариант джоинить все и уже на стороне сервера выяснять что к чему относится, в массивы собирать, но это как то не очень звучит

@kelizarov
Copy link

Советую попробовать разделить типы на слои приложения. Обычно это может выглядить так: API -> Domain -> Storage. И для каждого слоя используются свои типы для взаимодействия. Например для слоя API могут типы которые работают с квери парамертами. Storage занимался бы обычным представлением в базе данным, а Domain это уже не посредственно типы для основной логики приложения. Ну и так же между этими слоями нужно будет мапать между собой. :)

@sirewix
Copy link
Owner

sirewix commented Oct 18, 2020

Добавил Model.* параллельно API.*. Получается что API это слой API -> Domain, а Model это Domain -> Storage. Правда, в API все равно часто реюзал сущности из Model (заворачивая в newtype) просто потому что они идентичные. В целом каждая сущность имеет три три представления: Essential для создания, Partial для редактирования и Full полная структура с вложенностями. Для первых двух определяется только ToRow, для Full только FromJSON и ToJSON. Как одним sql запросом получать вложенную структуру без аггрегирования в json я так и не разобрался, поэтому оставил это как было.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants