Skip to content

TheComents 3.0, russian

Ilya N. Zykin edited this page Jan 9, 2015 · 17 revisions

TheComments 3.0, Расуждения о системе комментированя на сайте

TheComments - это комплексное решение для организации комментариев на сайте, использующем Ruby on Rails. Причиной появления TheComments стала глубокая неудовлетворенность другими доступными open source решениями. А если быть честным, то их фактическое отсутствие.

Сложность организации комментариев на сайте заключается в том, что эта задача не решается только на стороне сервера или клиента. Это одна из многих full-stack задач, целенапраленым решением которых, увы, практически никто не занимается. Причина этого вполне понятна, full-stack задачи подразумевают большой обем разнородной работы (JS, backend, архитектура) и большое количество инвестиций (временных, интеллектуальных или финансовых).

К тому же, объем данной задачи предполагает тщательное планирование и довольно глубокую проработку архитектуры конечного продукта, иначе результат будет малопригодным для использования в серьезном production'е.

Ниже я познакомлю вас со своим виденьем устройства системы комментирования на сайте. Расскажу о том, что и по камим соображениям я планировал сделать и что в итоге реализовал в своем решении.

Мне кажется, что мои мысли на этот счет могут быть полезны для любого веб-разработчика вне зависимости от конкретного языка программирования или фреймворка.

В завешающей части статьи я попробую софрмулировать свое представление о том, чем open source и R&D проекты независимых разработчиков могут быть полезны крупному бизнесу, в надажде однажды привлечь к подобным проектам внешние инвестиции.

Ожидания от предполагаемой системы комментирования

В ходе размышлений об идеальной для меня системе комментирования, я сформулировал для себя ряд следуюущих требований:

  1. Древовидные, c задаваемой глубиной вложенности
  2. Незарегистрированные пользователи (гости) могут оставлять комментарии
  3. Отсутствие капчи или других анти-спам решений "мешающих" пользователю. Наличие защиты от спам-ботов
  4. Наличие пред-модерации для комментариев "гостей"
  5. Быстрая отрисовка дерева комментариев без кеширования
  6. Добавление коммантариев на страницу без перезагрузки страницы
  7. Интеграция с антиспам сервисами
  8. Готовность к внешним процессорам контента (Sanitize, Emoji, Markdown ...)
  9. Уведомление пользователей об ответах к их комментариям
  10. Наличие админки для управления комментариями
  11. Модульность конечного решения. Код написанный в соответствии с современными техниками

В итоге все данные требования я реализовал в TheComments. Ниже я пройдусь чуть более подробно по каждому указанному пункту.

Древовидные, c задаваемой глубиной вложенности

Если размышлять о комментариях в терминах вставка/чтение, то можно придти к выводу, что создание комментария это событие довольно редкое по отношению к событию чтения списка комментариев и построению дерева.

Кроме того, довольно трудно предсказать форму выборки комментариев и условия налагаемые на этот процесс. Воплне вероятно, что в последствии будет необходимо отображать только часть дерева комментариев при загрузке страницы, а затем подгружать поддеревья по требованию.

Классический пример такого подхода вы можете видеть в LiveJournal, где в постах с большим количеством комментариев часто отображаются только верхние уровни, а более глубокие уровни дискуссии загружаются по клику.

В TheComments для обеспечения древовидного хранения комментариев в базе мной используется алгоритм Nested Set, который в целом должен покрыть основные предполагаемые требования. Так же отмечу, что экосистема rails располагает отличным и проверенным решением для работы с Nested Set.

Незарегистрированные пользователи (гости) могут оставлять комментарии

Всякий комментарий на сайте я расцениваю как подарок со стороны пользователя. И мне кажется, что любой проект (особенно некрупный) просто обязан создать все условия, что бы процесс создания комментария на сайте был пределно простым. Как пользователь я вижу 2 веские причины не оставлять комментарий

  1. Требование зарегистрироваться на сайте (или даже простое использовать соц сети для этого)
  2. Наличие капчи или других навязчивых способов антиспам обороны

Я считаю, что в большинстве проектов дать анонимному пользователю возможность оставить комментарий - это хорошая и полезная идея. Я не готов отказаваться от нее ввиду технических, организационных или маркетинговых ограничений.

