Как на гитхабе найти пользователя

Лучшие специалисты достойны того, чтобы их хорошенько поискать. Поэтому, команда Hurma System продолжает обсуждать, где искать кандидатов в 2019 году. И сегодня мы поговорим про IT-рекрутмент на крупнейшем сервисе для хостинга IT-проектов и их совместной разработки — GitHub.

Как GitHub может помочь найти специалистов?

GitHub — веб-сервис, который позволяет разработчикам хранить свой код, а также делиться этим кодом с коллегами и заниматься его совместной разработкой в open source.

Другими словами, GitHub для программистов — это как Facebook для среднестатистических пользователей. Разница в том, что технические специалисты могут работать над своим кодом совместно с другими, и отслеживать его обновления с помощью Git, распределенной системы управления версиями.

Профиль специалиста на GitHub для IT-рекрутера — ценный источник информации, поскольку именно там можно понять какая должность у кандидата, место его работы и в какой стране мира он находится. Также в профиле отображается email специалиста и его сайт.

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


Пошаговая инструкция: как искать специалистов в GitHub

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

1. Регистрация

На веб-сервисе поиском могут пользоваться только зарегистрированные пользователи. Создать учетную запись в GitHub не составит труда. После того, как вы заполните данные о себе, на указанную почту придет подтверждение, и вы сразу же сможете пользоваться сервисом.

2. Поиск по ключевым словам

Если вам нужен определенный специалист, например, Java-разработчик, то если вы пропишете слово «Java» в поиске, то GitHub выполнит поиск по таким категориям:

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

3. Поиск по языкам программирования

Также на GitHub можно сразу искать по языкам программирования, которые знает специалист. 

Например, вам нужен специалист, владеющий Python. Вы вводите в Google такой запрос:

site:github.com inurl:tab=repositories Python

Далее, переходите по предложенным ссылкам.

4. Поиск по технологиям 

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

site:github.com inurl:tab.repositories Java Spring NoSQL

5. Отслеживание активности 

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

6. Коммуникация

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

Как заинтересовать кандидата?

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

1. Рынок подстраивается под IT-специалиста, а не наоборот

Стремительное развитие технологий превращает некоторых специалистов в сфере в «трофей», который хочет заполучить каждая компания. Но, если кандидат —  профессионал, то в любом случае не он ищет работу, а она его. Поэтому пытаться достучаться до таких специалистов через другие площадки, например по поиску работы, просто бесполезно. Здесь на помощь приходят закрытые площадки, такие как GitHub. Но следует помнить: вашему кандидату прямо сейчас кто-то тоже может отправлять вакансию. Ваша задача — сделать так, чтобы он согласился именно на ваше предложение.

2. Работу в вашей компании нужно продавать

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

Универсальные сообщения вроде «Здравствуйте, я рекрутер такой-то компании, и у меня много отличных предложений» больше не работают. За внимание востребованного специалиста нужно бороться. Чтобы сделать это эффективно, необходимо тщательно анализировать профессиональные навыки сотрудника, его увлечения, текущее место работы и обязанности, как мы и писали выше. Только после этого напишите индивидуальное письмо с предложением, которое потенциально может его заинтересовать. В сообщении обязательно нужно отметить те преимущества компании, которые выгодно отличают ее от других работодателей; ответить на всевозможные вопросы, а после встретиться с ним лично и плавно подвести специалиста к подписанию оффера, поддерживая с ним контакт на всех этапах процесса рекрутмента. 

3. Специалист может не проявлять энтузиазма

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

Почему важно рекрутить на GitHub?

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

Время на прочтение
10 мин

Количество просмотров 5.6K

Здравствуйте. Меня зовут Александр и я Vanilla ES5.1 разработчик в 2018 году.

Данная статья является ответом на статью-ответ «Как сделать поиск пользователей по GitHub без React + RxJS 6 + Recompose», которая показала нам, как можно использовать SvelteJS.

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

Делать будем всё тот же инпут, отображающий плашку GitHub-пользователя:

Disclaimer

Данная статья игнорирует абсолютно все возможные практики современного джаваскрипта и веб-разработки.

Подготовка

Что-либо настраивать и писать конфиги нам не нужно, создадим index.html со всей необходимой вёрсткой:

index.html

<!doctype html>
<html>
<head>
    <meta charset='utf-8'>
    <title>GitHub users</title>

    <link rel='stylesheet' type='text/css' href='index.css'>
</head>
<body>

<div id='root'></div>

<div id='templates' style='display:none;'>
    <div data-template-id='username_input'>
        <input type='text' data-onedit='onNameEdit' placeholder='GitHub username'>
    </div>

    <div data-template-id='usercard' class='x-user-card'>
        <div class='background'></div>
        <div class='avatar-container'>
            <a class='avatar' data-href='userUrl'>
                <img data-src='avatarImageUrl'>
            </a>
        </div>
        <div class='name' data-text='userName'></div>
        <div class='content'>
            <a class='block' data-href='reposUrl'>
                <b data-text='reposCount'></b>
                <span>Repos</span>
            </a>
            <a class='block' data-href='gistsUrl'>
                <b data-text='gistsCount'></b>
                <span>Gists</span>
            </a>
            <a class='block' data-href='followersUrl'>
                <b data-text='followersCount'></b>
                <span>Followers</span>
            </a>
        </div>
    </div>

    <div data-template-id='error'><b data-text='status'></b>: <span data-text='text'></span></div>
    <div data-template-id='loading'>Loading...</div>
</div>

</body>
</html>

Если кому-нибудь интересен CSS, его можно посмотреть в репозитории.

Стили у нас самые обычные, никаких css-modules и прочего scope’инга. Мы просто помечаем компоненты классами начинающимися с x- и гарантируем, что больше в проекте таких не будет. Любые селекторы пишем относительно них.

Поле ввода

Всё, что мы хотим от нашего поля ввода — debounced-событий его изменения, а так же событие начала ввода, чтобы по нему сразу показывать индикацию загрузки. Получается вот так:

in_package('GitHubUsers', function() {

this.provide('UserNameInput', UserNameInput);
function UserNameInput(options) {
    var onNameInput = options.onNameInput,
        onNameChange = options.onNameChange;

    var element = GitHubUsers.Dom.instantiateTemplate('username_input');

    var debouncedChange = GitHubUsers.Util.delay(1000, function() {
        onNameChange(this.value);
    });

    GitHubUsers.Dom.binding(element, {
        onNameEdit: function() {
            onNameInput(this.value);

            debouncedChange.apply(this, arguments);
        }
    });

    this.getElement = function() { return element; };
}

});

Здесь мы заиспользовали немного утилитарных функций, пройдёмся по ним:

Так как у нас нет webpack, нет CommonJS, нет RequireJS, мы всё складываем в объекты при помощи следующей функции:

packages.js

window.in_package = function(path, fun) {
    path = path.split('.');

    var obj = path.reduce(function(acc, p) {
        var o = acc[p];

        if (!o) {
            o = {};
            acc[p] = o;
        }

        return o;
    }, window);

    fun.call({
        provide: function(name, value) {
            obj[name] = value;
        }
    });
};

Функция instantiateTemplate() выдаёт нам глубокую копию DOM-элемента, которые будут получены функцией consumeTemplates() из элемента #templates в нашем index.html.

templates.js

in_package('GitHubUsers.Dom', function() {

var templatesMap = new Map();

this.provide('consumeTemplates', function(containerEl) {
    var templates = containerEl.querySelectorAll('[data-template-id]');

    for (var i = 0; i < templates.length; i++) {
        var templateEl = templates[i],
            templateId = templateEl.getAttribute('data-template-id');

        templatesMap.set(templateId, templateEl);

        templateEl.parentNode.removeChild(templateEl);
    }

    if (containerEl.parentNode) containerEl.parentNode.removeChild(containerEl);
});

this.provide('instantiateTemplate', function(templateId) {
    var templateEl = templatesMap.get(templateId);

    return templateEl.cloneNode(true);
});

});

Функция Dom.binding() принимает элемент, опции, ищет определённые data-аттрибуты и совершает с элементами нужные нам действия. Например, для аттрибута data-element она добавляет поле к результату со ссылкой на помеченный элемент, для аттрибута data-onedit навешивает на элемент обработчики keyup и change с хэндлером из опций.

binding.js

in_package('GitHubUsers.Dom', function() {

this.provide('binding', function(element, options) {
    options = options || {};

    var binding = {};

    handleAttribute('data-element', function(el, name) {
        binding[name] = el;
    });

    handleAttribute('data-text', function(el, key) {
        var text = options[key];
        if (typeof text !== 'string' && typeof text !== 'number') return;

        el.innerText = text;
    });

    handleAttribute('data-src', function(el, key) {
        var src = options[key];
        if (typeof src !== 'string') return;

        el.src = src;
    });

    handleAttribute('data-href', function(el, key) {
        var href = options[key];
        if (typeof href !== 'string') return;

        el.href = href;
    });

    handleAttribute('data-onedit', function(el, key) {
        var handler = options[key];
        if (typeof handler !== 'function') return;

        el.addEventListener('keyup', handler);
        el.addEventListener('change', handler);
    });

    function handleAttribute(attribute, fun) {
        var elements = element.querySelectorAll('[' + attribute + ']');
        for (var i = 0; i < elements.length; i++) {
            var el = elements[i],
                attributeValue = el.getAttribute(attribute);

            fun(el, attributeValue);
        }
    }

    return binding;
});

});

Ну и delay занимается нужным нам видом debounce’а:

debounce.js

in_package('GitHubUsers.Util', function() {

this.provide('delay', function(timeout, fun) {
    var timeoutId = 0;

    return function() {
        var that = this,
            args = arguments;

        if (timeoutId) clearTimeout(timeoutId);

        timeoutId = setTimeout(function() {
            timeoutId = 0;

            fun.apply(that, args);
        }, timeout);
    };
});

});

Карточка пользователя

У неё нет логики, только шаблон, который наполняется данными:

in_package('GitHubUsers', function() {

this.provide('UserCard', UserCard);
function UserCard() {
    var element = GitHubUsers.Dom.instantiateTemplate('usercard');

    this.getElement = function() { return element; };

    this.setData = function(data) {
        GitHubUsers.Dom.binding(element, data);
    };
}

});

Конечно, делать столько querySelectorAll каждый раз, когда мы меняем данные не очень хорошо, но оно работает и мы миримся с этим. Если вдруг выяснится, что из-за этого у нас всё тормозит — будем писать данные в сохранённые data-element. Или сделаем другую функцию биндинга, которая сама сохраняет элементы и может подчитать новые данные. Или сделаем поддержку передачи в объект опций не просто статичных значений, поток их изменений, чтобы биндинг мог за ними следить.

Индикация загрузки / ошибки запроса

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

Запрос данных

Сделаем класс с методом запроса пользователя, в случае чего мы сможем легко подменить его экземпляр моком/другой реализацией:

in_package('GitHubUsers', function() {

this.provide('GitHubApi', GitHubApi);
function GitHubApi() {
    this.getUser = function(options, callback) {
        var url = 'https://api.github.com/users/' + options.userName;

        return GitHubUsers.Http.doRequest(url, function(error, data) {
            if (error) {
                if (error.type === 'not200') {
                    if (error.status === 404) callback(null, null);
                    else callback({ status: error.status, message: data && data.message });
                } else {
                    callback(error);
                }
                return;
            }

            // TODO: validate `data` against schema
            callback(null, data);
        });
    };
}

});

Конечно, нам потребуется обёртка над XMLHttpRequest. Мы не используем fetch потому что он не поддерживает прерывания запросов, а так же не хотим связываться с промисами по той же причине.

ajax.js

in_package('GitHubUsers.Http', function() {

this.provide('doRequest', function(options, callback) {
    var url;

    if (typeof options === "string") {
        url = options;
        options = {};
    } else {
        if (!options) options = {};
        url = options.url;
    }

    var method = options.method || "GET",
        headers = options.headers || [],
        body = options.body,
        dataType = options.dataType || "json",
        timeout = options.timeout || 10000;

    var old_callback = callback;
    callback = function() {
        callback = function(){}; // ignore all non-first calls
        old_callback.apply(this, arguments);
    };

    var isAborted = false;

    var request = new XMLHttpRequest();

    // force timeout
    var timeoutId = setTimeout(function() {
        timeoutId = 0;
        if (!isAborted) { request.abort(); isAborted = true; }
        callback({msg: "fetch_timeout", request: request, opts: options});
    }, timeout);

    request.addEventListener("load", function() {
        var error = null;

        if (request.status !== 200) {
            error = { type: 'not200', status: request.status };
        }

        if (typeof request.responseText === "string") {
            if (dataType !== "json") {
                callback(error, request.responseText);
                return;
            }

            var parsed;

            try {
                parsed = JSON.parse(request.responseText);
            } catch (e) {
                callback(e);
                return;
            }

            if (parsed) {
                callback(error, parsed);
            } else {
                callback({msg: "bad response", request: request});
            }
        } else {
            callback({msg: "no response text", request: request});
        }
    });
    request.addEventListener("error", function() {
        callback({msg: "request_error", request: request});
    });

    request.open(method, url, true /*async*/);

    request.timeout = timeout;
    request.responseType = "";

    headers.forEach(function(header) {
        try {
            request.setRequestHeader(header[0], header[1]);
        } catch (e) {}
    });

    try {
        if (body) request.send(body);
        else request.send();
    } catch (e) {
        callback({exception: e, type: 'send'});
    }

    return {
        cancel: function() {
            if (!isAborted) { request.abort(); isAborted = true; }

            if (timeoutId) { clearTimeout(timeoutId); timeoutId = 0; }
        }
    };
});

});

Итоговое приложение

app.js

in_package('GitHubUsers', function() {

this.provide('App', App);
function App(options) {
    var api = options.api;

    var element = document.createElement('div');

    // Create needed components
    var userNameInput = new GitHubUsers.UserNameInput({
        onNameInput: onNameInput,
        onNameChange: onNameChange
    });

    var userCard = new GitHubUsers.UserCard();

    var errorElement = GitHubUsers.Dom.instantiateTemplate('error');

    var displayElements = [
        { type: 'loading', element: GitHubUsers.Dom.instantiateTemplate('loading') },
        { type: 'error', element: errorElement },
        { type: 'userCard', element: userCard.getElement() }
    ];

    // Append elements to DOM
    element.appendChild(userNameInput.getElement());
    userNameInput.getElement().style.marginBottom = '1em'; // HACK

    displayElements.forEach(function(x) {
        var el = x.element;
        el.style.display = 'none';
        element.appendChild(el);
    });

    var contentElements = new GitHubUsers.DomUtil.DisplayOneOf({ items: displayElements });

    // User name processing
    var activeRequest = null;

    function onNameInput(name) {
        name = name.trim();

        // Instant display of `loading` or current request result
        if (activeRequest && activeRequest.name === name) {
            activeRequest.activateState();
        } else if (name) {
            contentElements.showByType('loading');
        } else {
            contentElements.showByType(null);
        }
    }

    function onNameChange(name) {
        name = name.trim();

        // Cancel old request
        if (activeRequest && activeRequest.name !== name) {
            activeRequest.request.cancel();
            activeRequest = null;
        } else if (activeRequest) { // same name
            return;
        }

        if (!name) return;

        // Do new request
        activeRequest = {
            name: name,
            request: api.getUser({ userName: name }, onUserData),

            // method for `onNameInput`
            activateState: function() {
                contentElements.showByType('loading');
            }
        };

        activeRequest.activateState();

        function onUserData(error, data) {
            if (error) {
                activeRequest = null;
                contentElements.showByType('error');
                GitHubUsers.Dom.binding(errorElement, {
                    status: error.status,
                    text: error.message
                });
                return;
            }

            if (!data) {
                activeRequest.activateState = function() {
                    GitHubUsers.Dom.binding(errorElement, {
                        status: 404,
                        text: 'Not found'
                    });
                    contentElements.showByType('error');
                };
                activeRequest.activateState();
                return;
            }

            activeRequest.activateState = function() {
                userCard.setData({
                    userName: data.name || data.login, // `data.name` can be `null`
                    userUrl: data.html_url,
                    avatarImageUrl: data.avatar_url + '&s=80',

                    reposCount: data.public_repos,
                    reposUrl: 'https://github.com/' + data.login + '?tab=repositories',

                    gistsCount: data.public_gists,
                    gistsUrl: 'https://gist.github.com/' + data.login,

                    followersCount: data.followers,
                    followersUrl: 'https://github.com/' + data.login + '/followers'
                });

                contentElements.showByType('userCard');
            };

            activeRequest.activateState();
        }
    }

    this.getElement = function() { return element; };
}

});

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

Мы использовали вспомогательную утилитку DisplayOneOf, которая показывает один элемент из заданных, остальные прячет:

dom-util.js

in_package('GitHubUsers.DomUtil', function() {

this.provide('DisplayOneOf', function(options) {
    var items = options.items;

    var obj = {};

    items.forEach(function(item) { obj[item.type] = item; });

    var lastDisplayed = null;

    this.showByType = function(type) {
        if (lastDisplayed) {
            lastDisplayed.element.style.display = 'none';
        }

        if (!type) {
            lastDisplayed = null;
            return;
        }

        lastDisplayed = obj[type];

        lastDisplayed.element.style.display = '';
    };
});

});

Чтобы в итоге это всё заработало, нам нужно проинициализировать шаблоны и бросить экземпляр App на страницу:

function onReady() {
    GitHubUsers.Dom.consumeTemplates(document.getElementById('templates'));

    var rootEl = document.getElementById('root');

    var app = new GitHubUsers.App({
        api: new GitHubUsers.GitHubApi()
    });

    rootEl.appendChild(app.getElement());
}

Результат?

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

→ Демо → Код

Пишите тупой и вечный код. Пишите без фреймворков, а значит крепче спите и не бойтесь, что завтра весь ваш код окажется deprecated или недостаточно модным.

Что дальше?

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

Но если бы он всё-таки был больше, вот что мы бы сделали ещё:

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

В данный момент весь CSS у нас лежит в index.css, его, очевидно, тоже нужно класть рядом с компонентами.

Не хватает сборки бандлов, мы подключаем все файлы руками в index.html, это нехорошо.

Нет проблем написать скрипт, который по спискам модулей, которые должны входить в бандлы соберёт весь js, html, css этих модулей и сделает нам по одному js’нику для каждого бандла. Это будет на порядок тупее и проще, чем настраивать webpack, а через год узнать, что там уже совершенно другая версия и вам нужно переписывать конфиг и использовать другие загрузчики.

Желательно иметь какой-нибудь флаг, который бы поддерживал схему подключения js/html/css громадным списком в index.html. Тогда не будет никаких задержек на сборку, а в Sources в хроме у вас каждый файл будет в отдельной вкладке и никакие sourcemap’ы не нужны.

P.S.

Это лишь один из вариантов, как оно всё может быть используя VanillaJS. В комментариях было бы интересно услышать о других вариантах использования.

Спасибо за внимание.

You can invite users to become collaborators to your personal repository.

If you’re using GitHub Free, you can add unlimited collaborators on public and private repositories.

About collaboration in a personal repository

To collaborate with users in a repository that belongs to your personal account on GitHub.com, you can invite the users as collaborators.

If you want to grant more granular access to the repository, you can create a repository within an organization. For more information, see “Access permissions on GitHub.”

Private forks inherit the permissions structure of the upstream repository. This helps owners of private repositories maintain control over their code. For example, if the upstream repository is private and gives read/write access to a team, then the same team will have read/write access to any forks of the private upstream repository. Only team permissions (not individual permissions) are inherited by private forks.

Inviting a collaborator to a personal repository

You can send an invitation to collaborate in your repository directly to someone on GitHub.com, or to the person’s email address

GitHub limits the number of people who can be invited to a repository within a 24-hour period. If you exceed this limit, either wait 24 hours or create an organization to collaborate with more people. For more information, see “Creating a new organization from scratch.”

  1. Ask for the username of the person you’re inviting as a collaborator. If they don’t have a username yet, they can sign up for GitHub. For more information, see “Signing up for a new GitHub account.”

  2. On GitHub.com, navigate to the main page of the repository.

  3. Under your repository name, click Settings. If you cannot see the “Settings” tab, select the dropdown menu, then click Settings.

    Screenshot of a repository header showing the tabs. The "Settings" tab is highlighted by a dark orange outline.

  4. In the “Access” section of the sidebar, click Collaborators.

  5. Click Add people.

  6. In the search field, start typing the name of person you want to invite, then click a name in the list of matches.

  7. Click Add NAME to REPOSITORY.

  8. The user will receive an email inviting them to the repository. Once they accept your invitation, they will have collaborator access to your repository.

Further reading

  • “Permission levels for a personal account repository”
  • “Removing a collaborator from a personal repository”
  • “Removing yourself from a collaborator’s repository”
  • “Organizing members into teams”

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

Разработчиков программного обеспечения (ПО) можно найти на платформах, где IT-сообщество делится советами по программированию, сотрудничает и учится друг у друга.

GitHub — одна из таких платформ, поэтому рассказываем как именно рекрутеры находят с ее помощью профессионалов.

Ранее в этом блог-посте мы делали обзор опубликованной в Boolean Strings инструкции по использованию неочевидных способов поиска кандидатов на GitHub. Теперь мы обновили этот блог-пост и рассказываем вам о всех способах поиска на этом ресурсе, актуальных в 2021 году.

Выбор ключевых слов

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

Пример — рекрутер, который ищет Java-разработчиков, может использовать запрос «бэкенд OR сервер». Однако в настоящий момент Java и так по большей части используется для бэкенд-программирования, так что эти ключевые слова излишни.

X-Ray поиск по языкам программирования

Известно, что в профиле пользователя на GitHub есть вкладка с перечислением языков программирования, с которыми знаком специалист. Этот факт можно использовать для X-Ray поиска — названия языков могут выступать в качестве ключевых слов.

Пример:

site:github.com inurl:tab=repositories Java Scala Python

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

X-Ray поиск по языкам и технологиям

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

site:github.com inurl:tab.repositories Java Spring NoSQL

Здесь есть большой плюс в том, что Google определяет MongoDB в качестве синонима для NoSQL — это удобно, поскольку MongoDB как раз и является популярной NoSQL-базой данных.

1


X-Ray поиск по «главному» языку программирования

Помимо прочего, на страницах репозиториев есть ссылки на страницы, посвященные конкретным языкам программирования. По ним можно искать отдельно:

site:github.com inurl:tab.repositories inurl:language.Java Spring NoSQL

Чтобы сравнить общее число репозиториев, посвященных конкретному языку, и общее число репозиториев, можно попробовать использовать подобный запрос:

results for repositories site:github.com inurl:tab.repositories inurl:language.php

2

Поиск по ключевым словам, количеству подписчиков или звездам

Количество подписчиков на GitHub — хороший показатель профессионального уровня разработчика и его репутации среди других программистов с открытым исходным кодом.

На заметку: 2-10 подписчиков — это хорошо, 11-25 подписчиков — это очень хорошо, 26-75 подписчиков — отлично, а разработчики с более чем 75 подписчиками — настоящие звезды (имейте в виду, что таких людей чрезвычайно сложно привлечь!)

В разделе «Репозиторий» содержатся общедоступные проекты, которые разработчик загрузил на GitHub, а также проекты, которые были скопированы («разветвлены»). Чтобы оценить популярность проектов разработчика, вам необходимо выяснить, сколько людей отметили их звездочкой или «разделили» их (вилка или звездочка — признак того, что другие разработчики считают проект ценным).

site: github.com («50..250 followers» | «100..500 starred») (javascript)

«joined on» -tab.activity

Вы можете добавить другие параметры, такие как дата регистрации (“joined on [date]”), определенные организации или даже организации с определенным количеством сотрудников, чтобы уточнить свой запрос. 

Как подобраться к разработчику на GitHub:

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

2. Отслеживайте активность
Проверяйте действия пользователей, чтобы понять, чем они занимались в последнее время. Как давно они заходили на GitHub? Загружали ли они свой код или сделали fork чужого проекта? Есть ли какой-нибудь проект, над которым они проводят большую часть своего времени?

3.Перекрестная ссылка (референс)
GitHub — отличная отправная точка для изучения технических интересов кандидата, но не забывайте делать перекрестные ссылки данных на других веб-сайтах, таких как Twitter, LinkedIn и Facebook, чтобы получить полную картину.

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

Часто задаваемые вопросы про рекрутинг разработчиков на GitHub

Видна ли электронная почта разработчика на GitHub?

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

  • найдите не разветвленный репозиторий
  • найдите коммиты пользователя и щелкните по его ID
  • добавьте «патч» после того, как вы закончили на идентификаторе фиксации (commit’s ID)
  • просмотрите commit information, и вы сможете увидеть автора и его адрес электронной почты.


Как найти email пользователей Github одним щелчком мыши

Чтобы упростить поиск контактов, используйте профессиональный инструмент, такой как AmazingHiring. Он автоматически ищет подходящих кандидатов в более чем 50 источниках (таких как Linkedin, Github, Stackoverflow, Facebook) и предоставляет источники с прямыми контактами программистов.

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

Вы можете начать с тестирования бесплатного расширения Chrome от AmazingHiring, чтобы мгновенно искать профили разработчиков GitHub, которых вы ищете в других социальных и профессиональных сетях.


Можно ли написать разработчику на GitHub?

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

Можно ли опубликовать вакансию на GitHub?

У вас есть два варианта:

  • изучить профили разработчиков и связаться с лучшими кандидатами напрямую
  • разместить вакансию на GitHub Jobs

На GitHub можно бесплатно сорсить?

Сорсинг на GitHub абсолютно бесплатный, но требует знаний Boolean search и платформы.

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


Разработчикам комфортно, когда им предлагают вакансию, упомянув их GitHub?

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


Какую информацию о разработчике я могу получить на GitHub?

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

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

Плохо, когда у разработчика нет профиля на GitHub?

Профессионалы стараются создавать и поддерживать свои профили на GitHub. Однако это не значит, что разработчик плохой только потому, что у него нет профиля. Это может значить, что они не заинтересованы в том, чтобы делиться своими проектами, или работали только над проектами под NDA и не имеют pet-проектов. Хорошо это или плохо в современном мире — решать вам, но вам точно нужно оценивать больше критериев, чем только наличие раскрученного GitHub-аккаунта.

Удачного сорсинга!

Вы также можете посмотреть запись нашего вебинара с Ириной Шамаевой, лидером сорсинга, в нем Ирина подробно рассказывает про функционал GitHub.

Советы рекрутерам: как найти контакты разработчиков

Статья была подготовлена авторами проекта AmazingHiring.
AH – поисковик для IT рекрутеров. Он помогает найти кандидатов больше,
чем где-либо, быстрее и эффективнее их оценить.

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

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

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

Больше разработчиков, чем где-либо

Кого и где ищут рекрутеры

Как правило, специалистов по подбору персонала интересуют контакты опытных специалистов — senior и middle-разработчиков, менеджеров проектов, системных архитекторов и т.п. Информацию о таких специалистах можно найти в интернете, однако сделать это не так просто.

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

  • профессиональные ресурсы (GitHub, Stackoverflow, HabraHabr, BitBucket, Codeforces и т.д.);
  • профильные сообщества, посвященные конкретным технологиям;
  • социальные сети;
  • AmazingHiring.

Найти базовую информацию о навыках и проектах разработчика можно на ресурсах вроде GitHub, «Мой Круг», Codeforces и т.п. При этом не следует пренебрегать и сообществами, которые посвящены конкретным технологиям – к примеру, Ruby-разработчиков можно найти на Rubygems, специалистов по Djando – на Djangoprojects, знатоков Perl – на CPAN, а специалистов по Android-разработке – в Google Play.

Больше разработчиков, чем где-либо

Ищем email разработчика

Многие сайты дают возможность создания так называемых консолидированных профилей, в которых можно указать разные типы связи – телефон, email, Skype и т.д. Однако большинство разработчиков предпочитает лишний раз «не светить» свои адреса. Но найти страницу конкретного пользователя, например, на GitHub обычно не так сложно, для этого нужно одно из двух действий:

1. Запустить внутренний поиск пользователей по имени и фамилии.

2. Либо воспользоваться X-Ray search: site:github.com <имя> <фамилия>.

Но что делать, если на страничке человека не указан его email? Тогда алгоритм действий может выглядеть так:

1. Находим профиль.

2. Переходим по адресу https://api.github.com/users/[username]/events/public, предварительно вставив никнейм кандидата в [username].

3. Ищем на странице символ ‘@’ и, соответственно, email кандидата.

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

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

Можно использовать и инструмент VoilaNorbert, который позволяет найти email-адрес в интернете по имени, фамилии и доменному имени.

По такому же принципу действуют и ресурсы AnyMailFinder.com и FindAnyEmail.net. Последний также привязан к социальному ресурсу Gravatar и отображает при совпадении аватарку пользователя.

Прибегают рекрутеры и к более изощренным методам – например, к подбору возможного email-адреса с помощью специальных генераторов. К примеру, сервис Name2Email, используя имя, фамилию нужного человека и доменное имя, может сгенерировать все возможные варианты названия его почтового ящика. Инструмент интегрирован с Gmail – это позволяет быстро проверить, какой из сгенерированных адресов реален. Почтовые адреса службы Google привязаны к соцсети Google+, поэтому при наведении курсора на реальный адрес всплывает окошко с персональными данными человека:

Другие генераторы и верификаторы адресов, в которых вы без труда сможете разобраться самостоятельно:

  • Guesser.email
  • EmailGenerator.io
  • EmailHunter.co
  • MailTester.com

Как правило, рекрутеры стараются найти личный почтовый ящик специалиста, но если этого не удается сделать, то тогда приходится искать рабочую почту. Сделать это можно с помощью подбора. Для этого достаточно узнать структуру построения email-адресов в компании – каждая организация использует свой шаблон создания названий почтовых ящиков (например, имя.фамилия@company.com). Проверить правильность предположения можно с помощью EmailHunter, либо вбив запрос “*@company.com” в Google.

Больше разработчиков, чем где-либо

Используем Boolean Search

По данным AmazingHiring, порядка 68% разработчиков СНГ пользуются Gmail как основным почтовым ящиком. Использовать boolean search (поиск в Google и других поисковых системах с использованием специальных операторов) можно и для поиска личного адреса.

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

1. Поиск почтового адреса через Google:

[firstname] [lastname] “@gmail.com”.

2. Поиск email на странице с упоминанием кандидата: для этого в поисковую строку надо вбить

*@gmail.com | *@*.com | @*.* [вся доступная нам информация, например, технологии, название компании].

3. Поиск на корпоративном сайте можно осуществить так:

site:[company].com [firstname] [lastname] email или site:[company].com [firstname] [lastname] contact

Больше разработчиков, чем где-либо

Что можно узнать из социальных сетей

Поиск контактов разработчиков через социальные сети не всегда эффективен. Но, если все остальные ресурсы исчерпаны, можно попытать удачу и там. Почти все соцсети предлагают свои инструменты для поиска нужных контактов. Например, в Twitter можно использовать Twitter Advanced Search или AllMyTweets.net.

Twitter Advanced Search, то есть внутренний поиск в Twitter, дает возможность искать твиты определенных пользователей, содержащие нужную нам информацию. В “Any of these words” для поиска адреса электронной почты мы можем перечислить все заменители символа @:

{at} {dot} {собака} [at] [dot] [собака] (at) (dot) (собака)

И указать ниже, в строке “From these accounts”, что нас интересует конкретный пользователь: @[account].

Во втором случае последовательность операции следующая:

  • Заходим в сервис AllMyTweets.net через свой Twitter.
  • Вводим нужный адрес аккаунта.
  • Ищем на странице @[company] ИЛИ @gmail ИЛИ email ИЛИ mail

Для «ВКонтакте» есть VK News Advanced Search. Здесь можно ввести “@[company].com” или “@[company].com” [firstname]. Так мы найдем email кандидата, если он указал его в публикациях в VK, либо узнаем структуру корпоративного email в организации, где работает наш кандидат.

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

Больше разработчиков, чем где-либо

Как все упростить

Значительно упростить задачу поиска разработчиков можно с помощью сервиса AmazingHiring. Cистема автоматически находит профили разработчиков на специализированных ресурсах (GitHub, Stackoverflow, BitBucket, HabraHabr, Dribbble и десятки других), в профессиональных социальных сетях (LinkedIn, МойКруг, DOU), а также в традиционных социальных сетях. Все данные сводятся в единую карточку кандидата – в ней сразу видны и возможные способы связи, и профессиональные достижения конкретного специалиста, и оценка технических навыков.

В результате у вас есть возможность найти всех разработчиков в нужной вам локации, увидеть их контакты, не затрачивая уйму времени на поиск, и, что самое сложное в рабочем процессе рекрутера, понять, насколько кандидат силен в той или иной технологии. Алгоритм AmazingHiring автоматически определяет, насколько высока профессиональная репутация кандидата на специализированных ресурсах – как часто копировали код, которым разработчик делился в рамках open-source проектов, высоко ли оценивали его ответы на те или иные вопросы на Stackoverflow, насколько высока его репутация на Kaggle и сотни других критериев.

Помимо этого недавно AmazingHiring запустил ATS (Applicant Tracking System, CRM-система для кандидатов), которая автоматически обновляет информацию о кандидатах и буквально “оживляет” вашу базу данных.

Вы можете попробовать сервис в действии, запросив бесплатный доступ к сервису по ссылке.

Добавить комментарий