Блог. Склад текстов. И прочее городу и миру...
Рубрикатор
Последние записи
Прогулка 11 мая

Что мы знаем о лосе? Ничего, и то не все.
Открыл тут на днях свой наблюдательский сезон, более-менее полноценно прогулявшись по лесу. Более-менее — потому что нагулял всего лишь километров семь, вместо десяти-пятнадцати. Да и снял не так уж много, на самом деле лес еще не слишком-то и проснулся.
Звери
Самое примечательное наблюдение, конечно, то, которое я вынес на заглавную картинку. Появление этого семейства метрах в сорока от меня было довольно-таки неожиданным… Вообще, я в этот момент стоял и размышлял, что как-то скучно гуляю — цвести почти ничего не начало, птицы всё знакомые попадаются, насекомые сидят по норам, поскольку ночью был минус, и еще толком не потеплело… Полагаю, что так близко они подошли как раз потому, что я стоял и размышлял, а не шел, хрустя листьями и хворостом под ногами, плюс, видимо, с направлением ветра повезло.
В общем, гештальт можно считать закрытым — раньше мне не удавалось снять в лесу лосей, только следы их жизнедеятельности. Конечно, фоточка так себе из-за размытой веточки на переднем плане, да и вообще хотелось бы снять самца в период полной рогатости… А еще я дичайше завалил все горизонты, что легко правится, но портит детализацию… Но это уже не так зудит. Все-таки именно фотонаблюдение получилось вполне полноценное.
Tg: апрель 2026
Затянул я немного, но таки выкладываю очередную подборку. См. также посты за январь, за февраль и за март.
Не знаю, заметил ли кто-то, кроме меня, но с апреля начались некоторые сбои в постинге. После очередного обновления iNaturalist стали возникать ошибки доступа к фотографиям. Я пока не разобрался, из-за чего это происходит, руки не дошли…
Биоразнообразие Свердловской области в TG
Для начала пусть будет свежая екатеринбургская гадюка.
Tg: март 2026
Что ж, пришло время для очередной подборки. См. также посты за январь и за февраль.
Биоразнообразие Свердловской области в TG
Очень хотелось выбрать наблюдение одновременно свежее и весеннее, но увы. Пусть символизирует уходящую зиму…
iNatGet v0.9.2 и его практическое применение

Версия 0.9.0.18
Итак, финальные отчеты по своим районным проектам на iNaturalist я сформировал, пользуясь уже новой версией inat-get. Сразу выяснилось, что версия 0.9.01, несмотря на то, что я старался для базовых вещей писать тесты, никуда не годится. Впрочем, это нормально на данном этапе (ранней беты). В результате, отлаживая на реальных данных, я дошел до версии 0.9.0.18 — уже вполне рабочей.
Полученными отчетами я вполне доволен. Примеры:
В подвале скриптов можно разглядеть мелким шрифтом, что сгенерированы они версией 0.9.0.15, а не .18. Это потому, что самые последние исправления в ветке 0.9.0 касались исключительно оптимизаций, и на результат не влияли.
Средств для удобного формирования отчетов все еще нет, пишу текстом в файлы, так что скрипты отчетов получились довольно развесистые. Я их поместил в отдельный репозиторий ing-sv-districts — можно полюбоваться, хотя структура там сильно так себе…
Версия 0.9.2
А здесь добавлена довольно мелкая фича — поддержка ERB, как в качестве шаблонов, вызываемых из пользовательских скриптов, так и в качестве пользовательских скриптов как таковых. Не то, чтобы это было существенное улучшение, но может, кому и пригодится.
Переводить районные скрипты на этот механизм я не стал, поскольку это ничего нового не дает. Впрочем, возможно, имело бы смысл для дополнительной отладки…
Промежуточные итоги
В общем и целом, текущая архитектура вполне годная, от главных тормозов версии 0.8.x удалось избавиться, основной упор по времени
идет в скорость интернета, причем обновления, как и задумано, берутся инкрементно — через параметр updated_since, что резко ускоряет
повторные запросы.
Но работа с локальной БД оставляет желать лучшего, группировочные запросы промахиваются мимо индексов, причем даже группировки по пользователям, которые самые простые по своему внутреннему устройству… Что ж, значит следующая итерация — 0.9.4, запланированная для решения именно этих проблем — запланирована не зря. Заметные тормоза, впрочем, видны только на генерации итоговой сводки — она сейчас занимает у меня пару часов, что печально, конечно, но по сравнению с 0.8.x — просто прекрасный результат.
Что порадовало — уже отлаженный на SQLite вариант на PostgreSQL заработал сразу — спасибо Sequel. Скорость работы на разных СУБД практически не отличается. Нужны, конечно, аккуратные замеры, но в целом разницу можно игнорировать.
Что дальше?
Общий роадмап имеется на вики проекта — Roadmap. Кстати, я тут «навайбкодил» генератор роадмапов из Issues и Milestones — action-is-roadmap — довольно прикольно получилось, люблю наглядность. Даты майлстоунов проставлены от фонаря — чисто для упорядочения, как обещания их воспринимать точно не стоит.
А если не вдаваться в детали, то ключевые задачи такие:
-
Оптимизация запросов.
Не знаю, насколько удастся их ускорить, но желательно выжать все возможное.
-
Доделать кэширование.
-
Удобный конструктор отчетов.
Чтобы не нужно было заморачиваться на оформление в пользовательских скриптах. Писать их, думая только о логике, причем в терминах множеств и выборок.
-
Доделать работу с прочими данными.
Пока реализованы далеко не все возможные запросы и фильтры, есть куда развиваться. И здесь нужно будет не забывать об оптимальности запросов.
Наверное, по ходу дела будут появляться новые задачи, и уж точно — находиться новые баги…
iNatGet v0.9.0

