Помимо основной работы, я занимаюсь своим небольшим побочным проектом, в основном на выходных. И есть особенность что отличает такие проекты – ты можешь уделять задачам столько времени, сколько посчитаешь нужным. На работе это не так.
В рабочее время у тебя есть дедлайн, нужно предоставить фичу реализованной в какой-то срок. И это даже хорошо, это организует. Но это плохо, если фича которую реализуешь задаёт архитектуру для проекта, и в последствии будет неоднократно изменяться и расширяться. Архитектуру лучше сразу делать хорошей, ибо рефакторинг будет очень болезненный.
Одна из составных частей моего проекта – чтение и распознавание текста с внешних ресурсов (сайтов, проще говоря).
Переписав три раза код, наконец получил то что мне нравится. В этом посте вкратце расскажу как я это вижу.
Задача
Итак, мои требования таковы:
-
Чтение с внешних ресурсов. Оно может происходить по-разному, в разных форматах и протоколах. Может оказаться так, что данные будут предоставляться после авторизации, через протокол
https
или вообще в виде локально доступного файла. (Это может быть .xls к примеру) Надо предусмотреть возможность добавления новых источников. -
Сайты с которых происходит считывание могут иметь самую разную структуру. Иногда информация о конкретном предмете (товар, в моём случае) может быть размазана по нескольким страницам.
-
Удобное масштабирование. Число источников может вырасти очень стремительно. Нужно уметь раскидывать задачи и данные на несколько серверов.
-
Обработка ошибок. Ресурс источник может внезапно поменять структуру DOM, нужно адекватно на это реагировать. Кроме того, мне не хотелось бы, чтобы весь процесс синхронизации валился из-за одной страницы, на которой формат оказался немного другим от ожидаемого.
-
Возможность производить обработку на разных платформах. К примеру, я так и не нашёл подходящего гема для работы с русской морфологией, а вот для python есть подходящий пакет. Хочу иметь возможность загрузить страницу на Ruby, а разбить и распознать – на Python.
-
Версионирование загруженных данных. На тот случай, что если в распознающем коде закралась ошибка – быстро и безболезненно откатить на старую версию.
Идея
Для того чтобы удовлетворить 2-й и 3-й пункт необходимо загрузку разбить на отдельные независимые части. Напрашивается создание нескольких воркеров, каждый для какого-то конкретного куска, например: