Java-разработка в Findev — это не просто обычная Java-разработка. У неё есть свои особенности, и именно они формируют наш подход к найму. Ниже мы объясняем, что, по нашему мнению, важно в нашей работе.
Очень часто кандидаты спрашивают нас: «Зачем вам знание многопоточности? Вы действительно это используете?» Да, в большинстве современных Java-стеков разработчики редко создают потоки или напрямую работают с пулом потоков. Фреймворки управляют жизненным циклом; реактивные пайплайны обрабатывают асинхронные цепочки; пулы соединений обеспечивают параллелизм. Код приложения выглядит последовательным. Но на самом деле это не так.
Модель микросервисов усугубляет ситуацию, а не улучшает её. Разделение логики по сервисам устраняет общие изменяемые состояния. Это исключает один класс проблем с параллелизмом и вводит распределённые гонки и взаимоблокировки, которые гораздо сложнее обнаружить. Взаимоблокировка внутри одного JVM приводит к дампу потоков с видимым циклом. Распределённая взаимоблокировка проявляется как тайм-аут, всплеск задержек или молчаливое накопление очереди. В трассировке стека нет ничего, что говорило бы «взаимоблокировка». Понимание того, что происходит под капотом (модель памяти, гарантии happens-before, планирование потоков), не является опциональным в асинхронных распределённых системах. Это разница между диагностикой проблемы и перезагрузкой сервиса с надеждой, что это поможет.
Инженеры, которые не знают внутренности VM, воспринимают многие вещи как загадку; инженеры, которые знают, могут аналитически распознавать паттерны и решать критические инциденты в продакшене вовремя.
Каждая система, которую мы строим, распределённая. Это значит, что каждое сообщение может быть доставлено более одного раза, и каждый потребитель должен быть спроектирован с этим учётом. Доставка как минимум один раз (at-least-once) — это стандарт Kafka; в большинстве приложений это приемлемый компромисс. В системах управления заказами или сверки разница между один раз и два раза — это некорректная позиция или дублированная сделка. Паттерн Saga — часть нашей профессиональной жизни. Он не устраняет проблему доставки; он делает явными режимы отказа. Решение о гарантиях доставки и идемпотентности должно быть принято в самом начале и проверяться каждый раз при эволюции системы.
Экстремальные рыночные события, такие как Flash Crash (2010), снятие привязки EUR/CHF SNB (2015), Brexit (2016) и рыночные потрясения COVID-19 (2020), неоднократно приводили к рекордным уровням торговой активности. В то время как объёмы торгов на бирже обычно увеличиваются в несколько раз, системы обработки событий на нижних уровнях могут испытывать нагрузку в 10-100 раз выше из-за эффектов расширения и каскадных перерасчётов.
Хотя инициирующее событие может напоминать то, что Талеб описывает как Чёрного Лебедя, инженерный вопрос уже уже: сможет ли система выдержать 100-кратный всплеск нагрузки без сбоев и вернуться к нормальным операционным затратам после? Постоянное избыточное резервирование — не решение. Частично решением является проектирование с эластичной ёмкостью, и оно должно быть заложено с самого начала, а не добавлено, когда система уже испытывает нагрузку. Но это не конец истории. Рост производительности оборудования дал нам роскошь не беспокоиться об алгоритмической эффективности. Кому важна сложность O(N²), если N достаточно мал? Но что если это не так? Вот тут знания алгоритмов, структур данных и внутренностей JVM снова становятся актуальными.
«Моё приложение в облаке, я защищён от большинства сбоев инфраструктуры» — нет, это не так.
«Команда DevOps и инфраструктуры подумала об устойчивости, это не моя забота» — нет, это ваша забота.
Облачные провайдеры предлагают гарантии доступности. Эти гарантии описывают, как их платформы ведут себя при определённых условиях. Они не описывают, как ваше приложение поведёт себя, если выйдет из строя только часть системы.
Как разработчики, мы отвечаем за то, чтобы наши системы продолжали обслуживать бизнес, когда что-то идёт не так: землетрясения, лесные пожары, отключения электроэнергии или бульдозер, случайно перерезавший кабель. Redis, Kafka, кластеры баз данных, k8s: все строительные блоки есть, но нам всё равно нужно заранее продумывать сценарии отказов.
RTO и RPO определяются до первого проектного решения, а не выявляются в ходе постмортема. Будь то синхронная репликация между дата-центрами, активная-активная топология или автоматический фейловер за 60 секунд — всё зависит исключительно от этих двух показателей.
Java по-прежнему наш основной язык бэкенда в финтехе, но Python и Node.js тоже набирают популярность.
А что мы строим на Java? В первую очередь системы, связанные с жизненным циклом сделок: системы управления заказами, системы управления исполнением, сервисы захвата и распространения рыночных данных, платформы пост-трейд обработки и так далее.
Вот несколько примеров из нашей прошлой работы.
Будьте осторожны: если работодатель просит войти через Google, iCloud или Госуслуги, прислать код или пароль, запустить ПО или перевести деньги — это мошенники.
ЖмитеГайд по безопасности