⚠️ Обращайте внимание на даты.
Этот блог больше не ведётся с 17 января 2023, и на тот момент с написания этой страницы (09.01.2018) прошло 5 лет.
Помните деревья навыков? Идея потихоньку развивается, но к сожалению, всё ещё остаётся идеей без реализации. Признаюсь, в немалой степени из-за того, что я просто не нахожу времени написать даже минимально пригодный к использованию пример. Я изначально исходил из необходимости графического представления тем для изучения, своеобразной карты, roadmap. Рисовал возможные интерфейсы для использования этого дела, но всё казалось каким-то либо неконтролируемым, либо громоздким и непонятным. Но потом я обнаружил крайне неожиданное для себя сходство с уже существующим программным обеспечением, давшее довольно богатый источник ценных мыслей.
Ещё раз: что это такое?
Задумывалось это, как помощник в изучении технологий. Нечто, что подскажет, когда осваиваешь нечто новое, что нужно предварительно освоить. Потому что ошибки в последовательности изучения встречаются удивительно часто. Частенько совершал сам, частенько наблюдаю у других.
Первая версия идеи — глобальный граф навыков, разные области которого поддерживаются разбирающимися в ней людьми (и распределённый по разным серверам, этим людям подконтрольным). Пользователи же этого графа отмечали бы себе несколько вершин, до которых хотят добраться, и шли по связям вперёд, узел за узлом, пока цель не будет достигнута.
Каждый навык представляется лишь своим описанием.
Никаких контрольно-измерительных материалов (тестов и подобного) навык содержать не будет (кроме разве что совсем мелких). Никто не мешает их реализовать как расширение системы, но я не вижу в этом необходимости, поскольку это средство для самоконтроля. Если пользователь не может быть честным с самим собой и ему нужен будет живой контроль со стороны, инструменты самоорганизации ему не помогут.
Включать ли в них непосредственно учебные материалы — вопрос открытый. Для начала предполагалось избегать этого, поскольку это лишние усилия. Нужно сосредоточиться на выявлении связей между навыками и пользоваться ссылками на уже существующие учебные материалы, если они существуют. Но других аргументов найдено не было.
По мере обдумывания системы возникали всё новые идеи:
- Каждому навыку можно сопоставить численный показатель сложности, зависящий от глубины погружения в граф навыков. Сумма этих показателей по всем изученным навыкам даст некое число, грубо соответствующее количеству и сложности освоенного. Некоторым по привычке к играм удобнее оценивать свои показатели в числах. Избавиться от этой привычки непросто, но её можно эксплуатировать.
- К статье или книге можно прикладывать требования к читателю. Читатель может ознакомиться, насколько он готов к материалу, перед его прочтением.
- На сайтах вакансий обычно есть плоская система меток. Замена меток на навыки в подобной системе может помочь составить более детальную картину о кандидате и о вакансии, а также автоматически считать, насколько сильно кандидат не подходит (см. п. 1). При условии, конечно, что кандидат не врёт.
:)
Об этом чуть далее. Нужны сохранение/загрузка списка освоенных навыков в файл/из файла. - Необязательно использовать систему для самообучения, можно использовать и для традиционного, когда учитель и студент различны. В клиентском ПО нужно предусмотреть профили пользователей, чтобы можно было вести учёт не только себя, но и других.
- Можно смотреть, куда можно двигаться дальше с имеющимся багажом знаний, приложив минимум усилий. Быть может, для перехода на технологию поинтереснее почти всё необходимое уже изучено?
- Можно сравнивать свой подграф с подграфами друзей. Это случайная мысль. Звучит как типичный лозунг приложения для соцсети, буквально сияющего своей вопиющей бесполезностью, вот только на сей раз натянутый на теоретически полезный инструмент.
Кое-какие другие идеи будут упомянуты далее.
Чего там сложного?
В своих изысканиях вокруг всей этой затеи я стараюсь следовать Unix way: каждая деталь этого механизма должна делать что-то одно и делать это хорошо. С той целью, чтобы детали можно было использовать повторно. Но этот механизм довольно разнообразен и потенциально может решать множество задач. Поэтому его стоит разбить на отдельные детали и реализовывать эти детали по отдельности.
Первая деталь, она же главная, и основа для всего прикладного ПО под систему — данные о навыках. Их структура, формат, политика внесения изменений и дублирования.
“Карта” будет сложной!
Первая модель предполагала только прямую зависимость навыков друг от друга. У каждого конкретного навыка должен был быть конкретный набор других навыков, которые нужно освоить до этого. Я сразу подозревал, что этого не хватит. Но подозрений мало. Нужны факты.
Я пошёл копаться в архивах и вспомнил, как изучал SQL. Я подошёл к нему случайно и с довольно неожиданной стороны: я наблюдал за запросами, которые генерирует ActiveRecord, адаптер для баз данных в Ruby on Rails, смотрел как он реагирует на добавление тех или иных условий или модификаторов. Конечно, зайти сколько-нибудь далеко таким наблюдением не получится. Но достаточно очевидно, что для изучения основ SQL вам вовсе необязательно лезть в ActiveRecord, да и в ORM вообще! То, что я полез, это скорее мой неосознанный (но сработавший) выбор.
Получается, что нужен ещё один вид связи, допускающий выбор. И пока нет уверенности, что это последнее усложнение данных. Скажем, ещё где-то неподалёку вьётся мысль о “A легче понять, зная Б”.
Навыки будут уточняться!
Не стоит всерьёз рассчитывать, что авторы определений всё правильно опишут с первого же раза. Они будут вынуждены вносить изменения, на которые нужно обратить внимание пользователей. Более того, наличие хорошо отработанной возможности обновления навыка позволит создавать условные “всеобъемлющие” темы для освоения, своеобразные дайджесты, с помощью которых можно оставаться “в теме” быстро меняющейся среды.
Но надо решить, как пользовательское ПО должно реагировать на изменения, внесённые на сервере. Что делать с тем, что пользователь уже освоил навык, который изменился? Что делать с теми навыками, что зависят от него?
Людям этим пользоваться!
Визуализация графа как основной экран взаимодействия с системой выглядит всё менее привлекательной идеей. Он хорош ровно для одной цели: обзора “с большой высоты”, с которой даже отдельные узлы обычно не разглядеть, разве что группы. Чтобы грубо ознакомиться с общим объёмом и структурой осваиваемого, этого хватит. Но вряд ли на что-то большее. И для объёма есть лучшая метрика — число вершин в графе зависимостей; а структура и так будет изучаться по мере обхода графа пользователем.
Для практически всех остальных задуманных целей интерфейс можно сделать куда более простым.
Языки?
Назрел ещё один вопрос, пока не обдумывал: как можно в такой системе организовать переводы на другие языки (на русский, к примеру)? Это айтишников на первых порах можно всех направить на английскую версию, под предлогом того, что английский — lingua franca индустрии и его де-факто необходимо знать. Но это даже для ИТ это будет проблемой, что уж говорить о других областях.
Лицензии?
Что уж тут поделаешь, есть такое понятие, как “интеллектуальная собственность”. Оно может ограничивать действия, которое для системы допустимо совершать. В частности, свободное зеркалирование навыков между серверами (чтобы спасти от исчезновения в случае смерти исходного сервера, к примеру) под вопросом. Можно ли обязать всех использовать достаточно свободную лицензию?
А теперь внезапная смена темы.
Поговорим о Linux?
Ещё когда я начинал с Ubuntu, мне страшно понравилась идея устанавливать всё и вся одной командой sudo apt-get install софтина
. Система знала огромное количество проверенного софта (software, ПО, программного обеспечения), умела скачивать заведомо проверенные файлы для установки и устанавливать их в основном без моего участия. Одна команда, требующая знать обычно только название софтины, одно нажатие Y, и через некоторое время в меню программ просто появляется новый значок с тем, что я просил. Это казалось почти волшебством после Windows, где для большинства ПО приходится лезть на официальный сайт за установщиком (а иногда ещё и гуглить его), скачивать установщик, запускать и прощёлкивать “далее-далее-далее-готово” (не забыв поснимать ненужные галочки, а то можно установить и кое-что ещё).
Так я познакомился с понятием “менеджер пакетов”. И начал узнавать, как это работает.
Установка большей части ПО устанавливает не только само ПО, но и ряд других вещей, необходимых для него. “Зависимости”, как я узнал потом. Система этого не замалчивала, она давала полный список изменений для каждой команды, просто я в него не вчитывался. Потом я вспомнил, что нечто похожее иногда делается и в Windows, некоторое ПО хочет предварительно установленные разные redistributable-пакеты вроде Visual C++, XNA, OpenAL. То, что менеджер пакетов обычно самостоятельно разруливает и это, меня порадовало.
“Зависимость” оказалась не единственным возможным отношением между двумя пакетами. Бывают ещё “рекомендация” (скорее всего, вам надо и это), “предложение” (вам может быть полезно и это) и “предоставление” (предоставляет это). Последнее особенно интересно: с помощью “предоставления” можно указать, что разные пакеты нужны для одних и тех же целей; иначе говоря, два разных пакета являются разными реализациями одного и того же. А другое ПО, которому совершенно не важна конкретная реализация, а нужна лишь какая-нибудь, могут зависеть не от другого конкретного ПО, а от такого “предоставления”. (Что является прямым решением одной из проблем выше!)
Ещё стоит отметить, что абсолютно все менеджеры пакетов, с которыми я сталкивался на практике, предоставляли возможность добавления сторонних репозиториев с пакетами. Доступных изначально всё-таки не всегда хватает. С местных зеркал, например, можно загружать ПО быстрее. А где-то можно найти ПО, которого (больше) нет (или не было вовсе) в изначальных репозиториях.
Сходство
Вы же уже заметили? Если вообразить гипотетический менеджер пакетов, в котором пакетами являются навыки, изучение очередного навыка сродни установке пакета: нужно вычислить граф зависимостей (запрашивая выбор пользователя при необходимости), а далее “установить его” в порядке зависимости.
Если делать топологическую сортировку сразу и выдавать пользователю линейный список, то получится своеобразный генератор планов обучения, от линейности которых я бежал с самого начала. Их, тем не менее, можно использовать для “общего обзора”. Но при освоении можно просто на каждом шаге демонстрировать, к освоению чего пользователь готов в данный момент. А порядок пусть выбирает сам пользователь. Например, связанные темы разумно осваивать близко друг к другу, так смена контекста не столь огромна. А кто-то напротив, мог устать от определённого предмета и хотел бы на время сменить направление. Каждый сможет выбрать по своему вкусу.
Можно пойти дальше и перенести в систему и другие концепции менеджера пакетов.
Версии
Если подумать, это самый простой способ внести изменения в уже существующее определение навыка. Просто опубликовать новый, большей версии. А природа таких определений позволяет без особенных затруднений иметь несколько “установленных” версий одновременно.
“Обновление навыка” (в системе, в какой-то мере и в реальности) будет заключаться просто в установке новой версии. Причём малое ресурсопотребление каждого пакета и отсутствие возможности конфликта позволяет иметь сколько угодно много версий любого пакета установленными одновременно практически без последствий. Ведь, к счастью, в 2017 году о нескольких лишних килобайтах постоянной памяти можно не беспокоиться.
Репозитории
Я всё старался избегать излишней централизации системы, чтобы в случае, если она окажется полезна, её могли без проблем разместить у себя другие. Но если проследить за децентрализованными сервисами, какой-то фактический центр у них всё равно образуется:
- Личная электронная почта осела на небольшое множество крупных провайдеров, за редким исключением.
- У Tox централизованно выдают адреса.
- GitHub стал де-факто центром Git, иногда попираемым Bitbucket и GitLab.
- Языковые менеджеры пакетов обычно опираются на здоровенный центральный репозиторий:
- Leiningen для Clojure на
clojars.org
- RubyGems на
rubygems.org
- NPM на
npmjs.com
- Leiningen для Clojure на
- Системные менеджеры пакетов обычно опираются на репозитории дистрибутива.
Почему это происходит? Трудно сказать. Скорее всего, потому что это технически проще. Что отдельные репозитории мало кому нужны, и поддерживать собственные сложнее, чем использовать сторонние. Особенно тем, кто не особенно технически подкован, а я рассчитываю однажды привлечь и таких пользователей в систему, чтобы описывать области, которые мне не знакомы. Возможно даже за пределами ИТ! Но заложить сторонние источники полезно, это здорово повысит “выживаемость” системы и может теоретически расширить её применимость. Могут, скажем, быть графы, доступ к которым ограничен. Об обучении каким-нибудь внутренним для компании навыкам.
Но если в пределах репозитория мы ещё можем рассчитывать на отсутствие конфликтов между пакетами (когда данные в одном хранилище, обычно можно следить за конфликтностью каждого добавляемого), то когда репозиториев станет много — вряд ли. Если продолжать держаться идеи управления навыками как пакетами, можно будет встретить те же проблемы, что и там: циклы зависимостей, конфликты имён.
Природа рассматриваемых пакетов даёт заметно больше свободы. Например, можно свободно ставить много версий одного и того же. Поэтому обновления до более новых версий не должны обернуться проблемами.
Циклы зависимостей можно худо-бедно решать, показывая их целиком и предлагая осваивать всё перечисленное сразу. На практике длина цикла вряд ли превысит 2-3 узла, а объёма материала в них вряд ли наберётся даже на маленькую книжку. Их возникновение уже нездоровая ситуация, да, но в мире пакетов тоже. И тем не менее, бывает. Стоит, кстати, поинтересоваться, как именно они возникают на практике, без злого умысла.
А вот конфликт имён, когда два разных автора опубликовали навыки с одинаковыми названиями, но разными смыслами — потенциальная проблема.
План действий?
Первым узлом этой системы, скорее всего, станет потенциально здоровенный репозиторий навыков от самых разных людей. Клиенты по умолчанию настроить на него, но допускать как добавление других, так и удаление этого.
Самая глупая первая версия может быть просто набором статических файлов (в который делать pull request’ы для добавления и обновления пакетов) со скриптиком для проверки и скриптиком для генерации индекса. Впоследствии можно будет заменить эту реализацию на более продвинутую, которая будет самостоятельно проверять корректность публикуемого, генерировать списки для конечных пользователей и предоставлять более удобный интерфейс для редактирования.
Когда будут данные, можно приниматься за клиенты.
Отмечу, что для менеджеров пакетов визуализация связей между пакетами применяется очень редко. Похоже, что для большинства сценариев будет достаточно просто обновления репозитория, текстового поиска по пакетам и ведения по процессу установки выбранного пакета (как следствие, и просмотр содержимого пакетов).
Интерфейс у этого, по первым прикидкам, может быть достаточно простым. В конце концов, действий там нужно выполнять не так уж много. Скорее всего, можно будет без потерь затолкать его даже на мобильные устройства вроде смартфонов.
Почитать:
- Debian: отношения между пакетами — документация по отношениям между пакетами системы
dpkg
, используемой в Debian (изначально), Ubuntu, Linux Mint и ещё в ряде мест. Конечно, там отношения устроены заметно сложнее, чем нужно здесь, но там и пакеты связаны куда большим числом ограничений: они могут пользоваться общими ресурсами без возможности “делиться доступом”. В описываемой системе я пока не могу представить, какие могут быть конфликты, например. - Топологическая сортировка — то, что превращает ациклический ориентированный граф в список. Список удобно представить пользователю, но у него, как я уже писал в ридми Skillforest, есть недостаток: он строже, чем нужно. Навыки упорядочены лишь частично, но мы пытаемся упорно затолкать их в линейный список в разнообразных курсах и книгах.
Послесловие
Почти весь текст выше на самом деле написан довольно давно (и лишь несущественно правился позднее), а в указанную дату публикации написан лишь этот раздел. С тех пор я читнул материалов по Semantic Web и вот что я по этому поводу думаю…
RDF видится мне естественным выбором для представления графа навыков/концепций.
- Он для графов. В нём все данные представляются в роли рёбер и вершин графа. В смысле, вообще все. Даже данные о каждой сущности кодируются рёбрами из сущности в литералы данных.
- Он изначально задуман для распределения данных общей связываемой структуры по независимым узлам.
- Он давно существует. Вокруг него сформировалась здоровенная экосистема. Стандартизированный язык запросов SPARQL для запросов к данным. Масса мощных инструментов для разработки, вроде Protege. Множество библиотек для валидации, хранения и других полезных действий. Наверняка и лучшие практики сложились, у которых можно проследить историю и заранее избежать ошибок, в ответ на которые они возникли.
- Данные в RDF можно представить несколькими способами. Есть выбор языков. Теоретически можно даже совмещать. Наверное.
- Уже есть сложившиеся практики связывания контента в Сети с RDF-сущностями.
Так что ближайший этап: подготовить спецификацию для формата в форме RDFS или даже OWL-онтологии. Выбор пока открытый.