Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 5
×

Як завдяки коду ми оптимізували роботу продакт-менеджера і не тільки

Мої вітання. Я Вова Кривицький, працюю Full-Stack розробником у EdTech-стартапі Mate academy. У цьому блозі спробую показати, чому написання коду — не ціль для розробника. І що найголовніше — це розуміти, яка користь для бізнесу від коду, що ти пишеш. Сподіваюсь, мій досвід стане у пригоді тим, хто розпочинає свою кар’єру в ІТ. Особливо зараз, коли конкуренція на ринку праці на junior-позиції дуже висока.

Як тільки я прийшов у професію (а було це приблизно три роки тому), моєю головною метою на роботі було... написати багато коду. На перший погляд, все логічно. Я ж працюю розробником, який за замовчуванням має писати код. Але якби ж все було так просто.

Перші місяці промайнули непомітно. Потрібно було вивчити багато нового та розібратись в тому, як працює проєкт. А ще — прокачатись самому, щоб кількість написаного мною коду була підкріплена його якістю, і в pull request’ах з моїми змінами я не отримував по 50 коментарів. Коли кількість коментарів в моїх pull request’ах зменшилась, я поступово почав думати не про те, скільки рядків коду я написав, а яку користь приносить цей код для бізнесу.

Для себе відповідь я знайшов у автоматизації процесів. Адже саме код дозволяє компанії автоматизовувати процеси та швидше розвиватись, використовуючи наявні ресурси з користю.

Є дві основні проблеми в процесах, які повністю відбуваються вручну. Перша — єдиний спосіб збільшити продуктивність при збільшенні навантаження — це додати ще людей, які паралельно будуть робити те саме.

Друга — люди помиляються значно частіше ніж код (здавалося б, так?). Тож ручна робота далека від ідеалу, і бажано мінімізувати її обсяг у бізнес-процесах. Звісно, є винятки (вони завжди є), але в більшості задач можна досягти певного рівня автоматизації, який задовольнить і компанію, і працівників, і клієнтів.

Саме тому наведу приклад з власного досвіду, який ілюструє, як код може бути корисний для компанії. Зокрема, відкриваючи нові можливості для розвитку продукту в зовсім несподіваних напрямах.

Приклад: пишемо скрипт, який буде парсити для нас вакансії з відкритих джерел

Long time ago in a galaxy far, far away ...

На одному з наших проєктів була задача — шукати топові компанії і розміщувати їхні вакансії у нас на платформі. Як це робилося: наш PM (привіт, Діма!) руками заходив на сайти необхідних компаній, шукав у них у футері посилання на careers/jobs сторінку, потім вручну передивлявся знайдені вакансії, щоб відібрати необхідні. Далі він вручну копіював опис вакансії до нас на платформу і таким чином вакансія зʼявлялась у нас на сайті.

Солюшн ручного додавання створювався в якості MVP, та очевидно, що такий підхід був не найоптимальнішим. Тож ми потребували оптимізації цього процесу. Діма можливо був і не проти додавати десятки вакансій в день, слухаючи в навушниках Симфонію № 5 Бетховена, але ми планували, щоб у майбутньому представники компанії самі займались додаванням вакансій на сайт (та й Діма міг робити корисніші речі). Так ми вирішили розробити скрипт, який допоможе Дімі звільнитися від цієї рутинної роботи, а компанії — залучити Діму до цікавіших і пріоритетніших задач.

Research

Так почався наш шлях до розробки дизайн-документа, який опише наш підхід до автоматизації цього процесу. Разом з командою ми прийшли до логічного висновку, що працювати з окремими ресурсами (сайтами компаній) буде не дуже зручно, бо на кожному з них є своя структуризація даних про вакансії (або відсутність такої структуризації).

На щастя, до такого висновку прийшли не лише ми, а й інші люди, які зрозуміли що така проблема існує, і вони почали цю проблему вирішувати. Рішення полягало в створенні спеціалізованих застосунків, що будуть дозволяти користувачам (читати «компаніям») керувати всім процесом найму нових робітників.

Завдяки гуглу та сайтам декількох FAANG компаній, ми підібрали близько 10 варіантів, які потім відфільтрували за необхідними нам параметрами. Так у нашому списку залишилось дві ATS-системи, з якими ми хотіли зробити so-called інтеграцію, або щось в такому вигляді. Цими ATS-системами стали:

  • LEVER (Netflix, Mercedes, Atlassian),
  • Greenhouse (Lyft, MessageBird, Wise).

Кастомери цих систем давали впевненість у надійності їхнього рішення, а їхні АПІ (Lever Developer та Developers Resources Greenhouse) були добре задокументовані і давали надію на швидку і безболісну інтеграцію. Визначившись з кандидатами (процес зайняв кілька днів ресьорчу і порівняння можливостей), ми зареєстрували на їхніх платформах акаунти розробників та подали заявки на інтеграції з обома системами.

Однією з характеристик відбору було те, що цими ATS користуються US-based компанії (на чий ринок ми і розраховували)

Development

Initial jobs fetch

Далі почався етап спілкування з представниками ATS систем щодо інтеграції. Ми отримали ключі до АПІ та величезний простір можливостей, у якому напрямку рухатись. Але будувати інтеграцію з двома платформами, проходити валідацію цієї інтеграції (процес схожий до валідації застосунку в play market/app store) і переводити всю взаємодію компаній з кандидатами на ATS платформи не дуже метчилося з нашою метою. У такий спосіб весь процес взаємодії б відбувався не на нашій платформі, і ми не змогли б отримати дані про його проходження і результат.

Тому, коли все було майже готово до побудови інтеграції, ми дещо змінили вектор нашої розробки. Замість будувати повну інтеграцію і ліститись в офіційному списку інтеграцій кожної ATS — ми вирішили використати АПІ ендпоінти цих систем. Так ми або представники компаній легко могли б переносити всі вакансії на нашу платформу і (що важливо) в нас зʼявлятиметься більше контролю над взаємодією користувачів з такими вакансіями. А це дозволить нам аналізувати цю взаємодію та впливати на її перебіг за допомогою проаналізованих даних.

Користуючись акаунтами розробника на цих платформах, ми знайшли, як саме можна фільтрувати вакансії за компаніями. Щоб отримати список всіх вакансій компанії треба було зробити get запит за такими адресами:

Приклад відповіді з Lever


Приклад відповіді з Greenhouse

Отож, ми отримали ресурси, за якими діставались відкриті вакансії компанії. Ці ресурси не потребували жодної авторизації, тож ними сміливо можна було користуватися, як відкритими. Справа залишалась за тим, щоб вирішити наступні задачі:

  • За запитом користувача (Діми або представника компанії) додавати вакансії компанії до нас на платформу;
  • Підтримувати актуальність списку вакансій (неактивні вакансії мають видалятися зі списку, нові — додаватися);
  • За запитом користувача видаляти всі вакансії компанії з платформи;
  • Відстежувати взаємодію користувачів з конкретними вакансіями та зберігати ці дані для подальшого аналізу.

Для їхнього вирішення ми використали мікросервісний підхід, який дозволив нам поєднати початкове додавання вакансій на платформу та підтримку актуальності цього списку надалі. Дизайн-схема сервісу виглядала наступним чином:

Схематичне зображення структури сервісу

Розберемо схему покроково:

  1. Користувач через вебдодаток нашої платформи робить запит на синхронізацію вакансій.
  2. Наша платформа додає повідомлення в SQS-чергу з адресою, за якою треба зробити запит.
  3. SQS трігерить Лямбда-функцію з цим повідомленням.
  4. Лямбда функція приймає повідомлення з url-адресою і передає його на обробку в ATS controller.
  5. ATS-controller робить реквест на необхідний ресурс і передає результат цього запиту в ATS service.
  6. ATS-service обробляє «сирі» дані з ATS controller, пропускаючи їх через необхідну функцію-маппер.
  7. Стандартизована під зберігання в нашій базі даних інформація записується в базу.

Сама собою ця схема виглядала досить straightforward, тому нижче додам деталі імплементації. Вони дозволять трохи краще зрозуміти, що ми робили з даними, як обробляли відповіді та як використовували результат.

Основна ідея перших трьох кроків — передати адресу, за якою робити запит до функції, яка власне цей запит і робить. Валідність цієї адреси ми перевіряємо ще до відправки SQS-меседжу. На серверній частині нашого продукту ми робили тестовий запит за тією адресою, яку нам передав користувач. Якщо з цієї адреси не повертався необхідний нам результат — це означало, що посилання невалідне (наприклад, компанія не використовувала вказану ATS) і ми показували користувачу помилку про те, що саме пішло не так.

А от коли вже передана адреса провалідувалась — ми створювали в нашій базі даних новий `jobs_sourse` обʼєкт і відправляли меседж в SQS, щоб зробити initial jobs fetch. На цьому етапі ми використали AWS SQS, щоб гарантувати доставку повідомлень. Якщо на якомусь етапі в лямбді сталася б помилка, повідомлення «висіло» б в черзі до тих пір, доки помилка не буде виправлена. Таким чином жоден запит не буде втрачено і ми зможемо гарантувати, що кожен (майже) запит буде виконано рано чи пізно.

У самій же лямбді ця адреса, за якою ми хочемо виконати запит, передається в ATS controller, що робить запит, приймає результат цього запиту, і передає його в ATS service на обробку. Перед тим, як передати результат в сервіс, контролер фільтрував отримані вакансії за необхідними нам параметрами, тож лише потрібні нам вакансії процесились далі. ATS service мав декілька методів, які відповідали за обробку вакансій з певного ресурсу в той формат, який може приймати наша платформа.

Формат, з яким працювала наша платформа:

```
{
  company_name: string,
  job_title: string,
  job_type: string,
  job_category: string,
  job_description: string,
  source_id: integer,
  apply_link: string
}
```

Тобто наш ATS service брав відповідні поля з «сирих» обʼєктів, мапив їх у таку структуру, і вже цей масив передавав на запис в нашу базу даних.

Спрощена схема мапінгу сирого обʼєкта в необхідний результат

На цьому етапі нічого складного. Ми робимо запит на вказані ресурси, отримуємо звідти результат, який завжди приходить в однаковому вигляді, мапимо його в потрібний нам формат і записуємо до нас в базу даних. А з бази даних вебклієнт нашого додатку вже дістає ці вакансії і показує їх на UI нашим юзерам. As easy as pie.

Data actualization

Пів діла зроблено, дані записуються до нас на платформу в один клік (для юзера) і через декілька секунд вже доступні для перегляду на платформі. Але як же актуалізовувати дані? Якщо якась вакансія вже стала не актуальною — її треба прибрати з платформи. Якщо якась вакансія додалася — її треба додати до платформи. У нас, звісно, ще залишився мануальний спосіб додавання вакансій на платформу, але ми вирішили піти з цього слизького шляху раз і назавжди, тому не використовували його.

Одним з варіантів була б інтеграція з ATS, яка дозволила б нам створити умовний web-socket, що відстежував би зміни на цих платформах (в обох платформах є ендпоінти, які трігерять слухача, коли відбувається певна подія), і викликав би функцію, яка б робила зміни в наше АПІ. Але цей варіант нам не дуже підходив (ми ж вирішили йти іншим шляхом). Тому ми... зробили ще одну лямбду! «It’s never enough», як то кажуть в нас на Херсонщині, звідки я родом.

Схема лямбди-актуалізатора

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

  • раз на 24 години функція запускається автоматично;
  • функція через GraphQL клієнт ходить до нас в базу даних і бере звідти всі ATS-посилання, які користувачі вже додали до нас на платформу;
  • кожне таке посилання функція передає в ATS-controller, який робить реквест і отримує актуальний список вакансій;
  • актуальний список вакансій опрацьовується в ATS-service і відправляється на АПІ нашої платформи;
  • АПІ нашої платформи створює всі нові вакансії і оновлює наявним, які прийшли повторно, необхідні поля (опис, назва, і поле updated_at);
  • після цього АПІ видаляє всі вакансії, у яких updated_at менше ніж поточна дата — 1 день.

Виходячи з такої логіки, максимальний час, який outdated вакансія могла «провисіти» у нас на платформі, дорівнював 24 годинам, що було доволі прийнятно в нашому випадку.

Висновки

На дизайн і розробку цього мікросервісу в нас пішло загалом 10 днів (2 робочих тижні). І як тільки він був запущений, наш продакт Діма одразу звільнив декілька годин часу на день, які тепер міг приділяти більш приоритетним задачам. А отже, інвестувати цей час у ріст продукту в інших аспектах.

До того ж цей функціонал створив додаткову цінність для користувачів і представників компаній, адже їм теж не треба було вручну додавати вакансії своїх компаній до нас на платформу. Всі були задоволені, бо позбулися рутинної роботи ...

Цей текст — лише моя думка, що ми, розробники, не повинні писати код задля написання коду. Все ж, основна ціль нашої роботи — покращувати процеси в компанії, вирішувати бізнес-задачі, робити життя і роботу наших клієнтів/ колег зручнішими. І завдяки коду ми можемо відкривати нові можливості для росту, пошуку нових ідей та фокусуванню на більш творчій роботі.

Прибираючи непотрібну рутину з поточного розпорядку дня, ми прискорюємо ріст і в цілому бізнесів, і окремих працівників, та потроху робимо наше оточення кращим. Тож, пишучи код, — вирішуйте проблеми, а не пишіть код, пишучи код.

👍ПодобаєтьсяСподобалось22
До обраногоВ обраному8
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

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

__________
Люди помиляються значно частіше, це факт. Але люди працюють в умовах, де помилка закладена заздалегідь, і мають алгоритми її опрацювання. Тому мало автоматизувати формальну роботу людей, щоб воно працювало — доводиться автоматизувати ще й граничні випадки. Це потрібно розуміти, визначаючи ціну автоматизації, і відповідно обирати, що автоматизувати варто, що не варто, а що хотілося б, але не першочергово.

Мало того, це треба пропонувати як продукт — що автоматизація не просто працює за людей, а ще своєчасно реагує на типові помилки, не намагаючись приховати їх «під килимок». А для помилок, які трапляються нечасто, це навіть більш цінне — бо чим рідша проблема, тим менше люди знають що робити і хочуть це робити. А автоматизація — це «зробив і забув». Це є виправданням ціни.

Підписатись на коментарі