Русский
Русский
English
Статистика
Реклама

Бэкенд

Recovery mode Как я искал работу в Берлине

04.09.2020 04:18:51 | Автор: admin

Обычно рассказывают про уже свершившиеся истории о том как кто-то уже нашел работу и переехал. Я все еще в процессе, так что расскажу с чем сталкивался и к каким выводам пришел. Советы будут в самом конце.

В марте 2020-го приехал я в Берлин на две недели отдохнуть (тогда корону многие всерьез не воспринимали). Через неделю после моего приезда Германия (и все остальные за ней) закрыли все границы и объявили режим ЧП. У меня было окно в день чтобы вернуться в Сербию, но я решил попытать счастье. Что-то мне подсказывало что я смогу воспользоваться ситуацией с короной чтобы получить документы не выезжая. Так и случилось, нашел миграционного адвоката, мы с ним обсудили ситуацию и он взялся за мое дело. Дело было за мной найти работу.

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

Еще будучи в Сербии я пытался искать работу в Германии, но за два года никто так и не отозвался по двум причинам:

  • Номер обратной связи был НЕ немецкий, а сербский, а значит я НЕ в Германии

  • У меня на тот момент не было разрешения на работу (о чем почти все спрашивали в анкете на момент подачи заявления)

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

Как только адвокат получил для меня разрешение на работу в Германии и я стал в анкетах указывать что виза у меня есть и оставлять немецкий номер - то звонки от рекрутеров и HR компаний стали поступать сразу. Только в Августе у меня было 21 интервью.

Конечно из-за Ковида компании начали отвечать только к конце июля. До этого была тишина.

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

Подавался я на позиции Fullstack, Frontend и Backend разработчика, Благо опыта было достаточно и еще я воспользовался пандемией и потратил время но обновление своих знаний, завершил пару курсов на Udemy, получил сертификаты, наполнил свой Github и порешал задачи на HackerRank, как оказалось потом, спрашивали все.

Frontend

Два года назад я начал копать Frontend, то выбор пал на Vue и React, потому что чуть ли не каждый второй пугал тем что Angular уже вымер, и держится он только на том что его поддерживает Google.

Мои наблюдения показали что Стартапы и новые компании ищут в основном React разработчиков.
Серьезные компании ищут Angular разработчика. Который написан на Typescript. на который здесь моляться.
Vue почти никто не интересовался, только одна компания просила меня сделать тест задание на Vue и то на следующий день позвонили и сказали что прерывают процесс рекрутинга на эту позицию так как руководство решило подождать.

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

Backend

Сразу бросилось в глаза то что почти никто не искал PHP разработчика, на Backend в основном искали Java, Go, RoR, Node или Python. Из этого списка я работал только с Node.js, поэтому и подавался на позиции где указывался Node.

Процесс рекрутинга

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

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

  3. На третьем этапе вам посылают тест задание, слова это хорошо, но надо доказать на деле что вы действительно знаете все о чем вы говорили до этого. Самое частое задание которое меня просили выполнить - это написать конвертор валюты.

  4. Четвертый этап они называют Behavioral Interview - обычно это Project Manager, пытается выявить сможете ли вы следовать правилам выполнения работ (обычно Agile), написания кода и составление документации

  5. Последний Этап - это знакомство с командой. К моему удивлению это было не "Ребятя, познакомьтесь. Это Азиз", а вполне себе серьезный разговор со большинством команды. Каждый задает вопросы в своей сфере и пытается понять как именно вы будете полезны именно им. До этого этапа я дошел только трижды

Советы

  • Agile: Представьте что ваш директор дал вам час на написать определенного кода. Не важно успеете Вы или нет. Вы должны начать писать код тк, чтобы в случает когда вы не успеете и передадите задание другому коллеге, он - взяв незаконченный код, понял что вы хотели сделать. 90% компаний ждали именно этого подхода от меня и этот ответ их полностью удовлетворял.
    На деле это выглядит так: Вы начинаете писать код, создаете функции оставляете их пустыми, дополните потом, или Вы или Ваш коллега, неважно - главное вы начертили структуру. То же самое касается Юнит Тестов. При написании обязательно надо создавать Тесты или до написания кода, или параллельно. Вы должны показать что вы будете членом команды.

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

  • Создайте несколько резюме, не бойтесь удалять из резюме годы не имеющие отношения к вашей программистской деятельности если подаетесь на программиста. У вас обязательно спросят чем вы занимались в период пропуска. Можете ответить что хотели попробовать свои силы в другой сфере то же. и теперь вернулись программирования так как эта страсть не угасает никогда

  • Удалите или отредактируйте позиции с предыдущих работ. Или придумайте хороший ответ который их удовлетворит. Если вы были директором предприятия и подаетесь на разработчика - будьте уверены Вас обязательно спросят об этом. Вам могут из-за этого и отказать, предположив что вы будете скучать в роли подчиненного.

Отказы

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

Из моих отказов один был мотивирован тем что:

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


Благодарю тех кто дочитал до этого момента, тех кто не дочитал тоже благодарю.

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

Подробнее..

Как не держать лишнее железо и справляться с ростом нагрузки внедрение graceful degradation в Яндекс.Маркете

14.01.2021 12:05:51 | Автор: admin

Привет, меня зовут Евгений. Я разрабатываю инфраструктуру поиска Яндекс.Маркета. Хочу рассказать, как graceful degradation помогает нам обрабатывать больше запросов, чем физически могут выдержать наши сервера, и что происходит с поиском в Маркете, если один из дата-центров отключается.

Проблема

Все критичные сервисы в Яндексе должны переживать отключение одного из дата-центров (ДЦ), поэтому обычно они размещаются минимум в трёх ДЦ.

Обычное состояниеОбычное состояние

Но когда все ДЦ работают, каждый из них оказывается задействован лишь на 60%. Ещё 10% резервируются для экспериментов и непредвиденного роста, а оставшиеся 30% используются только в случае, если один из ДЦ отключается, и нужно перераспределить запросы.

ДЦ 2 отключёнДЦ 2 отключён

Если сервис работает на сотнях серверов, 30% это огромное количество железа. А поскольку отключаются ДЦ очень редко, резервные мощности почти всегда простаивают.

Нам хотелось бы меньше греть воздух, ведь если сократить количество железа в каждом ДЦ хотя бы на 10%, речь уже шла бы о внушительных суммах. При этом, если просто вытащить часть железа, а затем при пиковой нагрузке какой-то из ДЦ отключится, оставшиеся мощности могут не справиться. Резко вырастет время ответа пользователю, а некоторые запросы будут вообще оставаться без ответа.

ДЦ 1 и ДЦ 3 не справляются с нагрузкойДЦ 1 и ДЦ 3 не справляются с нагрузкой

Применяем graceful degradation

Graceful degradation или изящная деградация это подход к построению систем, при котором система продолжает выполнять свою основную функцию, даже если отдельные её элементы вышли из строя.

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

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

Чтобы запустить graceful degradation, нам надо было решить две задачи:

  1. Разработать механизм уменьшения нагрузки.

  2. Сделать автоматизацию включения механизма.

Механизм уменьшения нагрузки

Уменьшить нагрузку можно по-разному. Один из вариантов отвечать ошибкой на некоторые запросы. Но тогда надо понять, на что можно так отвечать, а на что нет. То есть нужен какой-то параметр важность, которого мы не знаем. Если спросить у наших клиентов, что важно, они ответят, что важны все запросы, и ничего нельзя отбрасывать. Поэтому этот путь нам не подошёл.

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

Таким образом, мы выбрали третий вариант снижать качество. Основное преимущество этого подхода возможность уменьшать нагрузку на 5%, 10% и так далее.

Допустим, вы ищете себе новый телефон и заходите в категорию Смартфоны на Яндекс.Маркете. Я уже подробно описывал, как работает наш поиск: запрос отправляется во фронтенд, надо показать пользователю 48 лучших предложений из категории с телефонами для конкретного региона. Фронтенд делает свой запрос в поисковый бэкенд.

Бэкенд получает запрос и раcпределяет его на 8 серверов с шардами. В шардах хранятся предложения от магазинов.

Общая схема обработки поискового запросаОбщая схема обработки поискового запроса

На каждом шарде поиск проходит несколько стадий. На стадии фильтрации ищется примерно 50000 предложений, это число зависит от категории. На этапе ранжирования для каждого предложения вычисляется релевантность, учитывается цена, рейтинг товара, рейтинг магазина и ещё более 2000 факторов. ML по факторам вычисляет вес каждого предложения. Затем берётся только 48 лучших. Meta Search получает эти 48 предложений с каждого шарда, то есть всего 48*8=384 предложения. Предложения снова ранжируются, опять берётся 48 лучших. Последние 48 уже показываются пользователю. То есть чтобы показать нашим пользователям 48 телефонов, мы обрабатываем 400 000 предложений.

Количество обрабатываемых документов без graceful degradationКоличество обрабатываемых документов без graceful degradation

В случае с graceful degradation, когда надо уменьшить нагрузку, мы можем скомандовать: теперь обрабатывай 95% документов, а теперь 90% или 80%. Если обрабатывать 95%, то есть 400000*0.95=380 000 документов, то из них всё равно выбираются 48 лучших предложений для выдачи. И в среднем только 2 предложения будут отличаться от изначальной выдачи без снижения качества. При таком маленьком изменении большинство пользователей даже не заметят разницы.

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

Автоматизация включения механизма

Автоматизация работает за счёт постоянного мониторинга загрузки CPU. Если нагрузка становится выше 90%, автоматика начинает снижать качество. На 90% снижение небольшое, но если нагрузка продолжает расти, процент деградации повышается линейно и доходит до максимума при 100% загрузки CPU. Такой подход позволяет снижать качество минимально.

Общий алгоритм выглядит так:

При выключении ДЦ: балансеры перераспределяют запросы в оставшиеся ДЦ => нагрузка на CPU повышается => при превышении порогового значения происходит снижение качества по заданной формуле.

При включении ДЦ: балансеры перераспределяют запросы на все ДЦ => нагрузка на CPU снижается => понижение качества прекращается.

Повышение нагрузки при выключении ДЦ. Линии на верхнем графике показывают загрузку CPU в отдельных ДЦ. Нагрузка выросла с 82% до 98%. Нижний график показывает процент срезанных документов. Повышение нагрузки при выключении ДЦ. Линии на верхнем графике показывают загрузку CPU в отдельных ДЦ. Нагрузка выросла с 82% до 98%. Нижний график показывает процент срезанных документов.

Внедрение

Для внедрения мы провели несколько экспериментов и понижали качество на небольшом проценте пользователей. В течение недели мы постоянно отслеживали уменьшение нагрузки и одновременно количество переходов на магазины-партнёры. Имея на руках цифры, мы договорились с бизнесом на максимальное снижение кликов в 1% при снижении качества. Исходя из этого мы посчитали, сколько серверов можем отдать другим проектам или выключить для резерва. У нас получилось 15% всех мощностей поиска.

В конце, когда всё было готово, мы провели эксперимент с отключением дата-центра, чтобы убедиться, что всё работает как надо.

Выводы

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

Подробнее..

Чаты на вебсокетах, когда на бэкенде WAMP. Теперь про Android

13.01.2021 22:20:55 | Автор: admin

Мой коллега уже писал про наш опыт разработки чатов на вебсокетах для iOS, поэтому часть про особенности бэкенда с точки зрения клиента у нас общая. А вот реализация на Android, конечно, отличается. И ещё мне не приходилось, как в первой статье, искать библиотеку для поддержки старых версий операционной системы, потому что на Android каких-то глобальных изменений в сетевой части не было, всё работало и так.

К реализации вернёмся чуть ниже, а начнём с ответов на вопросы про бэкенд, которые появились после первой статьи: почему WAMP, какой брокер используем и некоторые другие моменты.

На время передам слово нашему бэкенд-разработчику @antoha-gs, а если хочется сразу почитать про клиент-серверное общение и декодирование, то первый раздел можно пропустить.

Что там на бэкенде

Почему WAMP. Изначально искал открытый протокол, который мог бы работать поверх WebSocket с поддержкой функционала PubSub и RPC и с потенциалом масштабирования. Лучше всего подошёл WAMP одни плюсы, разве что не нашёл реализации протокола на Java/Kotlin, которая бы меня устраивала.

Какой брокер мы используем. Продолжая предыдущий пункт, это, собственно, и послужило написанию собственной реализации протокола. Плюсы экспертиза в своём коде и гибкость, то есть при надобности всегда можно отойти от стандарта в нужную сторону. Каких-то серьёзных минусов не выявил.

К небольшим проблемам реализации проекта чатов можно отнести то, что нужно было ресёрчить и ревёрсить то, как работает реализация на Sendbird сервисе, который мы использовали. То есть какими возможностями мы там пользовались и какой дополнительный функционал был реализован поверх. Также к сложностям отнёс бы перенос данных из Sendbird в свою базу.

Ещё был такой момент в комментариях:

Правильно, что не стали использовать Socket.IO, так как рано или поздно столкнулись бы с двумя проблемами: 1) Пропуск сообщений. 2) Дублирование сообщений. WAMP к сожалению также не решает эти вопросы. Поэтому для чатов лучше использовать что-то вроде MQTT.

Насколько я могу судить, протокол не решает таких проблем магическим образом, всё упирается в реализацию. Да, на уровне протокола может поддерживаться дополнительная информация/настройки для указания уровня обслуживания (at most/at least/exactly), но ответственность за её реализацию всё равно лежит на конкретной имплементации. В нашем случае, учитывая специфику, достаточно гарантировать надёжную запись в базу и доставку на клиенты at most once, что WAMP вполне позволяет реализовать. Также он легко расширяем.

MQTT отличный протокол, никаких вопросов, но в данном сравнении у него меньше фич, чем у WAMP, которые могли бы пригодиться нам для сервиса чатов. В качестве альтернативы можно было бы рассмотреть XMPP (aka Jabber), потому что, в отличие от MQTT и WAMP, он предназначен для мессенджеров, но и там без допилов бы не обошлось. Ещё можно создать свой собственный протокол, что нередко делают в компаниях, но это, в том числе, дополнительные временные затраты.

Это были основные вопросы касательно бэкенда после предыдущей статьи, и, думаю, мы ещё вернёмся к нашей реализации в отдельном материале. А сейчас возвращаю слово Сергею.

Клиент-сервер

Начну с того, что WAMP означает для клиента.

  • В целом протокол предусматривает почти всё. Это облегчает взаимодействие разработчиков клиентской части и бэка.

  • Кодирование всех типов событий в числах (PUBLISH это 16, SUBSCRIBE 32 и так далее). Это усложняет чтение логов разработчику и QA (сразу не догадаться, что значит прилетевшее сообщение [33,11,5862354]).

  • Механизм подписок на события (например, новые сообщения в чат или обновление количества участников) реализован через получение от бэкенда уникального id подписки. Его надо где-то хранить и ни в коем случае не терять во избежание утечек. Как это сделано (было бы сильно проще и подписываться и отписываться просто по id чата):client подписываемся на новые сообщения в чате [32,18,{},"co.fun.chat.testChatId"]backend [33,18,5868752 (id подписки)]client после выхода из чата отписываемся по id [34,20,5868752]

Для работы с сокетом использовали OkHttp (стильно, надёжно, современно, реализация ping-pong таймаутов из коробки) и RxJava, потому что сама концепция чата практически идеальный пример того самого event-based programming, ради которого Rx, в общем, и задумывался.

Теперь рассмотрим пример коннекта к серверу, использующему WAMP-протокол через OkHttpClient:

val request = Request.Builder()    .url(ChatsConfig.SOCKETURL)    .addHeader("Connection", "Upgrade")    .addHeader("Sec-WebSocket-Protocol", "wamp.json")    .addHeader("Authorization", authToken)    .build()val listener = ChatWebSocketListener()webSocket = okHttpClient.newWebSocket(request, listener)

Пример реализации ChatWebSocketListener:

