![](https://habrastorage.org/webt/l4/qn/c5/l4qnc5pspx1jmyo-fdvtinvd_qy.jpeg)
В этой статье я расскажу, как делал свой проект социальной сети для сферы искусства havidea.ru от идеи до релиза. Расскажу о технической части, о мотивации и самоорганизации, какими инструментами пользуюсь в процессе разработки, о проблемах в работе со сферой искусства, с которыми я столкнулся почти сразу после запуска. Проект пережил реинкарнацию, т.е. был первый вариант, который я забросил и финальный, второй, который ушел в релиз.
В сфере веб-разработки я работаю немногим более трех лет. Проект поднимался в одиночку в свободное от основной работы время и главной целью было — выпустить продукт в установленные сроки (6 мес.).
Вдохновение, идея, исследование
Будучи подростком, я начал увлекаться музыкой, живописью. Чуть позже загорелся 3D графикой и даже успел заработать на 3D моделях первые копейки. Еще пару лет спустя всерьез занялся фото- и видеосъемкой и в этот же период на уроках вокала (и такое было в моей жизни, да) познакомился с будущей женой — актрисой. Все это подтолкнуло сделать какой-нибудь проект для поддержки “веселых” судеб творческих людей. Иии? Социальная сеть? Почему бы и нет? Но это же хейтят, мол, соц. сети умирают. У кого-то умирают, а у меня получится, верно? И вообще, если есть обоснованная идея и концепция, почему бы не воплотить это в веб-страницу? Загуглив список социалочек, наткнулся на интересный вариант — stage32. На мой взгляд, это единственная серьезная зарубежная площадка, собиравшая сообщество причастных к кинопроизводству. В России аналогов на то время (начало 2017 г.) я не нашел (плохо искал?). Решено. Сделаю свой сервис, опираясь на лучшие образы, практики и UX уже существующих соц. сетей, но с уклоном к сфере театра, кино и искусства в целом.
Идеология проекта
Некоммерческий, без рекламы, максимально полезный для самих участников. Свободный, без слежки, без метрик. Защита пользовательских данных.
Первый вариант (2017 г.)
Любой проект должен начинаться с постановки и ответа на вопросы: для кого? Для чего? Какую проблему это решает (цель)? Какие есть альтернативы? Какие преимущества можно предложить? После четких и лаконичных ответов, я составляю список функциональности будущего проекта. Далее определяюсь с костяком: убираю все хотелки и фантазии из общего списка функционала и оставляю только самое необходимое — то, без чего приложение не будет функционировать. От минимального функционала подбираю стек. Ищу примеры реализации. На этом этапе уже есть общая картина: что делать, для чего и как. Весь процесс, комментарии и мысли записываю в блокнот, чтобы повторно не решать то, от чего ранее отказался.
Проектировать UI начинаю с листка бумаги и карандаша. Любой листок, который есть под рукой, идет в дело, пока мысль не убежала. Определяюсь со страницами и провожу вторую грубую итерацию уже в электронном виде (проще что-то изменить):
Изображение наброска страниц![image](https://habrastorage.org/r/w780q1/webt/im/ek/ns/imeknsdy5hekt9mqq7mkfmegxlo.jpeg)
![image](https://habrastorage.org/webt/im/ek/ns/imeknsdy5hekt9mqq7mkfmegxlo.jpeg)
Далее прорабатываю эскизы детально. Вот, например, самый первый вариант страницы профиля:
Изображение страницы профиля![image](https://habrastorage.org/r/w780q1/webt/s0/za/m8/s0zam8n3w3mnonxj6e0db36m3ja.jpeg)
![image](https://habrastorage.org/webt/s0/za/m8/s0zam8n3w3mnonxj6e0db36m3ja.jpeg)
Посты, комменты, лайки, альбом с фотографиями — все по классике. Из нового:
расширенный профиль для актеров, поиск по профессиям и навыкам.
Для разметки макета использовал modulargrid.org:
Изображение страницы профиля с модульной подложкой![image](https://habrastorage.org/r/w780q1/webt/si/w9/ow/siw9owp-aekihtay6quxux8fwlc.jpeg)
![image](https://habrastorage.org/webt/si/w9/ow/siw9owp-aekihtay6quxux8fwlc.jpeg)
Я экспериментировал с 12, 15 колоночными сетками, но остановился на 12. Хочу отметить, что верстка по модульной сетке штука неоднозначная. Вам не всегда удастся вписать информацию в блоки, потому что интерфейсы — это графическое отображение данных. Я исхожу из принципов Data-Driven design, т.е. основное назначение интерфейсов — представлять данные и удобные варианты взаимодействия с ними. Именно поэтому дизайнер != веб-дизайнер. Вернувшись к проблеме модульной сетки скажу, что она лишь помогает в первоначальном расположении блоков, а финальный вариант должен утвердиться с помощью тренированного глаза. К тому же, в любой сущности должна быть изюминка или отхождение от правил, чтобы добавить живости.
Пара набросков главной страницы:
Набросок главной страницы 1![image](https://habrastorage.org/r/w780q1/webt/nh/pk/hf/nhpkhf1xjilwaelsno0qilsd2ou.jpeg)
![image](https://habrastorage.org/webt/nh/pk/hf/nhpkhf1xjilwaelsno0qilsd2ou.jpeg)
Набросок главной страницы 2![image](https://habrastorage.org/r/w780q1/webt/xb/kl/e_/xbkle_micaxleie8daa7kzczmv4.jpeg)
![image](https://habrastorage.org/webt/xb/kl/e_/xbkle_micaxleie8daa7kzczmv4.jpeg)
Некоторые решения выглядят не совсем удачными и убираются/правятся при верстке. На этапе проектирования надо давать себе свободу и не выводить все до идеала.
Страница входа:
Изображение страницы входа![image](https://habrastorage.org/r/w780q1/webt/z2/bh/5k/z2bh5ktk9cq8x4xxxal5y46xiao.jpeg)
![image](https://habrastorage.org/webt/z2/bh/5k/z2bh5ktk9cq8x4xxxal5y46xiao.jpeg)
После набросков десктопной версии, уделяю внимание мобильной. Графическая часть готова? Нормас. Пора кодить.
Frontend первого варианта.
В качестве бэкграунда для главной страницы я использовал библиотеку Three.js для работы с WebGL. Треугольники свободно плавают и “следят” за мышкой. Забегая вперед скажу, что в реинкарнации я отказался от Three.js и сделал на css + png, потому как библиотека весит ~570кб и использовать ее для одного несложного эффекта показалось расточительством. В разработке я придерживаюсь установок: минимализм, производительность, легкость поддержки. Так как социальными сетями примерно на 3/4 пользуются с мобильных, то был отдан приоритет легковесности и скорости. Как библиотеку UI компонентов взял Bootstrap 4. Без jquery, только css. Я пробовал обертку bootstrap-vue, но как-то не зашло. Бросались в глаза невалидные html теги и хотелось свободы кастомизации. Как вы могли догадаться, фреймворк Vue. Хотелось изначально заложить хорошую индексацию поисковиками, поэтому докрутил Nuxt.
Backend первого варианта.
Laravel. Для one-man проектов vue + laravel = must have. Скорость разработки, большое сообщество, куча готовых пакетов. Архитектура API-first (бэкенд изначально разрабатывается как API).
Какое API без документации? ApiDoc отличная штука, которая умеет генерировать документацию из PHPDoc. Роутинг кастомизировал и вынес файлы роутов из единого api.php, т.е. один файл, один роут. Для удобства и для генерации документации. Вдохновение черпал из Apiato. Неплохой starter kit для API, напичканный разными паттернами проектирования и оригинальным архитектурным Porto, призванным разбить приложение на модули, но по сути ведущий к монолиту. Судя по репозиторию, проект заброшен более года назад. Скорее всего, по причине активного распространения микросервисной архитектуры.
Отдых, прокачка скиллов
Шел 2018 год. В первой версии я успел реализовать регистрацию, аутентификацию, страницу профиля с редактированием, страницу настроек. Времени по вечерам было немного. Тогда я только начинал путь vue, да и ssr на nuxt капризничал. В итоге, через 4-5 месяцев сдулся. Это был амбициозный проект и не хватило скилла его поднять, не упав самому. За 2018 год я сильно подтянулся как full stack разработчик, освоил docker и в начале 2019 начал все с нуля. Ну, почти с нуля.
Второй вариант (2019 г.), релиз
Frontend второго варианта.
От nuxt ssr я отказался — прослойка из node.js требует дополнительного внимания, да и не видел в нем нужды конкретно на этом проекте. Bootstrap заменил на Quasar — полноценный vue UI (и не только) framework (почему взял его расскажу ниже). Интерфейсы полностью переделал, ушел от вк-стайл концепции. Теперь insta-стайл. Добавил возможность создания трех типов публикаций: фото, видео и текст. В макете использовал 24 колоночную сетку. Сейчас сервис выглядит так:
Финальный вариант первого экрана![image](https://habrastorage.org/r/w780q1/webt/dw/jq/5i/dwjq5i63fftfe_epupj7qqolg0o.jpeg)
![image](https://habrastorage.org/webt/dw/jq/5i/dwjq5i63fftfe_epupj7qqolg0o.jpeg)
Да, можно сделать верхнее меню прозрачным. Но нужно уметь хотелкам сказать “нет”. Главную страницу я в итоге нарисовал заново. Поэтому, не стоит вдаваться в детали раньше, чем будет полная картина. Рано или поздно вы захотите все изменить и не важно, насколько прекрасным было решение. Конечно же, сайт полностью адаптирован:
Страница профиля на мобильном![image](https://habrastorage.org/r/w780q1/webt/1n/v3/-r/1nv3-rae72v5hedykaogf43fsqw.jpeg)
![image](https://habrastorage.org/webt/1n/v3/-r/1nv3-rae72v5hedykaogf43fsqw.jpeg)
Про TypeScript. Я пробовал его внедрить, но в последствии вырезал, потому что строгая типизация требует больше времени на расстановку типов, интерфейсов. Я пришел к выводу, что TS без strict режима не имеет смысла. Оно и верно — зачем типизация без указания типов. В strict режиме приходится описывать абсолютно все и это как минимум +30% к срокам разработки. А если у вас не утверждена схема обмена данными с бэкендом, то придется постоянно отвлекаться на мелкие правки. Местами вам понадобится игнорить ошибки компилятора добавлением комментария @ts-ignore в код только потому, что вы не ответственны за сторонний код, который не полностью поддерживает TS. Кроме того, вся выгода от TS раскрывается в сложных логических расчетах, т.е. типизировать .vue файлы оказывается несколько избыточным. Буду рад услышать комментарии по этой теме.
Когда фронт был готов на 90%, я задонатил Browserstack и протестировал приложение на Safari. Не жалею потраченных денег, потому как удалось пофиксить парочку простых, но критичных багов. Минутка бомболейло. Safari, когда вы уже начнете думать о пользователях и разработчиках? Годами не исправляете баги. Особенно залипающий скролл в модалке. Я не нашел 100% работающего способа, как заставить Safari корректно скроллить контент в модальном окне. Буду рад, если кто сталкивался и подскажет решение.
Помимо основного приложения, сделал еще и простенькую админку со своим апи:
Screenshot админки![image](https://habrastorage.org/r/w780q1/webt/o4/sx/gr/o4sxgrlz9n4xdlsnqaz91tok6iq.jpeg)
![image](https://habrastorage.org/webt/o4/sx/gr/o4sxgrlz9n4xdlsnqaz91tok6iq.jpeg)
В админке ничего примечательного. Просто UI покрытие для некоторых фич, из-за которых лень лезть в базу и править данные руками.
Backend второго варианта.
Laravel. Обязательная валидация всех входящих данных, cors заголовки, дополнительные заголовки безопасности secure-headers, следование RESTful спецификации (как-нибудь попробую JSON-RPC), Fractal для трансформации отдаваемых данных на фронт. Try-catch всего, чтобы пользователь не давил мышку, а получил внятную причину ошибки. Автоматические дампы обеих баз данных с помощью db-dumper. Какого-либо автоматизированного тестирования не писал, ибо ограничен по времени. Надо подкачаться и попробовать TDD, может получится не сильно увеличивать сроки разработки или даже сократить.
Отдельно хочется сказать, что я избегаю использования абстракций на начальных этапах проектирования, если без них сейчас можно обойтись. Их преждевременное использование ведет к усложнению модуля приложения, который может быть никогда не использован. Решайте проблемы по мере поступления. Да, соблюдать баланс между архитектурой и сроками не просто и это приходит только с опытом, но лучше потратить время на продумывание базы данных, а переписать код приложения можно в любое время. Самый важный ресурс, который у нас есть — это время. Лучше выпустить не идеальный продукт и быть первым, чем потом догонять конкурентов. А они будут.
Проблема, стагнация
Запуск состоялся в конце мая. Я начал заниматься рекламой и почти сразу наткнулся на похожий сервис. Да, они по сути реализовали такую же идею. Года на 2 раньше. Надо было лучше исследовать рынок и мониторить его постоянно на предмет новых сервисов. Но проблема даже не в этом. В процессе дискуссий, размышлений и просто жизненного опыта я пришел к выводу, что проблема трудоустроенности людей искусства намного глубже и, возможно, специализированной социальной сетью не помочь. Это рыночная проблема нехватки рабочих мест. В каком направлении развивать продукт я точно не знаю. Сейчас проект переживает стагнацию.
Под капотом
Технологии, вошедшие в релиз
- Vue
- Quasar (UI библиотека vue компонентов). Это офигенный, легкий, красивый и минималистичный фреймворк и самое главное — mobile и desktop pixel perfect. Да, я пробовал vuetify 2 beta. Но как по мне, vuetify для мобилок не подходит и в целом его API и документация более запутанные, чем у Quasar. Также, у Quasar есть ряд плагинов и импортируемых функций. Например, работа с датами, touch событиями, определение платформы по user-agent, программные dialogs (модалки), работа с DOM и скроллингом: все это сужает круг зависимостей в package.json.
- Laravel
- Docker / docker-compose. Описывать docker-compose.yml не буду, но приведу несколько моментов: разделение контейнеров по network’ам. У меня их две: web и app; самостоятельные инструменты (Portainer, Traefik) в отдельных docker-compose, чтобы не падало основное приложение при перезапуске.
- Redis. Объектное хранилище с функционалом очередей. Если для очередей нужно что-то помощнее, попробуйте RabbitMQ.
- MySQL
- Mongodb. В монге храню публикации, комменты, медиа-файлы, уведомления — все самые объемные данные. Монга проще масштабируется, чем мускул.
- Nginx
- Traefik. Очень дружелюбный и простой в настройке reverse-proxy для docker окружения (и не только). Плюс сам получает ssl сертификаты let’s encrypt. Раньше использовал Certbot, а теперь вообще не парюсь с дополнительными зависимостями.
- Portainer. Контейнеры поднимаю руками через docker-compose, но иметь наглядный интерфейс по их состоянию очень полезно. Туда же падают логи из stdout / stderr. Если бюджет позволяет, то для логов можно поставить какой-нибудь ELK.
- ElasticSearch. Спасибо Laravel сообществу, что есть Scout драйвер для ES (Scout сам обновляет данные в индексах-базах эластика). Кстати, не забывайте закрывать сервис с внешки. Один из вариантов это сделать — в докер-контейнере прописать ports: «127.0.0.1:9200:9200» (заметка: для безопасности лучше не использовать стандартный 9200 порт). В эластике два индекса: по профилям и по публикациям. Настроен hunspell для русской морфологии.
Примечательные сервисы
- AWS Saas. Хотел поставить Minio S3, но в бюджет совсем не вписывается.
- Mailgun. У Laravel из коробки есть интеграция с этим сервисом. Очень удобный, со своим интерфейсом и (!) очередями.
- Sentry.io Saas. Можно поставить как self-hosted. Супер удобный и полезный инструмент отладки. Подключил и фронт и бэк к нему. Настроил релизы. Все runtime ошибки отслеживаются и вовремя обнаруживаются посредством, например, уведомлений на почту. Красота.
Полезные инструменты
- Trello — удобные канбан доски. У меня такой набор: сделать, готово, тестирование, обсуждение, отмена.
- Browserstack — тестирование на iOS, “любимом” Safari.
- Gitlab — репозитории и ci/cd. CD как таковой не настраивал — свой gitlab runner не поднимал, а давать коннектиться по ssh гитлабовским раннерам как-то стремно. Devops не моя сильная сторона, к тому же. По части CI — сборка фронта, пуш в репозиторий gitlab. Переменные храню здесь же в разделе ci/cd -> variables, которые пробрасываются на этапе сборки.
Итог
Несмотря на сложившуюся ситуацию с моими представлениями на особенности рынка сферы искусства, я нисколько не жалею несколько сотен затраченных часов. Процесс завораживал, давал кучу опыта и не только программерского. Я сделал сервис таким, каким задумывал и горжусь финальной реализацией. Мною двигала вера в то, что я смогу помочь творческим людям. Это было главной мотивацией. Может, изначальный некоммерческий подход поставил проект в сложное положение? Есть (спорное) мнение, что надо начинать либо бизнес, либо ничего. Как это ни печально, но иногда лучше вовремя остановиться, чем делать то, во что не веришь. Если придет новое понимание в какую сторону двигаться, то продолжу развивать. Буду польщен вашими мнениями.