В TheComments по-умолчанию я предоставил возможность гостям оставлять анонимные комментарии. Конечно же, при необходимости это поведение можно легко изменить.

Отсутствие капчи или других "мешающих" анти-спам решений

Вторым важным для меня препятствием для написания комментариев является любая форма капчи. На мой взгляд, пользователь не должен решать задачу спамообороны, т.к. это абсолютно не его проблема, а проблема технического характера, которую соответственно нужно решать технически или, в крайнем случае, организационно, привлекая к этому процессу модератора.

Однако, если мы принимаем решение о допустимости анонимных комментариев, то мы должны что-то предпринять, что бы система комментирования не превратилась в пылесос затягивающий в себя генерируемый ботами флуд, рекламу виагры и кросовок.

На данный момент в TheComments реализована многоступенатая система защиты от спама, которая совершенно прозрачна для пользователя, оставляющего комментарий. Вот базовое описание системы защиты от спама.

  1. Обязательность JS. Комментарий можно оставить только с помощью xhr POST запроса (AJAX-ом), что отсекает ряд примитивных ботов, которые не поддерживают исполнение JS. Как вы можете догадаться, написание и использование ботов поддерживающих JS - удовольствие довольно дорогое, а потому такое простое требование, как поддержка клиентом JS является довольно надежным способом спамообороны. Рассуждать об интересах добросовестных клиентов у которых откючен JS можно сколь угодно долго, но я допускаю такое ограничение системы, ввиду ничтожного количества пользователей не поддерживающих JS по каким-либо причинам.
  2. Время ожидания, перед отправкой. Обычно боты не удосуживаются подождать перед отправкой сообщения. Вашу статью бот читать не намерен, у него другая задача. Человек же, как правило, проводит на странице не менее 10 секунд перед тем, как отправить комментарий. На этом поведенческом факторе основана еще одна клиент/серверная ловушка. На клиенте, при отрисовке формы фиксируется время захода пользователя на страницу, а перед отправкой комментария рассчитывается время, которое пользователь провел на странице. Данное значение сохраняется в одном из скрытых полей формы. Комментарии, которые содержат значение ожидания меньшее, чем мы установили в настройках - должны быть отсечены. Так, задавая в настройках TheComments обязательное время ожидания перед отправкой, мы можем обеспечить еще одну простейшую линию спамообороны.
  3. Механические ловушки. Даже если бот поддерживает JS, то вряд ли он откажет себе в удовольствии заполнить в форме максимум доступных полей, или полей, которые носят широко-распространенные названия для форм комментирования (comment, commentBody и т.д.). Добавив в форму несколько дополнительных полей, скрытых от глаз пользователя (но не бота) через CSS , мы можем на стороне сервера легко отсечь часть бесполезных комментариев.
  4. Антиспам сервисы. Службы Akismet и YandexCleanWeb предоставляют возможность определять является ли данный комментарий спамом. TheComments использует обе службы для более достоверного определния типа входящего комментария. Сразу после создания комментария создается background задача, которая отправляет комментарий на проверку и в зависимости от результата проверки может автоматически пометить комментарий как спам и перевести его в состояние "deleted".

Наличие пред-модерации для комментариев "гостей"

Как бы ни были хороши подходы защиты от спама, они никогда не смогут обеспечить 100% результата. Потому мы не можем обойтись без человеческого участия.

Я считаю, что хорошей стратегией работы с комментариями гостей является следующий подход:

  1. При создании комментария он отмечается как "draft", т.е. как комментарий требующий модерации
  2. Комментарий получает уникальный для данного браузера идентификатор (view_token) и этот view_token сохраняется в cookies браузера
  3. Пользователь, оставивший комментарий в данном браузере, сразу после создания комментария может его видеть. Видимость данного комментария легко определяется в момент отрисовки дерева комментариев, путем сопоставления значения из cookies и значения view_token данного комментария.

Таким образом, комментарий гостя (который имеет статус "draft"), виден только в браузере комментатора, а в других браузерах он заменен на плашку с надписью "Ожидает модерации". И только после модерации, получив статус "published" комментарий могут видеть все.

Данный подход с одной стороны позволяет защитить систему от "плохих" комментариев (реклама, флуд, мат), а с другой стороны обеспечивает лояльное отношение комментатора, т.к. он сразу видит результат своих действий.

Быстрая отрисовка дерева комментариев без кеширования

Описанная выше стратегия работы с анонимными комментариями подразумевает, что процесс отрисовки дерева комментариев будет динамическим, т.е. дерево комментариев невозможно (или весьма трудно) закешировать, т.к. в момент отрисовки необходимо проверять довольно много условий отображения каждого конкретного комментария.

Те, кто сталкивался с процессом отрисовки дерева комментариев (или любых других деревьев), могут заметить, что данный процесс может оказаться довольно ресурсоемким, т.к. выборка дочерних элементов дерева для каждого узла является рекурсивной задачей, и временные затраты на отрисовку дерева очень быстро растут с увелечением количества элементов дерева и его глубины.

Эту проблему отрисовки деревьев часто решают именно кешированием. Но для нашего случая такой подход оказывается практически не применим.

Кроме того, для отрисовки узлов дерева совершенно не подходит использование паршелов (partials), которые чрезвычайно медленно выполняют свою задачу.

Ввиду всего этого в TheComments мне приходится использовать другое свое open source решение TheSortableTree. TheSortableTree - в основе своей это хелпер для быстрой отрисовки деревьев, использующих parent_id в качестве основного средства хранения дерева в БД.

TheSortableTree позволяет мне очень быстро рисовать деревья любого размера и любой глубины за приемлемое время. Ориентировочные цифры отрисовки - от 2000 элементов в секунду. Этого более чем достаточно, что бы покрыть любые требования по системе комментирования практически любого проекта.

В TheComments отрисовка даже очень большого дерева комментариев производится настолько быстро, что бы вы могли не опасаться о заметном снижении производительности при генерирования страницы.

Добавление коммантариев на страницу без перезагрузки страницы

Конечно же, всегда приятно видеть на странице незамедлительную реакцию на свои действия. Как уже было отмечено выше, с точки зрения простейшей спамообороны, AJAX поведение системы комментирования весьма выгодно, но кроме того оно выгодно и с точки зрения взаимодействия пользователя и сайта.

В TheComments добавление комментариев на страницу произодится через AJAX.

Интеграция с антиспам сервисами

В момент работы над TheComments я нашел 2 гема для интеграции с антиспам системами - Viking (сервис Akisment) и YandexCleanweb (гем от Evrone обеспечивающий работы с соответствующим сервисом от Yandex). Гем Viking так же поддерживал сервис Defensio, но, кажется, этот сервис прекратил свое существование и мне пришлось перепаковать гем Viking, убрав из него код, который мне был не нужен, так появился форк TheViking.

На данный момент TheComments поддерживает интеграцию с антиспам сервисами Akisment и YandexCleanweb. Проверка на спам может проходить синхронно и асинхронно (настоятельно рекомендуется). Для формирования background задач сейчас используется ActiveJob, а следовательно на входе вы можете использовать TheComments практически с любым решением для BG задач: DelayedJob, SideKiq, Rescue и т.д.

Готовность к внешним процессорам контента

Мне трудно представить систему комментирования в которой не требуется некоторый процессинг входящих данных. Например, замена символьных сочетаний ;) на соответствующие самйлы, вероятно, самый распространенный процессинг входящих данных в любой системе UGC направленности. Автоматическое оформление ссылок из URL так же никто не отменял.

Мое решение для данной задачи такое. Модель Comment в TheComments содержит 2 поля для пользовательского контента - raw_content и content. В поле raw_content, как не трудно догадаться, попадают сырые данные от пользователя, а в поле content попадают обработанные на сервере данные, которые проходят через before_save: :prepare_content. Следовательно, данные из поля content следует выводить на коментируемой странице.

Какой процессинг организовать внтури метода prepare_content и как будет выглядить функция foo self.content = foo(self.raw_conetnt) - решать только вам.

TheComments поддерживает интеграцию с любым набором процессоров входящего контента. Вы можете легко определить необходимый процессинг данных, просто переопределив метод prepare_content в модели Comment в вашем приложении.

Так же вы в любой момент имеете доступ к исходному тексту комментария, а следовательно в любой момент можно изменить набор процессоров и перегенерировать конечный результат, отображаемый на страницу.

Ограничения

  1. Ruby 2+ синтаксис
  2. Rails 4.2
  3. StateMachine
  4. ActsAsNestedSet + ActiveRecord + MySQL/PostgreSQL
  5. Наличие User модели