private inner class ChatWebSocketListener : WebSocketListener() {override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { connectionStatusSubject.onNext(ChatConnectionStatuses.NOTCONNECTED) //subject, оповещающий пользователей о состоянии коннекта (в UI нужен для отображения лоадеров, оффлайн-стейтов и так далее)}override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { webSocket.close(1000, null)}override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { onConnectionError("${t.message} ${response?.body}")}override fun onMessage(webSocket: WebSocket, text: String) { socketMessagesSubject.onNext(serverMessageFactory.processMessage(text)) //subject, через который идут все сообщения, которые в дальнейшем фильтруются для конкретных получателей (см. ниже)}override fun onOpen(webSocket: WebSocket, response: Response) { authorize() }}

Здесь мы видим, что все сообщения от сокета приходят в виде обычного String, представляющего собой JSON, закодированный по правилам WAMP протокола и имеющий структуру:

[ResultCode: Int, RequestId: Long, ArgumentsMap: JsonObject ]

Например:

[50, 7, {"type":100, "chats":[список чатов]}]

Декодирование и отправка сообщений

Для декодинга сообщений в объекты мы использовали библиотеку Gson. Все модели ответа отписываются обычными data-классами вида:

@DontObfuscatedata class ChatListResponse(@SerializedName("chats") val chatList: List<Chat>)

А декодирование происходит с помощью следующего кода:

private fun chatListUpdateInternal(jsonChatsResponse: JSONObject):ChatsListUpdatesEvent { return gson.fromJson(jsonChatsResponse.toString(), ChatsListUpdatesEvent::class.java)}

Теперь рассмотрим базовый пример отправки сообщения по сокету. Для удобства мы сделали обёртку для всех базовых типов WAMP сообщений:

sealed class WampMessage { class BaseMessage(val wampId: Int, val seq: Long, val jsonData: JSONArray) : WampMessage()  class ErrorMessage(val procedureId: Int, val seq: Long, val jsonData: JSONArray) : WampMessage() object WelcomeMessage : WampMessage() class AbortMessage(val jsonData: JSONArray) : WampMessage()}

А также добавили фабрику для формирования этих сообщений:

fun getCallMessage(rpc: String,         options: Map<String, Any> = emptyMap(),         arguments: List<Any?> = emptyList(),         argumentsDict: Map<String, Any?> = emptyMap()):WampMessage.BaseMessage { //[CALL, Request|id, Options|dict, Procedure|uri, Arguments|list] val seq = nextSeq.getAndIncrement() return WampMessage.BaseMessage(WAMP.MessageIds.CALL,               seq,               JSONArray(listOfNotNull(WAMP.MessageIds.CALL,               seq,               options,               rpc,               arguments,               argumentsDict)))}

Пример отправки сообщений:

val messages: Observable<WampMessage> = socketMessagesSubjectfun sendMessage(msgToSend: WampMessage.BaseMessage): Observable<WampMessage> { return messages.filter {   it is WampMessage.BaseMessage && it.seq == msgToSend.seq}    .take(1)    .doOnSubscribe {     webSocket.send(msgToSend.jsonData.toString())    }}

Сопоставление отправленного сообщения и ответа на него в WAMP происходит с помощью уникального идентификатора seq, отправляемого клиентом, который потом кладётся в ответ.

В клиенте генерация идентификатора делается следующим образом:

companion object { private val nextSeq: AtomicLong = AtomicLong(1)}fun getNextSeq() = nextSeq.getAndIncrement()

Взаимодействие с WAMP Subscriptions

Подписки в протоколе WAMP концепт, по которому подписчик (клиент) подписывается на какие-либо события, приходящие от бэкенда. В нашей реализации мы использовали:

  • обновление списка чатов;

  • новые сообщения в конкретном чате;

  • изменение онлайн-статуса собеседника;

  • изменение в составе участников чата;

  • смена роли юзера (например, когда его назначают модератором);

  • и так далее.

Клиент сообщает серверу о желании получать события с помощью следующего сообщения:

[SUBSCRIBE: Int, RequestId: Long, Options: Map, Topic: String]

Где topic это скоуп событий, которые нужны подписчику.

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

fun getSubscribeMessage(topic: String, options: Map<String, Any> = emptyMap()): WampMessage.BaseMessage { val seq = nextSeq.getAndIncrement() return WampMessage.BaseMessage(WAMP.MessageIds.SUBSCRIBE,                 seq,                JSONArray(listOfNotNull(WAMP.MessageIds.SUBSCRIBE,                                seq,                                options,                                topic)))}

Разумеется, при выходе с экрана (например, списка чатов), необходимо соответствующую подписку корректно отменять. И вот тут выявляется одно из свойств протокола WAMP: при отправке subscribe-сообщения бэкенд возвращает числовой id подписки, и выходит, что отписаться от конкретного топика нельзя нужно запоминать и хранить этот id, чтобы использовать его при необходимости.

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

private val subscriptionsMap = ArrayMap<String, Long>()private fun getBaseSubscription(topic: String): Observable<WampMessage> { val msg = wampClientMessageFactory.getSubscribeMessage(topic) return send(msg).map {   val subscriptionId = converter.getSubscriptionId((it.asBaseMessage()).jsonData)   subscriptionsMap[topic] = subscriptionId   subscriptionId}    .switchMap { subscriptionId ->      chatClient.messages.filter {       it.isMessageFromSubscription(subscriptionId)     }    }}

Так клиент ничего не будет знать об id, и для отписки ему будет достаточно указать имя подписки, которую необходимо отменить:

fun unsubscribeFromTopic(topic: String) { if (!subscriptionsMap.contains(topic)) {    return } val msg = wampClientMessageFactory.getUnsubscribeMessage(subscriptionsMap[topic]) send(msg, true).exSubscribe() subscriptionsMap.remove(topic)}

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

Подробнее..

Один день удаленного тимлида на бэкенде

13.10.2020 16:15:52 | Автор: admin

Привет, Хабр! Я - бэкенд разработчик на удаленке из Максилекта. Сейчас я работаю на внутреннем проекте компании, который мы реализуем совместно с зарубежным партнером. На собственных проектах с высокими нагрузками и ограниченными серверными ресурсами бывает всякое. Иногда у нас идет размеренная работа, а в другой момент мы целый день горим в пожарах на продакшене. Но в отличие от многих других проектов, здесь есть свобода выбора архитектуры, а вся ответственность за принятые технические решения на тебе. Каждое твое улучшение может привести к тому, что для обработки входящего трафика потребуется на один сервер больше или, наоборот, на один меньше. Это и воодушевляет, и влияет на всю твою работу, вплоть до распорядка дня. Продолжая рассказ своего коллеги с фронта, в этой статье я расскажу, как выглядит мой рабочий день.

Мое рабочее местоМое рабочее место

Вряд ли мое расписание можно назвать стандартным. Я - тимлид, но не вижу себя в будущем управленцем. В свое время я уже руководил Java-разработкой в одном из офисов крупного телекома, но понял, что мне интереснее программировать. Больше всего на свете мне нравится решать технические задачи. И согласился на статус тимлида в Максилекте я только потому, что в этом качестве можно сильнее влиять на принятие технических решений. Рядовой разработчик, конечно, может высказывать мнение, но конечный выбор будет не за ним. В этом смысле у него связаны руки. А тимлид обладает большей свободой действий, и мне это нравится. Наблюдая, как развивается наш проект, я захотел решить накопившиеся проблемы - люблю делать хорошие системы.

Я уже упомянул, что не планирую развиваться дальше на управляющем поприще. Чем дальше ты идешь, тем меньше времени тратишь на то, что наиболее интересно. А я не вижу себя ни в какой другой роли. Да и на рынке труда в статусе сениор-разработчика из региона чувствую себя более уверенно: даже в Краснодаре в офисе можно быстро найти работу, не говоря уже о множестве предложений на удаленке. Руководителям в этом смысле сложнее. Так что я выполняю задачи тимлида, но стараюсь сохранить максимальную связь с разработкой.

7:00

Я - жаворонок, просыпаюсь вместе с солнцем часов в 6 или 7 утра.

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

10:00

В 10 утра мы проводим дейли с командой. Мы собираемся максимум на 15 минут. Если такая встреча затягивается, участники начинают отвлекаться, поэтому я сознательно останавливаю все затягивающиеся обсуждения. Под такие темы лучше запланировать отдельную встречу, позвав на нее только тех, кого этот вопрос касается непосредственно. Людей в команде много, у всех разный профиль, так что это сильно экономит время.

На дейли мы рассказываем о том, кто что делал вчера, с какими проблемами столкнулся, чем будет заниматься сегодня. Первым обычно выступаю я - доношу последние новости о проекте, например что происходит на продакшене. Команда решает сложные задачи и не всегда видит результат своей работы, так что я стараюсь это исправить. Допустим, в течение дня мы запускаем Clickhouse на новых серверах, а с утра я рассказываю о том, сколько процентов нагрузки на процессор ему требуется в реальной эксплуатации, сколько тысяч сообщений в секунду он обрабатывает. Рассказываю и о багах - например, совсем недавно у нас были проблемы с Kafka (мы уперлись в баг самой Kafka), так что на дейли я не мог не предупредить коллег о том, как этот баг проявляется.

Если параллельно с деятельностью тимлида я успеваю решить какие-то задачи по разработке, то говорю и о них. Ну а после этого передаю слово коллегам.

10:15

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

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

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

Накануне планирования я общаюсь с зарубежным партнером, чтобы выявить его основные пожелания. Кроме того мы достаем задачи из бэклога. В ходе планирования все эти задачи выносятся на общее обсуждение. Обычно задачи к нам приходят на английском с пояснениями на языке бизнеса, я же в ходе обсуждения стараюсь объяснить на русском, чего же от нас хотят. Эти пожелания мы декомпозируем, оцениваем и смотрим, уместятся ли все они в ближайший спринт. Если на этой стадии выясняется, что мы набрали слишком много задач, подзадачи с наименьшим приоритетом отправляются обратно в бэклог, а я впоследствии согласовываю это с партнерами.

13:00

Я не особо требователен к условиям работы и графику жизни. У меня нет жесткого обеденного времени или ритуала, который я бы использовал, чтобы разгрузить голову. Но летом в обеденное время мы с женой иногда гуляем по побережью Азовского моря. У нас есть небольшая квартирка на берегу, куда мы приезжаем летом. Иногда в середине дня мы идем по берегу обедать в столовую - получается отличная прогулка. Зимой я работаю из Краснодара, там таких возможностей нет.

14:00

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

Хотя больше всего я люблю решать технические задачи, в статусе тимлида я очень редко сижу и что-то программирую. Обычно весь день занимаюсь решением разного рода вопросов - от установки конкретных версий на тестовый стенд, до внедрения новых технологий. Это огромный спектр задач. К примеру, начали мы вводить testcontainers - подключили библиотеку. Локально у разработчиков все работает, а с GitLab возникли проблемы (когда мы пушим наш код в GitLab, он тоже гоняет тесты, и там они не заработали). Разработчик сам не смог решить проблему из-за отсутствия доступа к конфигурации GitLab, так что тут пришлось подключиться мне. У меня доступа тоже не было, но с помощью коллег вопрос решили. И такие задачи заполняют почти целый день.

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

17:00

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

19:00

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

22:00

Поскольку встаю я рано, вечер у меня получается коротким - к 10 часам обычно я уже сплю, чтобы с утра снова вернуться к интересным рабочим задачам. Меня это воодушевляет. Например, как раз сейчас мы внедряем ClickHouse. В этой системе многие вещи сделаны нестандартно, поэтому с ней интересно работать. Наш кейс использования аналитической базы данных практически идеально на нее ложится - как будто ClickHouse делали под нас. Такие задачи поддерживают мою уверенность в том, что я нахожусь на правильном месте.

Автор статьи: Андрей Буров, Максилект.

P.S. Мы публикуем наши статьи на нескольких площадках Рунета. Подписывайтесь на наши страницы в VK, FB, Instagram или Telegram-канал, чтобы узнавать обо всех наших публикациях и других новостях компании Maxilect.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru