Привет, Хабр! В своей первой статье про анализ вакансий C#/.Net разработчиков на рынке я выделила очень интересное замечание, которое определило тему сегодняшней статьи – «не количество навыков делает из мидла синьора, а образ его мышления». Построить граф связности компетенций для синьора это конечно хорошо, но к сожалению, на практике применить его достаточно сложно.

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

Результаты кластеризации по частоте встречаемости навыков
Результаты кластеризации по частоте встречаемости навыков

Имеющиеся проблемы

Для начала стоит понять, какие параметры мы имеем и что нам с этим делать. Мало того, что только 28% вакансий из моего датасета имеют разметку грейда от HR, так еще и корреляция числовых признаков достаточно низкая.

Матрица корреляции числовых признаков в датасете
Матрица корреляции числовых признаков в датасете

Стоит обратить внимание, что уровень ответственности, выделенный LLM, растет вместе с годами опыта. С одной стороны это достаточно очевидно, а с другой стороны ломает все исследование: пытаясь структурировать данные, мы получаем линейную зависимость ответственности от года опыта при нелинейном распределении навыков.

Демонстрация зависимостей между признаками
Демонстрация зависимостей между признаками

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

Попытка нечеткой кластеризации навыков
Попытка нечеткой кластеризации навыков

Новая система координат и повторная кластеризация

Технически, мы имеем вес каждого технического навыка для каждого года опыта, представленного в матрице компетенций, флаг наличия архитектурных навыков и уровень ответственности, выявленный LLM при анализе текста вакансии. Используя эти три параметра, мы можем определить новый параметр - Topological Seniority Index (TSI). Он позволит связать между собой все параметры по формуле:

TSI=WSP_t+(2*L_r )+(B_a*WSP_t)

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

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

Отношение значимости навыков в вакансии к их количеству
Отношение значимости навыков в вакансии к их количеству

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

Повторная кластеризация радует нас тремя вполне обособленными группами с достаточно приятным индексом силуэта в 0.4.

Результат кластеризации по числовым параметрам: ‘WSP’, ‘L_resp’, ‘B_arch’, ‘B_arch’*‘WSP’
Результат кластеризации по числовым параметрам: ‘WSP’, ‘L_resp’, ‘B_arch’, ‘B_arch’*‘WSP’

С одной стороны, замечательно, мы получили разметку, способную каждой вакансии присвоить «рыночный» грейд. Но будем ли мы способны классифицировать наши вакансии по данной разметке?

От кластеров к классификации. Граничные значения грейдов

Проверить стабильность и предсказуемость наших данных было решено с помощью Bagging с использованием kNN. Таким изощренным образом мы сможем сгладить «шум», мешающий классификации и попытаться повысить точность модели. И результаты превзошли все ожидания.

Результат классификации на тестовой выборке (датасет от января)
Результат классификации на тестовой выборке (датасет от января)

Крайне высокое значение Accuracy вызвано не переобучением, что было проверено на других, незнакомых модели, датасетах.

Результат классификации на датасете от начала апреля
Результат классификации на датасете от начала апреля

Но теперь наблюдается другая проблема: пороги перехода между грейдами плавают, в зависимости от выбранного датасета. На графиках, представленных ниже зеленая область - это TSI характерный для Junior, синяя область - для Middle, оранжевая - для Senior.

Распределение грейдов в датасете от января
Распределение грейдов в датасете от января
Распределение грейдов в датасете от начала апреля
Распределение грейдов в датасете от начала апреля
Распределение грейдов в датасете от середины апреля
Распределение грейдов в датасете от середины апреля

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

Выводы

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

Но все эти смелые заявления работают только при некоторых оговорках:

  • Динамика обучающей выборки: Индекс TSI не является константой. Это «снимок» рыночных ожиданий в конкретный момент времени, требующий регулярной перекалибровки порогов при изменении трендов индустрии.

  • Декларативность данных: Модель анализирует «wish list» работодателей, а не реальные компетенции сотрудников. Это оценка позиционирования грейда рынком, а не финальный вердикт (именно поэтому я провожу так же анализ исходного кода).

  • Доменная специфика: Текущие веса оптимизированы под экосистему C#/.NET. Перенос модели на другие языки (Python, Go) потребует адаптации «архитектурного множителя» под специфику их парадигм.

Поделитесь своим мнением: что вы думаете о таком подходе? Можно ли усмирить хаос и бардак в требованиях на рынке или это босс высшего уровня?

Комментарии (12)


  1. GameHipe
    21.04.2026 15:12

    Я сам не особо эксперт, но думаю могу добавить пару комментариев на этот счёт.

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


    1. Dozorova_Alyona Автор
      21.04.2026 15:12

      Вы правы, потерянное ограничение, которое стоит указывать всегда: мы никак не можем оценить soft skills. Но мы можем попытаться автоматизировать все остальное)


  1. OlegZH
    21.04.2026 15:12

    Постановка задачи отражает всеобщее представление о том, что "сеньор" — это здорово прокаченный "миддл".

     «не количество навыков делает из мидла синьора, а образ его мышления».

    С этим можно было бы вполне согласиться. Но что это значит? Это значит, что речь идёт о различии компетенций: у "миддла" и у "сеньора" разные области компетнции. Грубо говоря, у "миддла" область компетенции — это библиотеки, а у "сеньора" — архитектура. Это совершенно разные задачи! Вы (все) пытаетесь выстроить некую единую шкалу компететности, помещая на эту шкалу и "джуна", и "миддла", и "сеньора". А нужны просто специалисты под различные задачи. Младший программист — это ученик. Не следует ждать от него уже готовых навыков и умений. На на деле, мы видим, что на такие вакансии уже требуются готовые специалисты. Обыкновенные программисты — это те, кто, собственно, и разрабатывает для компании рабочий код. Младший программист не должен писать код для "прода". Он пишет код для самообучения. А, вот, старшему программисту нужно решать архитектурные задачи и по мере их решения предлагать собственные библиотеки, которые будут использоваться в разработке. Старшего программиста можно просто назначить. Просто кто-то обязательно должен заниматься архитектурными вопросами. Разработчикам ("милллам") некогда проводить исследования. Они работают в рамках жёсткой спецификации. Но кто-то должен сам создавать такие спецификации. И тут достаточно двух-трёх библиотек, чтобы взять какого-нибудь "миддла" и сделать "сеньором". Просто задачи разные. Трудно цифирьками измерить.


  1. OlegZH
    21.04.2026 15:12

    Текущие веса оптимизированы под экосистему C#/.NET.

    Если нужно оценивать именно уровень компетентности в рамках какого-либо языка программирования и/или технологии, то здесь нужно, прежде всего, выделить саму структуру знаний. Есть синтаксис языка, если его семантика, есть типовые задачи и типовые подходы к решению данных задач, есть типовые приложения и технологии их построения, основанные на определённых библиотеках. Но! если у нас есть описание этой структуры, то мы можем построить на базе этой структуры обучающий курс и любого специалиста подтянуть до "сеньора". Весь вопрос в том, что мы хотим: мы хотим что-то там измерить или получить готового специалиста?


    1. Dozorova_Alyona Автор
      21.04.2026 15:12

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


      1. xabrxaxabr
        21.04.2026 15:12

        Если бы ещо работодатель понимал, что он хочет, то тоды да…


      1. OlegZH
        21.04.2026 15:12

        Вы хотите измерить. А мне нужно освоить, овладеть. Мне нужен инструмент для успешного овладевания C#. Что бы иметь ясный курс и реально оценивать свой текущий уровень. Нужны какие-то задачи. Вот здесь мы изучаем язык. Вот здесь — рабочие инструменты. Вот тут — методологию создания приложений (определённого типа). А здесь — создаём законченные решения. И чтобы тебе в конце ещё и сертификат выдали, что ты всем этим действительно владеешь. (Вопрос, ещё и за какие деньги. Но сейчас вопрос о принципах.) Было бы очень удобно самостоятельно что-то изучать, но в определённой системе, да так. чтобы свой текущий уровень можно было предъявить любому потенциальному работодателю. (Поработали ещё немного, сделали собственными руками какую-нибудь СУБД, вот, уже, и "сеньор".))))


        1. Dozorova_Alyona Автор
          21.04.2026 15:12

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


          1. OlegZH
            21.04.2026 15:12

             А Вы пишете о "домашнем" последовательном обучении, которое может устареть через полгода из-за развития индустрии

            В том-то и интерес — найти такую последовательность, чтобы не устарело. Изучать больше принципы и методику, а деталям реализации отводить своё узкое место. Так и измерять будет просто: человек принципы хорошо знает? Хорошо. А остальное можно и в справочнике узнать (или у LLM спросить).


            1. Dozorova_Alyona Автор
              21.04.2026 15:12

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


              1. OlegZH
                21.04.2026 15:12

                Есть общие вопросы: управление памятью, мнопоточность, ООП, пользовательский интерфейс, работа с базами данных. Да есть некоторые частности, вроде Linq и Entity Framework. Но это очень важные частности. Есть толстая тёмнобордовая книжка по C# (Нейгел и другие). Можно взять за основу. Для новичка это будет каркасом для целенаправленного обучения, а для компаний — способом измерить компетенции.


                1. Dozorova_Alyona Автор
                  21.04.2026 15:12

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