Что ж… Вот я и зарелизил 🌿 iNatGet v0.9. Через два с небольшим года после v0.8, и через примерно год после последней версии — v0.8.0.16. Обо всех этих минорных корректирующих версиях я ничего не писал, главным образом потому, что там мучительно правились мелкие баги, а нормальная работа требовала глобального рефакторинга (т.е. переписать заново с нуля), на который никак не находилось времени.
Однако все это время я не прекращал пользоваться своей программой, регулярно формируя отчеты для своих проектов1 на iNaturalist. Таким образом я постепенно уточнял свое понимание того, как это в принципе должно работать и где у меня провалы в архитектуре. Плюс развитие нейросетей… В проекте ни строчки сгенерированного кода, но для консультаций и ревью я пользовался различными LLM очень активно2, что и позволило сравнительно быстро написать новую, полностью переделанную, версию.
Если версии v0.8.x я характеризовал как альфа-версии, то ветка v0.9.x пусть будет бетой, но пока — очень ранней бетой…
Коротко о том, что это за проект вообще, можно прочитать в README-ru.md в репозитории.
-
См. журналы проекта «Биоразнообразие районов Свердловской области» и его дочерних. ↩
-
О своем отношении и подходе к использованию нейросетей я подробно писал в посте: «Заметки об LLM и нейросетях вообще». ↩
Tg: февраль 2026
Что ж, продолжу делать месячный дайджест того, что принесли мои tg-каналы с популярными наблюдениями. Здесь — свежепрошедший февраль. См. также пост за январь.
Биоразнообразие Свердловской области в TG
Долго думал, в итоге решил взять вот такого каменского февральского орлана-белохвоста. Солидная птица. И не так уж часто его наблюдают в принципе, особенно у нас в области.
Автодокументирование моделей Sequel

Набросал предварительную версию YARD-плагина для автодокументирования Sequel-моделей — yard-is-sequel.
Существующий yard-sequel с современными версиями YARD/Ruby/Sequel не работает.
Мой вариант, конечно, не может пока похвастаться полнофункциональностью (версия 0.8.0 — это ранняя альфа), но кое-что самое важное умеет:
-
Генерирует список ассоциаций:
many_to_many,many_to_oneиone_to_manyс корректными ссылками на типы. -
Генерирует список полей. Также с типами, но тут есть нюансы…
-
Маппинг типов полей требует доработки. Кроме того, типы, не поддерживаемые SQLite, скорее всего, не будут нормально обрабатываться в принципе.
Поля берутся из
Database#schemaна созданной in-memory SQLite базе данных. Было бы хорошо, безусловно, брать их непосредственно из миграций, но пока непонятно, как это сделать. -
Путь к миграциям следует указать через переменную окружения.
-
Чего нужно доделать?
-
Отрефакторить и упростить обработку ассоциаций.
-
Расширить обработку типов в полях и сделать ее менее хрупкой. Сейчас есть подозрение, что минорная смена версии Sequel может всё поломать…
-
Добавить возможность брать схему из отдельно сохраненного файла (в формате JSON, скорее всего).
Но надо понимать, что я буду что-то править и дорабатывать только постольку, поскольку мне это самому нужно… Однако, если кто-то предложит свои пулл-реквесты, или хотя бы подробные баг-репорты, отнесусь со вниманием.
Что там в Tg?
Решил написать, чего интересного (с моей точки зрения) принесли скрипты постинга популярных наблюдений в телеграм за минувший январь.
Биоразнообразие Свердловской области в TG
Залетный чернозобый дрозд в Екатеринбурге. Я бы не стал исключать, что со временем их станет больше — все как-то стали забывать, но вообще-то привычных дроздов-рябинников на Среднем Урале еще двадцать лет назад не было…
Об инвалидацию кэша

