От переводчика: эта статья — сокращенный перевод оригинального поста веб-разработчика Джесси Хорна. Его работа и одновременно хобби — веб-дизайн. Своими наработками и полученным опытом Джесси частенько делится с другими программистами, как опытными, так и начинающими.
Некоторое время назад я написал довольно объемный пост на Hacker News, который получил солидную поддержку читателей. Я обратил внимание на возможности этого ресурса и решил попробовать создать его клон, для того чтобы получить новый опыт и знания.
Skillbox рекомендует: Практический годовой курс PHP-разработчик.
Напоминаем: для всех читателей «Хабра» — скидка 10 000 рублей при записи на любой курс Skillbox по промокоду «Хабр».
Изначально это казалось мне отличной целью, где набор инструментов и тактика работы были предопределены. Ранее я работал над менее крупными задачами, используя разные языки и фреймворки. Единственное, чего не было, — это крупного проекта, который бы позволил собрать все это вместе.
Работать над новым проектом я решил с нуля, используя язык Crystal. Это удобный инструмент, который к тому же еще и новый. Он быстрый, принципы работы с ним похожи на Ruby. Он статистически типизирован плюс является open source. Но просто нового языка тоже недостаточно, поэтому я решил усложнить свою задачу, и сделать не клон Hacker News, а усовершенствованный вариант этого ресурса.
Кстати, я думал, что создание обычного клона будет легкой задачей. И то, что это не так, я понял чуть позже, начав работу.
Не метьте слишком высоко
Я не хочу сказать, что вы не должны ставить амбициозные цели. Пробуйте достичь звезд, через тернии или без них. Мечтать — полезно, пытаться достичь того, чего не мог сделать ранее, — необходимо для успешного продвижения по профессиональной лестнице.
Я сказал, что не стоит пытаться сразу бросаться на амбразуру выполнения сложной и большой задачи. Выберите то, что вам нужно в конкретный момент для реализации идеи. Далее рекомендую разбить значительные цели на более мелкие. Если у вас слишком много кода, в котором большое количество «мусора», то попробуйте все упростить и структурировать.
Я даже не могу выразить словами, насколько важно разделить большую задачу на несколько более мелких.
В моем случае я столкнулся с различными новыми проблемами, с которыми не встречался ранее. Во-первых, я работал Crystal лишь однажды — когда создавал приложение, сложность которого ненамного превышала сложность программы типа «Hello, world!». В прошлом я использовал Python, Lua, PHP. Новый язык был первым препятствием на пути к реализации проекта.
Вторым стал фреймворк. Crystal, будучи новым языком, пока еще имеет не слишком много фреймворков и документации для них. Я решил использовать Kemal для своего клона. Я надеялся на то, что фреймворк интуитивен, поскольку в своей работе встречал именно такие. Но здесь оказался другой случай — отдельные вещи было нелегко понять. Например, некоторые участки кода выглядели вполне нормально, но почему-то не работали. И найти причину проблемы в интернете было сложно все по той же причине — новизна языка и самого фреймворка. В некоторых случаях мне приходилось подолгу останавливаться и разбираться с причиной проблемы. До настоящего момента я никогда не заглядывал в исходники, например, того же Flask.
Третье препятствие — специфические цели, которые я выбрал для проекта. Для того чтобы сделать мой клон полезнее, я решил добавить ряд функциональных особенностей. Я работал с Hacker News ранее, поэтому знаю многое о достоинствах и недостатках этого ресурса. Мне пришло в голову, что будет хорошо задействовать аналитические данные, предоставляемые GitHub. Используя их, я бы мог добавить статистику по количеству просмотров и активности пользователей на сайте.
Таким образом, я решил, что мой клон должен показывать по крайней мере просмотры и клики для каждого поста. Такая функция, возможно, была бы полезна для пользователей, а ее реализация стала бы хорошей практикой для меня. Но я не думал, что это займет столько времени! Сейчас проект представляет собой скорее proof-of-concept, чем готовый ресурс. Кроме просмотров и кликов, я также решил добавить отображение появляющихся комментариев, чтобы они показывались в real-time. Если бы не эта дополнительная задача, проект был бы завершен гораздо быстрее.
Сейчас проект поддерживает авторизацию, размещение и сортировку постов, взаимодействие с другими пользователями путем комментирования и просмотра профилей и т.п.
Четвертая проблема, с которой я столкнулся, — хаос. Миграции, модели, просмотры, API-контроллеры, CSS и JavaScript-код накапливаются очень быстро. И все это превращается в кашу. Я попробовал решить проблему, и у меня почти получилось. Но отчасти проблемные места в коде моего проекта еще встречаются — вы можете без проблем это заметить. Так, во многих местах код повторяется, эндпоинты не организованы, нейминг усложнен, что приводит к росту объема кода и большому количеству запросов к базе данных. Постепенно я решаю эту проблему.
Во многих местах код повторяется
Когда проект стартовал, я решал проблемы по мере их появления. Например, нужно было проверить, аутентифицирован ли пользователь, — и я нашел оригинальное решение, которое занимало три строки или около того в зависимости от маршрута. Я очень спешил внедрять найденные решения.
Вообще мне нужно было следовать принципам DRY с самого начала. Не повторяйтесь! Мне нужно было написать промежуточную программу, которая бы делала, что необходимо, а затем просто применяла найденное решение в тех случаях, когда это требовалось. В дальнейшем я буду корректировать свой проект исходя именно из этого принципа.
Нейминг эндпоинтов и организация
Раньше я разрабатывал API в команде Pioneer. Мы использовали REST — стиль архитектуры, которому я фактически присягнул, будучи новым членом команды Pioneer. В этой команде я работал над небольшими элементами огромного приложения. А вот в своем новом проекте мне все пришлось писать с нуля.
«RESTful API» должен иметь Uniform Interface, так сказано в «Вики». В своем проекте я организовал все так, что эндпоинты определялись в source-файлах, которые назывались соответственно функции или назначению. Регистрация и выход из приложения были прописаны в «auth.cr». Логин пользователя прописывался в «user.cr».
Несомненно, эта часть требует переработки. В дальнейшем я организую все так, чтобы действия относились к эндпоинту "/user", просто потому, что все это имеет отношение к «User». Например, для улучшения структуры проекта разделю код на более удобные и управляемые части с большим числом файлов. Создам папку «src/user/auth/», в которой будут содержаться функции логина, регистрации и выхода пользователя из приложения.
Слишком много запросов
В этом проекте я пытаюсь масштабировать свои идеи. В настоящее время к базе данных осуществляется слишком много запросов. Так, если бы у приложения было сто пользователей, я бы просто сошел с ума, пытаясь узнать, сколько запросов к базе данных выполняется каждые несколько секунд. Сейчас клиент обновляет статус сообщений каждые 10 минут. Кроме того, пост циклически определяет, был ли он просмотрен пользователем. Во время каждой проверки происходит запрос к базе, это выполняется в соответствии с текущим фильтром. И все это значительно нагружает сервер.
Все, что описано выше, — лишь примеры проблем, с которыми я все время сталкиваюсь. Я не могу описать их в полном объеме. Тем не менее сейчас я размышляю над тем, чтобы документировать мои проблемы и решения. Надеюсь, что все это поможет другим программистам увидеть и понять мои ошибки и избежать собственных. Я знаю, что если буду использовать комбинацию Redis и MySQL или Postgres, то смогу ускорить выполнение запросов. Но пока что остановлюсь на этом.
Надеюсь, что вам понравилась статья и вы смогли почерпнуть что-либо полезное для себя.
Skillbox рекомендует:
- Онлайн-курс «Профессия frontend-разработчик».
- Образовательный онлайн-курс «Профессия веб-разработчик».
- Практический курс «Мобильный разработчик PRO».
Автор: skillbox