---
title: ''
disqus: hackmd
---
# Тестовое задание SkyEng
[TOC]
## Задание 1
*Есть N микросервисов, каждый хранит у себя часть данных. Например: данные о пользователе, оплаты пользователя, начисления и списания продуктов, аналитика мобильного приложения. Заказчик просит сделать endpoint, который вернет данные с возможностью фильтровать и сортировать по любым полям, при этом нужны данные из всех микросервисов. Дополнительно должна быть возможность пагинации. Какие технические решения возможны и как ты будешь выбирать подходящее?*
### Размышления
Чтобы писать меньше букв, договоримся, что сервис-поставщик -- это микросервис, хранящий часть данных
#### Фаза 0 (отрицание)
Сначала было бы круто узнать какую конечную цель преследует наш заказчик, возможно и проектировать ничего не придётся или функциональные требования поменяются диаметрально.
#### Фаза 1
Дальше важно выяснить вопрос о том насколько часто будет требоваться описанный эндпоинт. Если на входе понятно, что это разовая акция или же наоборот ничего непонятно и полезность фичи нужно еще проверить, то я бы пошел по наименее трудозатратному пути и в качестве решения предложил бы организовать разовую выборку данных (тут, не хватает знаний об объеме выбираемых данных), хранящихся в сервисах-поставщиках в любое хранилище у которого есть UI (считайте, что можно взять любую реляционную строковую СУБД), в котором можно посортировать и пофильтровать. При выборе конечного хранилища не побрезговал бы даже гуглотаблицами, хотя там и нет пейджинга, но с другой стороны мы и объема данных не знаем. Может пейджинг это просто блажь, которая случайно затесалась в требования (шутка).
Т.е. самый примитивный вариант реализации выглядел бы вот так:
```graphviz
digraph graphname{
rankdir=LR;
SS [label="Service-source"]
SS2 [label="Service-source2"]
Points[shape=none label="..."]
SSN [label="Service-sourceN"]
CSV [label="CSV"]
CSV2 [label="CSV2"]
Points2 [shape=none label="..."]
CSVN [label="CSVN"]
GD [label="
Google
SpreadSheet
"]
CL [label="Client"]
SS->CSV[label="Data"]
SS2->CSV2[label="Data"]
SSN->CSVN->GD[label="Data"]
Points->Points2->GD[style=invis]
CSV->GD[label="Data"]
CSV2->GD[label="Data"]
{rank=max;CL}
CL->GD[dir=both]
}
```
#### Фаза 2
В реальной жизни при принятии решения стараюсь опираться на команду, на технические компетенции её участников, на вектор желаемого развития участников команды. Самое шикарное когда удаётся совместить выполнение бизнес-потребности с желаемым вектором развития сотрудника(-ов).
#### Фаза 3 (принятие)
Если так случилось, что решение по каким-то причинам нужно принимать в "одну каску" и без контекста, то давайте примем еще ряд допущений:
* нет ограничений по времени и бюджету
* нет зависимых технологий, на которые мы должны опираться
* нет ограничений по внешнему виду конечного сервиса
* нет необходимости резервировать данные
* нет потребности в мониторинге сервисов
* нет потребности ограничивать доступ к эндпоинту
* нет возможности управлять стеком технологий, используемых в сервисах-поставщиках (знаю, что в skyeng стек стабильный, при решении задачи фантазиурю)
* мы имеем равнораспределенную нагрузку на сервис, без пиковых нагрузок
Попытаемся додумать и сформулировать перечень требований к системе. Множество сервисов-поставщиков намекает на то, что:
1. Мы имеем дело с гетерогенным стеком технологий
2. Нельзя рассчитывать на синхронность при обмене данными
3. Количество сервисов-поставщиков и объем данных может меняться (обычно растёт)
4. Хочется минимизировать трудозатраты со стороны команд, разрабатывающих сервисы-поставщики
5. Исключить влияние на логику сервиса-поставщика
Очертим функциональные требования к эндпоинту:
1. Данные представляются в виде грида
2. Данные можно фильтровать
3. Данные можно сортировать
4. Есть пейджинг
Картинка отражающая финальное техническое решение:
```graphviz
digraph graphname{
rankdir=LR;
SS [label="Service-source"]
SS2 [label="Service-source2"]
Points[shape=none label="..."]
SSN [label="Service-sourceN"]
Broker [label=Kafka]
A [label="Application"]
DB [label="DB"]
CL [label="Client"]
{rank=max;CL}
SS->Broker[label="Data"]
SS2->Broker[label="Data"]
SSN->Broker->DB->A[label="Data"]
Points->Broker[style=invis]
DB->Broker[label="Request"]
A->DB[label="Request"]
CL->A[dir=both]
}
```
Ключевой функцией системы является сбор данных, для её реализации я решил использовать Apache Kafka, потому что с ней мы:
- можем получать данные тогда, когда хотим
- не зависим от стабильности работы сервисов-поставщиков
- имеем возможность сделать не один, а несколько эндпоинтов с подобной функциональностью, не привязываясь к конкретным технологиям
- можем добавлять новые сервисы-поставщики, опять же, не привязываясь к конкретным технологиям
Выбранное архитектурное решение позволяет воспринимать эндпоинт как один лаконичный компонент большой системы и развивать его тоже можно постепенно по мере поступления проблем, в том числе экспериментируя с технологиями и инструментами. Поэтому над выбором СУБД и ЯП эндпоинта ломать голову не будем и возьмем первое приглянувшееся, например, postgresql, php и vue. Для пейджинга, сортировки, фильтрации на фронте будем использовать [https://bootstrap-vue.org/](https://bootstrap-vue.org/)
#### Чекинг
| Требование | Решение | Решено? |
|:----------------------------------------------------------------------------------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |:------------------:|
| Гетерогенность технологии сервисов-поставщиков | Готовые клиенты или REST API от Confluent Platform [https://www.confluent.io/product/confluent-platform/multi-language-development/](https://www.confluent.io/product/confluent-platform/multi-language-development/) | :heavy_check_mark: |
| Асинхронное взаимодействие между сервисами-поставщиками и ендпоинтом | Apache Kafka в коробке даёт возможность асинхронного взаимодействия | :heavy_check_mark: |
| Готовность к изменению количества сервисов-поставщиков и набора поставляемых данных | Если какой-то сервис-поставщик перестанет существовать, то на эндпоите просто не будет данных которые поставлялись этим сервисом. Если появится новый сервис-поставщик, то прикрутим два confluent-коннектора (producer и consumer) и организуем вывод данных на эндпоинте | :heavy_check_mark: |
| Минимизация трудозатрат команд сервисов-поставщиков | Потребуется только доступ на чтение (и чуть-чуть на запись) в БД и краткая консультация о структуре хранения данных | :heavy_check_mark: |
| Исключить влияние на логику сервиса-поставщика | Сервис-поставщика не меняем | :heavy_check_mark: |
| Данные представляются в виде грида | bootstrap-vue | :heavy_check_mark: |
| Данные можно фильтровать | bootstrap-vue | :heavy_check_mark: |
| Данные можно сортировать | bootstrap-vue | :heavy_check_mark: |
| Пейджинг | bootstrap-vue | :heavy_check_mark: |
_Портрачено времени: 6 часов_
## Задание 2
_Ты пришел в команду как тимлид. Разработчики жалуются: легаси, говнокод, много багов. Двое разработчиков предлагают рефакторинг, которым никто давно не занимался. Другие двое — переписать всё с нуля. Что ты будешь делать?_
### Размышления
Белые пятна в контексте:
1. состояние бизнеса: Активный рост/стабильность/кризис/?
2. потребности бизнеса?
3. критичность сервиса для бизнеса?
4. фактический уровень разработчиков?
5. степень погруженности разработчиков в предметный домен и код?
6. длительность работы с текущей кодовой базой каждого разработчика?
7. документация?
8. и прочее
Постараюсь придерживаться следующего алгоритма действий:
#### 1. Анализ
1. Выслушаю каждого тет-а-тет, позадаю вопросы, уточняющие мотивацию каждого разработчика и уровень решимости переходить к действиям
2. Узнаю планы и потребности бизнеса
3. Узнаю планы в IT-управлении компании: общий вектор развития, желание внедрению массовых IT-решений
4. Соберу общую встречу(-и) на которой попробуем вместе с командой зафиксировать больные точки и плюсы/минусы вариантов решения. На встрече займу роль фасилитатора
5. Проанализирую кодовую базы и архитектурные решения
6. Предыдущие шаги кроме информации должны дать время, чтобы успеть посмотреть за реальной работой по задачам, пособирать статистику решения задач: ttm, попадание в оценку, попадание в требования. Если времени не хватит, то возьму искусственную паузу в принятии решения.
#### 2. Принятие решения
Вот тут могут быть самые разные решения: от "остановить выпуск фич и переписать всё с нуля" до "оставить всё как есть и даже не рефакторить". Решение будем принимать исходя из данных полученных в результате анализа, т.е. оглядываясь на бизнес, роадмап развития разработчиков, состояние продукта. Скорее всего остановимся на каком-то промежуточном варианте при котором мы и тех.долг сокращаем и бизнес-фичи пилим.
Что важно:
1. Принимать решение и отвечать за него будем внутри команды
2. Расскажем бизнесу о принятом решении
3. Общую цель, принципы её достижения и роадмап максимально визуализируем и для себя, и для бизнеса
4. Разложим работу на микрозадачи
5. По возможности решение бизнес-задач совместим с повышением качества
6. Будем измерять профит от каждого действия например, в виде берндаунчарта
7. Есть вероятность, что для сняти боли потребуется изменить процесс или ввести новые роли в команду
_Затрачено времени: 1час_
## Задание 3
_Продакт приходит к тебе с огромной задачей: сделать собственное решение видеосвязи на платформе обучения, просит оценить её. Как будешь оценивать?_
### Размышления
Размышления буду строить, опираясь на факт, что в компании уже есть общий движок для видеосвязи - [https://habr.com/ru/company/skyeng/blog/446444/](https://habr.com/ru/company/skyeng/blog/446444/)
Прежде чем оценивать узнаю о причинах, по которым продакту нужно своё решение. Предполагаю, что результат диалога будет таким:
1. делать своё решение нелесобразно
2. сформированы перечень требований в команду видеосвязи
3. вместе с продактом откурируем реализацию требований командой видеосвязи
О варианте когда продакт переубедил могу поразмышлять устно.
_Затрачено времени: 1час_