Задать вопрос
@XaoTikS
Программист-бэкендер. Разработчик на python.

Как правильно располагать абстрактные классы, имеющие разные ответственности?

Здравствуйте! Есть вопрос насчёт расположения в проекте интерфейсов. Я думаю многим известна эта картинка:
23aaba77439f5ea9655aa63c15cae98a.png

По дефолту мы располагаем сущности и интерфейсы в ядре (по крайней мере, у меня так сделано) - слой core или domain. Но что если у меня в core.interfaces.py лежат абстрактные классы (интерфейсы):
1) класс, ответственный за репозиторий (методы загрузки и выгрузки данных из файла в память и обратно);
2) класс, ответственный за конвертацию пользовательского объекта в словарь и обратно
3) класс, ответственный за то, по какому алгоритму будет формироваться новый id для добавления записи в бд;

Пример:
0eb597da8eafd5b376c29a73e27804b0.png
1c5d5a65f10a97cbf276a7bc7056ca01.png

Реализации этих интерфейсов лежат по разным слоям/папкам, а вот сами интерфейсы в одном месте - модуле interfaces.py

С точки зрения чистой архитектуры стоило бы переложить интерфейсы туда, где лежат их реализации ( в одну директорию), но добавить в каждый слой, подслой core (т. е. ядро именно для этого слоя), куда бы мы и положили интерфейсы?
  • Вопрос задан
  • 193 просмотра
Подписаться 1 Простой Комментировать
Помогут разобраться в теме Все курсы
  • Академия Эдюсон
    Python-разработчик + ИИ
    9 месяцев
    Далее
  • Нетология
    Python-разработчик: расширенный курс + нейросети
    12 месяцев
    Далее
  • ProductStar × РБК
    Профессия: Python-разработчик + ИИ
    8 месяцев
    Далее
Пригласить эксперта
Ответы на вопрос 3
fenrir1121
@fenrir1121
Начни с документации
С точки зрения чистой архитектуры стоило бы переложить интерфейсы туда, где лежат их реализации ( в одну директорию), но добавить в каждый слой, подслой core (т. е. ядро именно для этого слоя), куда бы мы и положили интерфейсы?
Можно хоть так хоть так. Кто-то кладет все "вертикально" (все слои одного домена), кто-то "горизонтально" (по слоям). У обоих подходов есть плюсы и минусы.

2) класс, ответственный за конвертацию пользовательского объекта в словарь и обратно
3) класс, ответственный за то, по какому алгоритму будет формироваться новый id для добавления записи в бд;
Придумают же тащить джаву в питон... По пункту 2 достаточно описать Protocol и просто реализовывать методы в классе без всей этой ментальной гимнастики. По 3 пункту вообще не понимаю в чем смысл целого класса чтобы формировать id, но как будто достаточно просто создать функцию и при необходимости заменить ее реализацию.
Все интерфейсы, не имеющие двух реализаций не нужны.
Все интерфейсы обмазанные Any не нужны.
Все интерфейсы, которые приходится менять потому что надо поправить параметры реализации не нужны.
Ответ написан
Комментировать
opium
@opium
Просто люблю качественно работать
а кто вызывает create_new_id и to_dict/from_dict? если только реализация репозитория (файл, json), то это детали хранения, в core им делать нечего, клади рядом с реализацией. В core остаётся то, что зовёт сам use case: IRepository и генератор id, если id нужен до сохранения. Правило простое: интерфейс принадлежит тому, кто его вызывает, а не тому, кто реализует. Отдельный core в каждом слое не нужен, только лишние папки.
Ответ написан
@KrimsN
python dev
Соглашусь со всем написанным выше. На самом деле нет единой "правильной" раскладки, которая решала бы все вопросы, у каждого варианта есть свои плюсы и минусы.
Я бы для python сейчас рассматривал go подход, без абстрактных классов, использовать только интерфейсы (Protocol) и объявлять их рядом с пользователями, там где этот протокол нужен (или рядом).
Если нужна "базовая" реализация, использовал миксины, или просто функции хелперы, и раскладывал иерархию "плоско" на утиной типизации и реализации протоколов, без чёткой структуры наследования, которая в python не даёт ничего, кроме 2 вещей, оверинжениринга и возможности выстрелить себе в ногу позже.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы