Учу я тут себе Python, и чтобы руки размять, запилил за неделю одноклеточный сайтик (вот код). И пришла в голову мысль пояснить тут всем, почему делать сайты — это сложно, больно и весело.
Я человек гордый, поэтому клянчу один раз и больше не буду. Поставьте звездочку в репку. На рынке труда я недолго и никому не нужен, но если человек в галстуке посмотрит на мои звездочки, то у него наступит эффект ореола, задергается глаз и пойдёт пена изо рта, и он даст мне работу и денежки.
Кто поставил звезду, разрешаю подсмотреть ответ на самый главный вопрос аниме.
Кто круче: Рэй Аянами или Аска Лэнгли?
Правильный ответ:
Содержание скрыто
Показать
Кацураги Мисато. Ну если ты в норме, естественно.
Содержание скрыто
Показать
Ладно, к сайту. Короче, суть, простая: заходим на страничку, вводим адрес человека или сообщества VK, и сайт тужится, и выдает самые залайканные посты со страницы. Нормально? Нормально.
Вон для vk.com/dtf выдал, естественно, фигню: Тоби Фокс хайпанул на новом анонсе, розыгрыши всякие, тьфу.
А вот для паблика с мемасами из третьих героев выдал пару годных приколов.
Забор в пещере, хе-хе. На любителя, конечно, но я любитель.
Иногда использую эту штуку, чтобы, скажем так, доесть из паблика самое вкусное, а ленту не листать. Аналоги в интернете такие есть, но все платно, все ограниченно, мда…
Ну ладно, что сделать-то надо, чтобы вот это все работало? А дохрена чего.
Сразу скажу, что это не гайд для уже понимающих, а картина широкими мазками для ничего не знающих, чтобы просто передать масштаб событий.
О, и ещё скажу, если сейчас с DTF много кто начнет тестить сайт, я не отвечаю, что он будет работать быстро и не упадет. Работает он с расчетом на одного пользователя (меня), и я нагрузочные тесты хоть и делал, но на 20 одновременных вызовов только. Они не сломали сервак, но были очень, очень медленные…
1. Рабочая среда
Берем не Windows, а Ubuntu 22.04 — мы же разработчики, а разработчики разрабатывают в той же среде, в которой будет прод. Если разрабатывать на Windows, то в проде могут возникнуть мелкие непредвиденные проблемы.
Берем среду разработки PyCharm (естессно, Professional Edition, мы не пальцем деланые).
Берем два больших монитора, и второй разворачиваем на 90 градусов, чтобы получилось вот это:
Очень удобно. На первом мониторе пишем код и имеем много места хоть для четырех окон одновременно (хотя обычно открыты два), а на втором — сразу все нужные второстепенные штуки:
— панель сервисов (в частности для Docker, который ещё обсудим);
— панель контроля версий Git (у меня тут все просто, но в реальной работе обычно видишь сложное переплетение веток и коммитов);
— закладки и брейкпоинты, без которых в большом проекте никуда;
— панель создания коммита;
— терминал, куда надо что-то писать каждые 5 минут;
— панель запуска проекта, чтобы видеть, что там внутри происходит и какие ошибки выпадают.
Также, у нас есть ещё слева третий монитор от ноута Lenovo Legion, на котором это все летает, и который доволен, что я наконец использую его не для нагиба нубов в Elden Ring, а для достойных взрослого человека вещей (например, чтобы писать посты на DTF, ну-ну).
О, а ещё делаем виртуальное окружение. Без виртуального окружения работать зашквар. Вот видите папку «venv»? Это оно, родимое. Оно делает так, что наш проект накапливает жир и зависимости, не мешая другим проектам. Вещь в себе, так сказать.
И еще ставим себе линтер PyLint и форматтер Black: эти ребята помогут нам держать наш код чистым, свежим, безошибочным и узким: 88 знаков в ширину — это чтобы можно было сразу два окна кода смотреть на одном мониторе, так надо.
Если думаете, что 88 знаков — это узко, то прикиньте, основные стандарты Python разрешают вообще лишь 79 знаков. Но как сказал бы друид-медведь на последней презентации Baldur’s Gate 3: «друг мой, это уже слишком узко».
2. Выбираем фреймворки
Фреймворки — это, грубо говоря, программные основы, которые хорошими людьми были созданы для других хороших людей. Они решают распространенные и низкоуровневые проблемы, и мы можем на эти фреймворки натягивать свой код, решающий локальные высокоуровневые проблемы.
Фреймворка нужно два.
Фреймворк для бэкенда (где будет происходить скрытый от человека основной програмный замес) выбираем не Django, не Flask, а FastAPI. Почему? Потому что он классный и сейчас на хайпе.
Фреймворк для фронтенда (который будет показывать человеку кнопочки и картиночки) выбираем не Vue, не Angular, а React. Почему? Потому что ни одного не знаем, а React в вакансиях чаще встречается.
Начнем с бэкенда.
3. Главный файлик
Создаем папку backend\app\ и пилим main.py, ну как обычно.
Здесь у нас что происходит:
— мы просим фреймворк FastAPI запуститься;
— задаем CORS (это такая штука, которая нужна для грамотного общения между фронтендом и бэкендом, в нашем случае сделано для понтов);
— подключаем роутеры (опишу ниже. Пока только скажу, что с помощью роутеров мы даем понять FastAPI, что если кто-то сделал запрос «vktastiest.ru/posts», то ему нужно дать посты, а если «vktastiest.ru/xbox_rules», то его надо послать нахер).
4. Фигачим простой конфиг
Создаем файлик config.py:
Это файлик с общими настройками, которыми будут пользоваться другие файлики проекта. Тут есть:
— всякие захардкоженные вещи (версия API VK, которое будем долбить, название проекта и т.д.);
— настройка загрузки секретиков, которые хардкодить нельзя. Для них надо создать отдельный файл .env, никому его не показывать. Грузит настройки из файла эта строчка:
Выглядит файл .env так:
Ой, я его же вам показал, да? Какой ужас, не смотрите. Тут мой личный токен для обращения к VK API. Но на самом деле вообще пофиг, проект учебный, а токен можно получить за 50 секунд.
В реальных проектах в таких файлах висят десятки и сотни разных переменных, в которых есть пароли к базам данным, настройки уровня конкретных машин и всякое разное. Если они куда-то уйдут на сторону, это будет катастрофа;
— еще у нас тут есть настройки логгинга:
У нас в проекте будет орудовать специальный логгер-демон. Мы нажимаем кнопку «запустить и молиться, что влетит», а этот демон будет показывать нам, что происходит внутри, в формате этих вот настроек.
Закидываем файлик config.py в папку core, шоб не мешался:
5. Строим схемочки
Схемочки — это киллер-фича FastAPI. Мы пишем вот такое:
И таким образом говорим, что если мы работаем с постами, то посты должны быть только в таком формате: сам Post с шестью полями, из которых одно поле — это массив схем Video с одним полем, а другое — это массив схем Photo с одним полем.
Ну тут все просто.
Вообще, это киллер-фича не самого FastAPI, а библиотеки Pydantic, которая в него входит, но не суть.
6. Обращаемся к VK (наконец-то)
Вот сейчас будет по-настоящему весело.
Итак, что нам нужно, чтобы обратиться к VK, и попросить дать нам популярные посты? Просто написать vk.com/good_api/dtf/please_give_me_popular_posts? Хрен-то там.
Во-первых, Контакт не дает посты, отсортированные по лайкам. Это его принципиальная, видимо, позиция — чтобы все листали ленту, а не просто ели самое вкусное. Поэтому сначала нам нужно загрузить все посты со страницы, а потом только отсортировать их на своей стороне. К счастью, сортировка даже 100.000 постов происходит весьма быстро.
Во-вторых, у Контакта есть ограничение на количество запросов: его долбить можно только 3 раза в секунду. Если долбить больше, то он будет возвращать ошибку 429, которую не нужно бояться, но нужно обрабатывать.
В-третьих, нам нужно все делать это асинхронно. Асинхронное программирование — это сложнее, в теорию я углубляться не буду, но оно позволяет повысить скорость получения данных в примерно десяток раз.
Если в паблике есть 120.000 постов, а у нас один токен, то асинхронно и на стиле их можно собрать за 30 секунд, а синхронно и без стиля — придется терпеть 755 секунд, что неприемлимо.
Ну давайте работать, че.
Сначала создаем абстракцию: монстрика «PostFetcher». Он будет ответственнен за то, чтобы асинхронно забирать посты из VK. При его создании мы указываем настройки vk_domain (адрес страницы), amount_to_fetch и sort_by_likes, и одна кнопка fetch_posts, которая вернет нам все посты с паблика.
Личико у него будет такое:
Кстати, вверху мы назначили демона-логгера за ним присматривать.
Уже искушенные питоном читатели увидят несколько особенностей кода:
— используются @датаклассы. В одной умной книжке я прочитал, что если в классе нет сложных инвариантов, то можно его превратить в @датакласс. Ну так и есть, код смотрится элегантнее;
— у нас есть protected атрибуты и будут еще такие методы, все по чести;
— пишем на английском, потому что когда люди спрашивают «с какого языка начинать изучать программирование», правильный ответ — с английского.
Какой дальше у нас план? Нам нужно, чтобы наш монстрик делал следующее:
— узнавал, сколько на стене вообще постов;
— предположим, их 100.000 на одной стене. Теперь монстрик должен породить кучку асинхронных демонов, каждый из которых будет выгрызать из VK по 2000 постов. VK будет сопротивляться, и давать каждому демону постоянно ошибку 429 (слишком много запросов, онии-чан!), но мы сделаем так, что демоны будут ненасытны, и вернутся только тогда, когда каждый соберет по 2000 постов. Это займёт время;
— все результаты от демонов соберем в кучку и отсортируем.
7. Механизм обращения к API
Отвлечемся от монстрика PostFetcher. Пока в отдельном месте правила, по которым будут совершаться обращения к API. Отделим, так сказать, политики от деталей, как умные люди пишут, мы тут за принцип Dependency Inversion, ок?
(я просто накидываю умные слова, чтобы казаться понимающим, думаю это заметно)
Запилили две функции vk_synchronous_request и vk_asynchronous_request. Первая обращается к VK API синхронно (я обращаюсь и сижу жду полгода, пока запрос что-то мне вернет). Вторая делает это асинхронно (я обращаюсь и не жду полгода, а иду заниматься своими делами, потом вернусь).
И для второй функции нам нужен семафор.
Он нужен, чтобы при любом раскладе у нас не было больше сотни ожидающих демонов. Может случиться так, что слишком много демонов сломают нашу систему вообще, такое особенно часто случается на Windows. Ну сотни демонов для наших потребностей хватит.
8. Обработчик ошибок от API
Делаем, короче, отдельного монстрика VKError.
Он будет принимать в себя то, что нам выдал VK API при запросе, и если ошибка есть, и она критичная — то VKError будет останавливать процесс и выдавать наверх исключение. А если не критичная (в нашем случае это только «слишком много запросов в секунду, подождите»), просто ждет и передает работу следующему демону.
Так как обращаемся к VK мы не только синхронно, но и асинхронно, то и ошибки тоже надо обрабатывать по-разному: и асинхронно, и синхронно. Не скажу, что это прям супер-красиво, но меня уже было не остановить.
9. Пишем код на языке Контакта (что)
Да, сейчас нам нужно написать код на языке самого Дурова. Что я имею в виду.
В VK API есть приятный фокус. Мы можем один запрос сделать раз в 3 секунды, напоминаю. Но есть такая штука, как /execute. Она представляет собой один запрос к VK API, но в ней можно написать свой код на VK Script (внутренний язык VK), который позволяет делать до 25 внутренних обращений к VK API и возвращать результат.
Ну то есть мы делаем не один лоховской запрос на 1000 постов, а делаем гигачадный запрос execute, в котором происходит 25 запросов на 1000 постов.
Надо только это все написать… Ну пишем, что делать, подглядываем в документацию Контакта, не маленькие.
Этот код в цикле делает несколько запросов за постами и дает нам результат сразу для всех запросов. Код мы подставляем в свой запрос к VK, и он там творит свои дела.
То есть мы написали код, который делает запрос, и в этот запрос поместили внутрь написанный нами другой код. Нормально, да?
Правда, может он дать только 5 мегабайт за раз (иначе ошибка), поэтому делать нечего, будем просить не 25 000 постов, а хотя бы 10 000 (10 итераций). Это будет медленнее, но так мы минимизируем риск того, что этот запрос возвратит нам ошибку.
Мы для этого ниже укажем число 10 одной переменной, ничего сложного.
10. Возвращаемся к PostFetcher
Пишем нашему монстрику protected method, то есть функцию, которой он будет узнавать количество постов на стене:
Мы дергаем эту функцию, и монстрик запоминает: о, в домене «repouiii» аж 5512 поста, вау… И кладет эту информацию себе в атрибут _total_posts_in_domain.
Теперь пишем код, который будет асинхронно пожирать посты из VK:
Тут у нас вообще функция в функции. Асинхронная функция fetch_posts, понимаете, имеет в себе асинхронную функцию fetch_posts_for_offset.
Что тут происходит:
— запускается функция fetch_posts, и происходит синхронный сбор количества постов со стены;
— создаются асинхронные демоны-задания, клоны функции fetch_posts_for_offset, но для каждой разный offset: чтобы покрыть все посты, которые нужно получить. Первый демон есть посты с 1 по 1000, второй — с 1001 по 2000, и т.д.;
— собираются, скажем, 50 таких демонов, и они бросаются одним большим скопом в VK API. А мы ждем;
— когда дождались, монстрик PostFetcher запоминает эти посты в атрибут _posts и сортирует их по лайкам.
Я сначала боялся, что отсортировать сотню тысяч постов по лайкам будет долго, но по факту это оказалось самое простое и быстрое из того, что делает наш PostFetcher.
11. О, мы же еще должны результаты упаковать
Упаковать мы должны в схему.
Помните, мы схемы делали? А VK же нам посылает не наши скромные схемы на 6 полей, он шлет лютых жирдяек на десятки полей со всяким ненужным мусором: айдишники, ссылки, службные данные. Нам надо написать код, который будет приводить этих жирдяек к нашим стройным схемам, в которых есть только то, что нам нужно для отправки на фронтенд.
Ну вот, после этого наш монстрик PostFetcher знает, что там есть на стене VK на языке понятных нам схем.
Вот такая у нас получилась компания:
12. Строим роутеры
Мы пишем вот это вот:
Здесь мы делаем связку: если в запросе к нашему сервису есть префикс /posts, то перенаправляем на эндпоинты, где происходит обработка этих постов.
На роутер /utils не обращайте внимания, не помню зачем я его сделал.
13. Пишем эндпоинт
А вот и адрес нашего единственного эндпоинта.
Ля какая красота. 90% занимает документация и простейшие проверки. А по сути самое главное происходит в последних трёх строчках:
— создаем монстрика по нашим настройкам;
— просим его обратиться к VK API;
— собираем с него результат.
Это прекрасно, это абстракция, это инкапсуляция, это ООП.
14. Можем уже что-то тыкать
Зацените-ка, сейчас мы уже можем запустить проект, перейти на http://127.0.0.1:8000/docs (если кто зелёный, здесь 127.0.0.1 означает мой личный комп, а не адрес в интернете) и увидеть вот такое:
Это называется Swagger, убер-крутая штука, которая по сути является автосгенерировавшейся документацией к тому, что мы сделали. Более того, можно даже с её помощью делать тестовые запросики прямо из браузера.
Кстати, для DTF такая штука тоже есть, видали? Полюбуйтесь.
И да, там свои запросы можно тоже делать, например взять все тысячи постов Грейнджера, десятки тысяч его комментов и залайкать их сразу, чтобы сделать ему приятно (на самом деле, в DTF API есть защита от частых запросов, поэтому просто не будет). Для запросов надо только свой токен из профиля взять, но это сами разберётесь.
И ещё обратите внимание, что в нашем проекте есть 1 эндпоинт /posts, а в реальном проекте я насчитал 95 (девяносто пять (де-вя-но-сто пя-ть)) эндпоинтов, и это ещё не самое большое количество.
Ну а мы попробуем-ка обратиться к нашему монстрику! Вводим тестовые данные с каким-то пабликом по Евангелиону и нажимаем Execute:
В это время наши логи показывают, как демоны разделяются по оффсетам на 12980 постов, жрут их, и возвращают обратно:
А вот и результат. Выглядит, может, не очень красиво, но это по факту то, что нам нужно:
Давайте посмотрим, что скрывается за этими ссылками…
То есть это кто-то лайкает, да…
В такие моменты программист обычно тяжело вздыхает закидывается назад на стул, закрывает ладонями глаза и размышляет, нахрена он вообще дышит, живёт, работает… Потом вспоминает, что у него, как у самурая и пустого текстового файла, нет цели, а есть только путь, и садится за комп опять.
Короче, жить можно.
Ну что, всё с бэкендом? Нет, мы кое-что забыли.
15. С%ка, тесты!
Надо писать тесты. Как бы больно это не было.
Роберт Мартин сказал, что без тестов нельзя жить, поэтому жить без тестов не будем. На весь проект ушло 5-6 дней, и один чистый день — ушёл только на тесты.
Мы напишем 18 хорошеньких тестов, которые как минимум выполнят две важные вещи:
— скажут нам, если мы где-то накосячили (а они обязательно скажут);
— когда мы будем править проект потом, тесты скажут, если мы что-то испортили (а мы обязательно испортим).
А тесты — это вам не шпроты на черном хлебе, тесты надо уметь готовить. Вот посмотрите сюда:
Тут в коде есть как минимум несколько интересных вещей:
— фикстуры. Это такие штуки, которые подготовливают среду к тому, чтобы выполнялись тесты. То есть они что-то делают перед тем, как тесты будут запущены.
— патчи. В нашем случае они присутствуют в фикстурах. Патчами мы делаем так, что функция начинает выполнять не то действие, которое он выполняет по-настоящему, а захардкоженное в тестах действие. То есть PostFetcher в тестах будет не реально обращаться к VK API, а просто возвращать значение, похожее на то, что возвратил бы Контакт, например вот:
Здесь у нас идут друг за дружкой как добротные, качественные ответы, так и злые ответы, которые мы не должны пропускать.
— параметризируемые тесты. Это значит, что мы пишем только один тест, то в его шапку закидываем настройку, что он друг за дружкой обрабатывает разные данные. Скажем, нам нужно протестировать 10 кривых ответов. Нубасы делают на это 10 тестов, а мы сделаем 1 параметризируемый тест, а-е.
А ещё у нас будет вишенка на торте: асинхронные тесты. То есть мы запатчим асинхронные вызовы, и сами тесты тоже будут выполняться асинхронно. Вот так это будет выглядеть:
И ещё у нас будет одна большая фикстура на все тесты вообще:
Здесь мы назначаем тестовый клиент (который будет на наш фантомный сайт долбиться) и какой-то mock_aioresponse, я уже забыл зачем я это скопипастил из StackOverflow.
А ещё мы один раз сделали тестирование на основе свойств. Хз почему так называется, но используется тут библиотека hypothesis. Благодаря ей мы пишем не много разных входных значений на тест, а только одно, скажем, текстовое. И она создает 100 разных тестов с произвольными строками на входе. Каждый раз тесты разные, можно так нарваться на пару интересных сюрпризов в продакшене. Но в основном такое используется, чтобы понтоваться на собеседованиях о том, что мы это знаем.
Что, сложно тесты эти все писать? Да. Тем более это сложно морально, ведь без тестов все и так будет работать! Но зато когда мы эти тесты прогоним, то увидим картину, за которую любой прогер своего тимлида продаст:
Все тесты пройдены, и это, уверяю экспертно, настоящий кайф.
А хотя не, это не всё, зацените ещё прикол:
Здесь мы прогнали все тесты, используя библиотеку coverage. Она высчитывает, какие строчки были покрыты тестами, и показывает аж цветом, какие «зеленые» (покрыты), а какие «красные» (не покрыты), и выдает процент покрытия. У нас 92% строк покрыты тестами. Это более чем достойно, в продакшене 80-90% считается хорошим показателем.
Итак, мы имеем вот такую команду тестов, которые нас прикроют, если что. Ну как прикроют… Они как строгий и добрый батя накосячевшего подростка, который предпочтёт надавать сыну по жопе сам, чтобы жизнь потом не ударила ещё сильней.
Короче тесты — это классно, ребята, пишите тесты.
_. Блок постоянной боли
Есть одна вещь, которая редко где живописно описывается, но которая занимает 80% времени работы над проектом. Это:
— гугление;
— отладка ошибок;
— втыкание в экран в слезах и кровавом поту и диким желанием послать всё нахер, потому что ВОТ СЕЙЧАС ТОЛЬКО РАБОТАЛО А УЖЕ ПОЧЕМУ-ТО НЕ РАБОТАЕТ;
— перелопачивание того, что уже было написано. Например, pylint мне сказал, что я переусложнил код — значит надо выделить ещё одну абстракцию, потому что pylint умный, а я нет.
По сути, программисты любят свою работу за то, что сюрная жесть произвольной продолжительности вот этого вот блока рано или поздно внезапно превратится в работающий и взлетевший проект, и этот момент — единственный способ для большинства прогеров испытать настоящую, чудесную, детскую радость жизни.
А потом всё заново.
Короче, это как ежедневная игра в Dark Souls на low-level персе (люблю игры Миядзаки, кстати), нейропроцессы в мозгу почти те же. Или можете себе представить пыточное колесо, наполовину погруженное в воду и к которому привязывают программиста, и колесо медленно кртится. Вот когда программист в воде — это ощущения написания кода, а когда колесо вытаскивает его из воды — это ощущение от работающего кода, который скоро опять сломается. И так всю жизнь.
Но надо сказать, что именно это делают прогера сильнее. На лёгком миддлами и сеньорами никто не становится, страдание и преодолевание необходимо и неизбежно, к нему надо привыкать. Поэтому и говорят, что каменные чресла — главное оружие разработчика, то есть умение сидеть над задачей, не сдаваясь, до конца.
16. Формализируем зависимости
Нужно по-быстрому запилить файл requirements.txt, в котором будут собраны вещи, без которых наш проект работать не будет. Делаем это одной командой и получаем вот:
Этот файлик ещё пригодится.
17. Докер
Крутые ребята могут в контейнеризацию. Поясняю просто: это как виртуализация, только контейнеризация.
Ладно, на самом деле мы пишем вот такой файлик:
И благодаря ему мы создаем как бы контейнер, в котором наш созданный проект живет и в ус не дует. И мы можем его так же развернуть на любой другой машине. Это значительно облегчает процесс разворачивания на сервере, потом увидите.
Обратите внимание, что файл requirements.txt как раз тут используется. Контейнер заполняет себя зависимостями сам, обращаясь к этому файлику.
18. Фронтенд
Вот не люблю фронтенд (потому что не умею), а описывать надо…
Ну вот просто типа фронтенд и бэкенд — это как два брата. Они неразлучны, но без фронтенда быть скучно, а без бэкенда — вообще нельзя. Поэтому я как бы по жизни за бэкенд, и поэтому с фронтендом знаком слабо и пишу на JavaScript с помощью гугла и с некоторым отвращением, хотя, признаюсь, баловаться с CSS это прикольно.
Короче, создаем под него папку frontend, будет она так выглядеть:
Мы наворачиваем туда фреймворк React, и еще такую штуку как Bulma и Bootstrap, а также FontAwesome. Они используются, чтобы все было красиво (подробнее объяснять не буду, да и не надо — бэкенд все равно интереснее, отвечаю).
Нам тут что нужно сделать. Формы и кнопочки, логика тут прописывается:
Мы тут собираем и делаем запрос к нашему бэкенду и получаем данные для показа. Ну то есть как на бэкенде мы делали запрос к VK API, так и тут, мы с фронденда делаем запрос к API на нашем бэкенде:
При этом кнопочка ещё должна быть не тупой: она должна уметь входить в режим ожидания и вертеть спиннер, пока идет запрос к Контакту. А то человек на панике нажмёт кнопку 10 раз подряд, и сервер загнётся. Мы делаем это так:
Код самого спиннера в формате SVG копипастим с какого-то туториала, получается вот это:
Сойдёт.
Ну и осталось только заклепать формирование HTML для формы и постов. Выглядит это так:
Все написано вручную, вот этими вот руками. Поля, кнопка, цикл по постам и циклы по фото и видео в постах.
Правда, не особо красиво, от больших HTML мне душно бывает, и я уже хотел, чтобы это побыстрее все закончилось. Ну главное работает.
Есть картинки и видео, ссылки на посты, счетчик лайков и даты постов. Нормально.
19. Снова докер
Мы делали контейнеризацию для бэкенда. Сейчас сделаем контейнеризацию для фронтенда. Вот так:
Вверху мы законтейнеризировали наш фронтенд, который только что написали, а внизу — мы ещё добавили т.н. caddy. Это веб-сервер, который будет проксировать запросы от клиентов на конкретный порт фронтен… А, впрочем, пофиг, это долго объяснять. Но он нужен.
Дотошный читатель меня спросит: а почему я использовал ноунейм caddy, а не стандартный NGINX? Потому что NGINX я уже настраивал, а caddy нет, вот почему.
20. Оркестрируем наши контейнеры
Мы выше сделали два файла для контейнеров: для фронтенда и бэкенда. Сейчас нам нужно сделать один общий файл для всех контейнеров проекта: его называют docker-compose.
Он тут простой: он берёт два контейнера и запускает их по очереди, притом сначала бэкенд, потом фронденд. Ну и ещё пару настроек и работа с портами. То есть от берёт 2 и больше контейнера вокруг и создаёт из них согласованное приложение, которое сразу и под ключ работает. Это называется оркестрацией, и красота этого слова хорошо передаёт приятное ощущение от того, когда docker-compose выполняет свою работу.
Это нужно для того, чтобы мы на любой машине могли запустить вот этот вот файл — и всё сразу же развернулось без продолжительной головомойки.,3
Ну вот и всё, осталось развернуть это дело на настоящем интернете.
21. Закидываем проект на GitHub
Естественно, нужно сначала выложить проект в интернет. На самом деле, мы постоянно, пока делали проект, создавали коммиты — дискретные программные акты, которые в конце концов привели нас к фишишу. Коммиты эти собираются в Git, а выгрузим мы это — на GitHub:
Ну вот такой проектик, на 69 коммитов в одну каску (я не подстраивал 69, оно само, честно).
22. Деплой
Покупаем себе VPS у любого провайдера. VPS — это виртуальный сервер. То есть у провайдера есть 1000 физических серверов, на одном из этих серверов есть 1000 виртуальных серверов, и один из них мы купили за ~400 рублей в месяц. В панели видим такое:
Все, у нас есть сервер с красивым номером 95.163.242.198, и ешё нам дали от него логин и пароль.
На почту нам пришел логин и пароль, подключаемся к серваку через SSH, то есть через командную строку. Делаем это прямо в PyCharm Pro, нормально:
И все, мы подъехали, можно делать что хотим:
А делать мы хотим вот что. Нам нужно ввести четыре команды. Мне лень описывать, возьму с документации (которую я в будущем напишу), что мы сделаем:
То есть: 1. склонировали проект с GitHub; 2. открыли директорию; 3. создали файл с секретиком; 4. запустили docker-compose.
Вот 4. docker-compose — это настоящий секс, просто по-настоящему. Если бы мы вручную собирали этот проект, ушло бы ещё много времени на ужас, пот и слёзы. А тут — одна команда и все. Если будем переносить на другой сервак — то там тоже нужна будет одна команда и все. Тяжело выразить, как это облегчает жизнь. Сейчас без Docker вообще никуда.
Теперь, если в браузере вбить 95.163.242.198 — наш сайт откроется! Ух!
23. Домен
Покупаем домен vktastiest.ru, чтобы люди заходили на него, а не на 95.163.242.198. Стоит он около 300 рублей, покупаем на год и убираем автопродление — через год даже я про него забуду:
Тут нужно пару вещей поднастроить, и от это мы настроили, и через 2 часа мы можем заходить не на 95.163.242.198, а по нашему домену. За 2 часа — должны кэши DNS обновиться, если вы понимаете о чем я. Живём!
24. Документация
Ну, и на сладкое: пишем документацию, чтобы человеки со стороны могли пользоваться нашим проектом как своим и не гадали, как его запускать.
Пишется это всё в формате Markdown:
Ну всё, великолепно, теперь у нас все есть и на гитхабчике, и в интернетике.
Победа!
А знаете, что самое смешное?
Это девиз всего IT, но к тексту выше относится особенно. Проект, который я так долго описывал — это ничто, это как пройти Doom на «I’m too young to die», и этим понтоваться перед младшим братом, который в детский сад пошёл. Ну то есть в его глазах ты победитель зла и король мира, но по сути ты жалок и ещё ничего не понял.
По своему функционалу проект никчемен и вообще днище. Он и на 20% не покрывает того, что происходит в реальной жизни.
Это смешная синтетическая ерунда, несмотря на то, как это было сложно.
Сначала джун думает, что когда он это сделал, он уже крутой и всё может. А по факту он только начал погружаться в это море ужаса, печали, адреналина и кофеина.
Я даже боюсь думать о тех, которые вот-вот только закончили курсы по Питончику, всяким его циклам-генераторам-итераторам-компрехеншенам и думают, что их уже можно брать вершить великие дела за большую зарплату, эх…
Какое горе, какое разочарование, всё это IT. Это как живого кита хавать китайскими палочками. Но ладно.
Что по-хорошему нужно было бы сделать ещё:
— подключить базу данных. Хотя бы SQLite. У нас нет БД, это просто жалкое зрелище. Ни одного запроса, даже через ORM, это что такое вообще;
— настроить мемоизацию и кэширование, чтобы сайт запоминал посты от сообществ и не делал бы новый запрос каждый раз;
— сделать нагрузочные тесты через locust;
— гораздо плотнее поработать с нагрузкой и обработкой исключений, чтобы минимизировать падение сайта от живых запросов. Сейчас если он упадёт, я не удивлюсь ни капли;
— настроить SSL на сервере (чтобы замочек был. Но это стоит почти 1000 рублей, было жалко);
— сделать поиск данных в постах через таски с Celery, с мониторингом на Flower (это не я, это сервис такой);
— сделать не один токен к VK API, а хотя бы 10 токенов, и делать ротацию по ним, чтобы не ждать каждые 3 секунды долгого ответа;
— сделать пагинацию в API, чтобы не за один раз отправлять 6969 постов, а хотя бы по сотке. Также пагинация нужна на фронтенде, чтобы держать на одной странице хотя бы 50 постов, а не все 500;
и т.д., и т.д., и т.д…
Но вообще, у меня была цель первый раз в жизни срастить бэкенд и фронтенд и все это задеплоить через docker-compose. У меня это получилось, и я доволен. Доводить до ума буду потом то, что будет достойно доведения до ума, и за огромные деньги, конечно.
Выводы
Я вижу, что вы нифига не прочитали и просто проскроллили вниз к выводам, но уже по длине текста и картинкам вы:
— примерно понимаете масштаб того, что нужно знать/уметь, чтобы сделать даже самый одноклеточный сайт;
— все ещё не имеете представления, насколько эти знания ничтожны по сравнению с тем, что нужно для запуска настоящих больших и жирных проектов. Даже не так: мы с вами (да, я тоже) не просто не имеем представления, мы даже не имеем представления, насколько мы не имеем представления, сечёте?
— можете понять и простить людей, которые сделали сайт DTF. Это хорошие, добрые, умные и нежные люди, которые работают как могут. Ну это я про девелоперов, по крайней мере, про их руководителей ничего уверенно сказать не могу, а то забанят.
Если кому-то было интересно почитать, мне будет приятно; если не понравилось — напишите что херня полная, я переживу. Только звезду мне поставьте, ну будьте людьми, будьте людьми, это ж социальный рейтинг программистов, как в той серии Черного Зеркала, мне эти звёзды больше хлеба нужны.
И главный вывод
Содержание скрыто
Показать
Кацураги Мисато > Аянами + Лэнгли
Содержание скрыто
Показать