Тестовое задание для ВТБ Мультибонус.

Кандидат: Черкасов Евгений Александрович hh.ru

Задание: гугл-документы

Решения

1. Хлебные крошки

Код основного компонента можно посмотреть тут: 1/src/stories/Breadcrumbs.js

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

  1. $ cd ./1
  2. $ yarn
  3. $ yarn storybook

2. Корректное число

Код в файле 2/index.js Тесты в файле 2/index.test.js

Тесты можно запустить следующим образом

  1. $ cd ./2
  2. $ yarn
  3. $ yarn test

3. Наименьшее пропущенное положительное число

Код в файле 3/index.js Тесты в файле 3/index.test.js

Тесты можно запустить следующим образом

  1. $ cd ./3
  2. $ yarn
  3. $ yarn test

4. Про принципы проектирования

Самый важный принцип для меня - это KISS, что значит "не усложняй", когда можно не усложнять. Довольно часто я отстаиваю именно эту позицию при принятии решений и при ревью кода. Если я вижу что код написан сложно и нужно потратить время, чтобы разобраться в нем, то я скорее верну реквест на доработку.

Принцип DRY мне тоже близок, но на этапе разработки я склонен часто его нарушать, чтобы в будущем исправить. Пример: Бывает, что команда делает несколько родственных, но разных компонентов и гораздо проще и эффективнее реализовать эти компоненты изолированно, а потом выделить общий код и вынести в родительский компонент или ХОК, чем на старте обсудить все нюансы и заблокировать работу команды пока один сделает общий код, от которого придется наследоваться.

Принцип YAGNI очень близок к KISS и его тоже стараюсь активно продвигать. Думаю нет программиста, которому нравится делать ненужную работу.

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

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

Для UI мне нравится использовать Component Driven Development — сначала создаем все компоненты изолированно, а потом собираем из них, как из лего, более сложные компоненты или страницы. Очень хорошо на эту методологию ложится Atomic Design, когда UI делится на атомы, молекулы и организмы. На этом подходе я построил около 10 приложений.

С приходом TypeScript я стал использовать Type Driven Development — сначала пишем интерфейсы и типы, а затем делаем реализацию. Это позволяет на берегу качественно продумать все связи в разрабатываемой фиче, а затем очень легко и быстро набрать основной код, так как IDE практически 80% пишет за тебя.

К сожалению, я довольно редко пишу тесты, но TDD для некоторых моментов очень выручает. Например, в текущем своем проекте я использую TDD для реализации сложных адаптеров, которые покрывают сразу несколько кейсов. Так же я использовал TDD для реализации 2 и 3 задания. Это позволило не беспокоиться, что я не учту "особые" случаи, а так же сэкономило время на ручной проверке всех вариантов входных данных.

5. Про паттерны проектирования

Основные паттерны, которые я использую осознанно:

Фабрика - по заданным параметрам возвращает нам нужный объект. В Реакте можно использовать для генерации разнотипных элементов списка типа list.map(item => factory(item))

Адаптер - в последнем проекте использую на 100%. От бекенда приходят грязные данные, поэтому с помощью адаптеров преобразую их в необходимый вид и кладу в стор: fetchData().then(adapter).then(saveToStore)

Декоратор - по сути ХОКи в реакте. Например: withBorder(Card)

Фасад - бывает что нужно взять какую-то сложную, часто универсальную, либу для использования в конкретном кейсе. Фасад нужен, чтобы упростить интерфейс либы. Например на вход будет приниматься 1-2 бизнес параметра вместо 10 технических.

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