Как известно, в программировании есть только две реально сложные задачи: именование переменных и инвалидация кэша1. С первой мы сделать ничего не можем, со второй, конечно, тоже, но что-то делать приходится…
И вот в процессе большого рефакторинга inat-get я в очередной раз задумался. Суть тут вот в чем: данные, которые требуется получать из API iNaturalist — очень большие (зависит от целей, конечно, но они могут быть очень большими), и логично их закэшировать в локальной базе данных. Естественно, кэшированные данные нужно обновлять.
Есть прекрасный параметр updated_since в запросах к API, т.е. мы храним у себя информацию о сделанных запросах, и когда
нам нужно получить новые данные по тем же условиям, указываем дату/время предыдущего запроса в этом параметре. Но полностью
проблему это не решает: updated_since не отменяет (и не должен отменять) все остальные параметры запроса, т.е. те
наблюдения, которые выпали из запроса, в выборку не попадут. И останутся в локальной БД в старом состоянии.
Ну, то есть, выбрали мы, например, данные по проекту, который фильтрует наблюдения с quality_grade=research, а потом
пришел добрый человек и заметил, что в наблюдении культурное растение. Наблюдение выпадает из проекта, но мы об этом
не можем узнать через обновление…
Какие есть пути решения? Вижу несколько вариантов, ни один из которых меня не устраивает полностью…
-
Автор этой фразы, предположительно, Фил Карлтон (Phil Karlton), ведущий инженер компании Netscape. ↩
Натурадыбр – 2025

Что ж, год подходит к концу, я продолжаю снимать птичек на кормушке, но не думаю, что туда заявится кто-то новый и неожиданный. Так что можно подвести итоги наблюдательского года. Конечно, iNaturalist предлагает свою инфографику, но это все же сухая цифра, хоть и приятно оформленная.
Здесь я попробую изложить итоги года более субъективно и оценочно.
Количественно, как можно видеть, в этом году я снимал меньше, чем в прошлом и позапрошлом. Так получилось, в основном, потому, что в июле, августе и начале сентября я учился на водительские права (сдал), и у меня резко перестало совпадать свободное время с подходящей погодой.
Хотелось бы сказать «зато качественно…», но судя по количеству новых видов (и видов вообще), качество наблюдений осталось примерно таким же. Разве что чисто технически оно выросло, о чем ниже.
Ну и еще про количество, чтобы потом не возвращаться: в мае перешагнул отметку в 5000 наблюдений на iNaturalist, а в сентябре — 6000. Сейчас у меня в профиле показывается 6069 наблюдений всего и 1111 видов. Правда, если брать только наблюдения исследовательского уровня, т.е. подтвержденные, получится 4748 и 836 видов соответственно, так что тысячником называться еще не смею. Ну да ладно, новые виды пока прибавляются, так что пара-тройка лет — и за тысячу перевалю.
Паттерн «Фасад» и гем для DSL

При написании inat-channel я столкнулся вот с какой проблемой: с одной стороны, более-менее сложные
действия должны быть декомпозированы, то есть разбиты на модули и отдельные методы в них; с другой — глубокая декомпозиция заставляет
писать длинные обращения к методам типа INatChannel::Telegram::send_observation, что неудобно, да и не эстетично. По хорошему вообще
нужно верхний уровень методов инклюдить и писать send_observation в основной программе, но если писать все как включаемые методы модулей,
то во-первых, они все из всех модулей попадут в финале в одно пространство имен, а во-вторых, туда же попадут и приватные методы.
Для подобных случаев и предназначен паттерн «Фасад» — мы создаем отдельный программный модуль — в данном случае это модуль же в терминах Ruby — который содержит только нужные извне методы, делегируя их в основной нормально декомпозированный код. И затем его спокойно инклюдим в коде основного скрипта.
Собственно, именно так я и сделал, определив модуль IC и заполняя его методами в тех же файлах, где они определены. Туда же отправились
некоторые методы, не нужные вовне, а используемые слабо логически связанными модулями — здесь речь скорее не о логике и отделении фасада,
а о сокращении (текстовом) кроссмодульных вызовов. Впрочем, по мере разрастания структуры вопрос, что считать внутренним, а что внешним,
становится не очень однозначным.
Подумав немного на эту тему, я решил вынести абстракцию в код и написал is-dsl — гем, упрощающий, а главное — структурирующий делегирование методов и констант фасаду. Подробнее — в README репозитория (есть русская версия), а также в yard-документации. Здесь коротко обозначу основные особенности:
-
Помимо основного модуля фасада формируется теневой модуль — для использования внутри библиотеки. Все, что попадает в основной, попадает и в теневой, обратное неверно. См.
shadow-методы. -
Можно делегировать как статически синглтон-методы классов и модулей, так и лениво методы произвольных синглтон-объектов, где сам объект создается или получается через вызов блока. См.
lazy-методы. Предполагается применение с методом классаinstanceв первую очередь.
Планов менять или добавлять что-то в основную функциональность нет, думаю когда-нибудь сделать плагин для YARD, чтобы делегирование методов правильно автоматически документировалось.
Продолжая повышать энтропию интернетов...
В порядке продолжения повышения энтропии, а также эксперимента ради, я недавно завел еще три канала в телеграм с наблюдениями из iNaturalist:
- Daily Flowers of the World
-
Наблюдения цветов — в запросе указаны
term_idиterm_value_id, чтобы в выборку попадали именно наблюдения с цветами, а не вообще все наблюдения цветковых растений. - Daily Birds of the World
-
Наблюдения птиц. Тут ничего специфического, просто каждый день разные птицы.
- Daily Butterflies of the World
-
Наблюдения бабочек — в запросе опять же указаны
term_idиterm_value_id, чтобы в выборку попадали только взрослые особи, т.е. собственно бабочки, а не гусеницы, куколки или яйца.
Показаны 12 записей из 331