Как правильно строить архитектуру файлов для бота aiogram?
Делаю большого телеграм бота, но уткнулся в то, что код стал крайне большим.
Видел как люди отдельные части кода распределяли по разным файлам. Как это правильно организовать?
Можете дать ссылку на видео/туториал
Ответы (1 шт):
Лично я делаю условно по паттерну MVC (хотя трудно назвать такую реализацию здесь реальным паттерном, но отталкиваюсь именно от него), то есть выстраивать архитектуру на основе model:view:controller.
В app.py находятся все статические переменные, например экземпляр бота, экземпляр диспетчера, экземпляр app-объекта, если вы используете Flask/FastAPI и webhooks. Сюда в принципе можно выносить и другие статические данные.
В controller.py находится вся логика, возможно распределена по своим классам. Иногда можно создавать другие зависимые файлы - к ним нужно только подключать экземпляры с файла app.py, и все - можно строить уже логику по разным файлам, как вы задали в вопросе. Можно конечно прикрутить и наследование, но ООП для ботов - спорная тема.
ПРИМЕЧАНИЕ: чтобы не получать ошибки о частично инициализируемых объектах - нужно в каждом файле всегда первым делать импорт из файла app.py, так как некоторые декораторы ссылаются на эти объекты из этого файла (app.py), что в общем-то ломает основную логику работы.
В models.py должны быть созданы модели базы данных, если вы знакомы с ORM, в противном случае можно просто создать функцию, которая отвечает за соединение к базе данных.
В файле main.py создается точка входа. Можно также создать режим DEBUG - очень удобное применение, если часто вносятся данные в код. При этом логика работы такова: если DEBUG это TRUE, тогда запускать метод executor.start_polling(dp), в противном случае запуск веб-сервера. Я использую для своих целей uvicorn.
В файле config.py выносятся все основные конфиденциальные данные. Еще как вариант - можно их спрятать в переменных среды.
При этом, чтобы строить такую архитектуру - каждая задача должна быть распределена в свою функцию. Если отталкиваться от паттерна, это нужно для того, если в каком-то файле будет отключена функция или убран вызов какой-то функции - она не сломает всю логику бота, то есть каждый файл должен быть независимым (условно) друг от друга.