Мок-собеседование iOS разработчика

Подготовка к собеседованию на iOS Developer

Транскрипция видео:

  • Михаил нас покинул не [музыка] выдержал Итак всем привет Добро пожаловать на канал аёс такой Меня зовут Екатерина ботева Сегодня у нас очень интересный выпуск про Моко собеседования нам было не просто выцепить дорогих коллег в этот предновогодние дни когда горят дедлайны когда все у пытаются успеть в кот Фриз и сегодня смелый Владимир Алексеев согласился поучаствовать в Мом Собес в качестве собеседуем э его сегодня будет пытать Михаил Назаров А я надеюсь вы поставите нам лайки Напишите комментарии а

    00:00:00 - 00:01:25

  • Напишите лучи поддержки Владимиру потому что это очень тяжело публично пройти роль собеседуем мого в интервью потом остаться на тубе навеки и в общем я надеюсь вы будете к нему добры сни сходить потому что это просто десятикратное А я тем временем передаю слово Михаилу Да всем привет А честно говоря у нас пока нет особого плана Поэтому я думаю что мы просто будем идти как идётся Да обсудим сначала какие-то базовые основы Свифта потом может быть чуть-чуть поговорим про точку Может быть чуть-чуть поговорим про UI может быть

    00:00:51 - 00:02:15

  • даже затронем какие-то платформенные особенности вот ну Наверное чтобы это всё-таки было похоже на Настоящее интервью Владимир Давай ты как обычно на интервью спрашивает Расскажите о себе вкратце Чем занимались на предыдущих проектах пожалуйста а да Всем привет Меня зовут Вова а у меня около 3 лет коммерческий опыта коммерческой разработки побывал на многих проектах начиная от каких-то галер заканчивая большими бигтех нашими русскими А первое место работы у меня была так галера все мы это проходили все Мы это

    00:01:33 - 00:02:50

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

    00:02:13 - 00:03:24

  • инжинеринг и везде где можно было всё усложнить они всё усложнили Viper состоит машиной поначалу мне ещё неопытному зелёному было очень весело но опыта под набрался понял как там работают протоколы всё Т такое А в принципе интересно сейчас не буду говорить Где я сейчас работаю но большая русская компания Все вы её знаете Все вы там заказываете Пока как-то Так расскажи пожалуйста про последнее место работы какие непосредственно у тебя обязанности про Команду Расскажи Сколько человек в команде как построены процессы

    00:02:49 - 00:04:05

  • А ну вот расскажу тогда про вот предпоследнее место работы это была компания у нас был проект проект был интересный в команде Нас было двое iOS разработчиков Все мы мы вдвоём пришли после того как ушли предыдущие два iOS разработчика нам было немножко тяжеловато поначалу потому что нас никто не зан борди а проект очень нелёгкий был а задачи у нас ставились нашим условным тимлидом который у нас был третий но не писал потому что это было Out ST и как бы он просто менторинг нека проводили кот ревью я там

    00:03:26 - 00:04:45

  • выступил за то что начать проводить ретроспективы всякие артефакты скрама было интересно на этом месте работы я познакомился с вот всеми вот этими процессами научился строить их самость так можно сказать а потом когда я уже уходил к нам пришёл новичок третьим получается Он был что-то около Ну jor to midle было интересно менторинг учишь кого-то другому было интересно ушёл потому что проект закончился а на другой переходить мне немножко не хотелось потому что проект на который предложили был мне абсолютно не интерес хотелось

    00:04:14 - 00:05:45

  • расти в другом направлении и с другими технологиями Окей спасибо ну я предлагаю переходить тогда к технической части Возможно мы будем накидывать какие-то задачки Я вот сейчас Поша экран всё замечательно Да вот ты получается зашёл в Яндекс комнату у меня нет какого-то определённого списка задач я просто буду накидывать и мы от этого будем наверное что-то обсуждать Ну вот давай начнём с такого кода А вот пока можешь его Изучить и Если тебя всё устраивает то тогда я задам вопрос Если вдруг сразу появились какие-то вопросы ты можешь их

    00:05:00 - 00:06:39

  • задать Да я даже знаю какой будет следующий вопрос поэтому задавай Ну мой вопрос всё ли тут в порядке Нет это такой базовый вопрос с которого всё начинается функция должна быть поме потому что это у нас структура и чтобы менять её свойства внутри мы должны пометить её как тин потому что ну Это обусловлено её семантикой её расположением в стеке и её типом Давай попробуем что вообще значит это тенг что происходит у нас там вот на пятой строчке Да вообще что что вообще происходит в этой функции А да а у нас value typ как он работает

    00:05:51 - 00:07:26

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

    00:06:44 - 00:08:05

  • предыдущего бы объединили бы их со свойствами которые внутри и создалась бы уже новая структура которая бы там пере записалась как-то так а вот ты сказал такие слова как стек А что это такое вообще стек И какое он имеет отношение к структурам У нас есть два места хранилища от структуры классов это ку там есть на самом деле ещё несколько но пока не об этоже для располагать val типа зачастую Конечно есть множество исключений которые потом могу Если что назвать но основная задача стека - это расположить

    00:07:26 - 00:08:43

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

    00:08:08 - 00:09:33

  • меняется динамически в зависимости от того На каком элементе мы и вот именно для этого мы должны знать разме элементов стека для того чтобы как бы Вычитать и прибавлять вот этот память к к второму указателю который отвечает за то За то на каком элементе мы сейчас находимся Угу угу ну О'кей Ну вот смотри просто я вот пытаюсь понять вот допустим Давай напишем такой код чтобы компилятор не ругался воображаю Угу Ну во-первых валиден ли он Могу ли я так написать давай начнём с этого кстати не помню Можно ли сделать так в свифте в

    00:08:51 - 00:10:26

  • каком-нибудь помню на питоне описал там можно было так сделать в свифте кажется нельзя объявить функцию внутри функцию Но кажется Ну не в этом сути или в этом Ну хорошо я думаю что всё-таки можно но суть действительно не в этом а давай мы сделаем вот так тогда угу чтобы мы сейчас не упёрлись в Этот спор а не надо Это лишнее становись пока не было такого за Вот мне интересно а вот у меня вызывается функция ABC внутри в неё вызывается функция Давай назовём её А1 э точнее Вот это будет А1 это будет А2 это будет

    00:10:02 - 00:11:41

  • А3 здесь получается А1 А2 Дасти так ИТ А2 А2 А3 и вот здесь где-нибудь вызывается А1 вот у меня вызывается А1 внутри у неё вызывается А2 внутри А2 вызывается А3 угу вот вопрос А каким образом поток выполнения вернётся из функции А2 А3 функцию А2 потом из функции А2 функцию о а потом с функции А1 вообще вот сюда вот куда-нибудь на двадцать четвёртую строчку как это произойдёт Угу А ну он у нас в любом случае да вернётся потому что третья функция ничего не вызывает как у нас работает стек внутри функции

    00:11:04 - 00:12:41

  • когда мы составим функцию допустим Будем рассматривать А2 вот мы зашли в четырнадцатую строку у нас создался условный стек в котором Ну начались размещать элементы и переменная B добавилась у нас в этот стек когда мы вызвали функцию А2 Мы создали другой стек зайдя в её тело а то бишь вообще если вдаваться немножко в историю Зачем нужен был придумать стек одна из его причин это как раз-таки для этого чтобы мы могли последовательно идти по строчкам кода если мы провали в какую-то функцию мы сможем создать

    00:11:53 - 00:13:07

  • условно новый стек выполнить какие-то там дела которые будут в этой функции и потом условно вернуться назад к нашему выполнению той предыдущей функции Откуда мы её вызвали А и получается Здесь Ну будет создано три новых стека Когда наш код дойдёт до выполнения каждой функции угу а а сколько вообще стеков тогда в программе существует как бы вот вопрос такой если у нас на каждый вызов новой функции создаётся новый стек не их может быть бесконечным мм Ну а как а както как они тогда между собой функционируют мне вот не очень

    00:12:29 - 00:14:02

  • понятно как мы из стека А попадаем в стек б а кстати вот это О'кей интересный вопрос Нет я точно уверен что он не один но как Они между собой коммуницируют вопрос интересный можно бы в даться Окей Ладно рекурсия тут ни при чём кстати ещё одно необходимость так это рекурсия возможности Ну хорошо давай попробуем чуть-чуть с другой стороны зайти Вот ты ещё сказал что что есть какие-то исключения когда там структуры Бут располагаться не на стеке Кстати а где и в каких случаях можеш Да рассказать вот допустим я создал здесь

    00:13:19 - 00:15:00

  • это вот мой Фрут Давай вот так вот вопрос вот переменная D расположится на стеке или не на стеке в данном случае да потому что здесь ну нет никаких исключений Какие вообще могут быть исключения это наша структура очень большая потому что в принципе стек Ну не резиновый у него есть какое-то ограничение по памяти если мы там храним в нашей структуре миллион картинок то очевидно оно всё переедет на кучу потом если мы не можем На момент компиляции заранее посчитать размер нашего нашей структуры допустим если там есть

    00:14:11 - 00:15:34

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

    00:14:55 - 00:16:23

  • Угу А так а сам Фрут Это что было в этом Это был протокол Да ка Это протокол Да а что бы поменялось я вот не очень понимаю Вот в чём разница между тем что мы положили просто LD равно FR и там или написали протокол В чём что что-то поменялось А здесь мы просто в стеке храним нашу наш фрукт А если был бы протокол то есть мы от переменной D ожидали бы протокольный тип То бишь под капотом бы в игру вступал экзистенциальный контейнер и у нас бы хранилась как бы как бы ссылка не на сам фрукт А ссылка на экзистенциальный

    00:15:42 - 00:16:56

  • контейнер который уже хранит э в своём ввт и пвт всю вот эту реализацию фрукта который есть в протоколе у ввт пвт - Это что такое Это протокол witness Table и value with Table рассказать А вопрос я вот не очень понял то есть у него и то и то будет или как а Да у него будет и то и то протокол witness Table будет хранить ссылки на реализацию наших методов которые объявлены в протоколе в ввт а vtn Table уже будет хранить конкретную реализацию наших протоколов Но это конечно же если мы не сможем поместить в три машинных слова в value

    00:16:20 - 00:17:53

  • буфера и Да окей Окей Ну кажется кажется кажется что мы пришли к тому чтобы поговорить о диспетчеризации Угу Раз уж ты сам зашёл в эту тему Давай о ней поговорим а вот мне что интересно вот мы делаем такую штуку как Final вот мы Зачем делаем мы это на самом деле для двух вещей Первое это чтобы сделать диспетчеризацию статической а второе это такие правила хорошего кода чтобы кто-нибудь другой в нашем проекте случайно не захотел бы от наследоваться от нашего фрукта чтобы это вых саэ борики Final представляется для всех

    00:17:07 - 00:18:46

  • классов автоматически если не используется Никакое наследование так угу А ну я бы наверное тут уточнил что это зависит от параметров твоей сборки да Вот потому что если ты как-то каким-то кастомным образом собираешь как собственно и собираются большинство крупных проектов то там может быть всё не так радужно Окей Вот ты сказал что будет статическая диспетчеризация а ну а что такое вообще диспетчеризация в таком случае давай так тогда задам вопрос определение диспечер - это то как мы говорим программе К какой области в

    00:18:01 - 00:19:26

  • памяти нам надо обратиться чтобы найти метод Метод либо переменную что-то найти в памяти могу могу начать рассказывать какие виды печери зации есть Ну вот смотри вот допустим у меня есть протокол а протокол Apple назовём Apple protocol Угу а аа и у меня есть структура Apple которая подписывается на этот Apple прокол в этой структуре я реализую функцию it Print и рак я пишу extension для протокола [музыка] а тоже в нём реализую функцию X [музыка] Угу и создаю переменную типа Apple прокол в которую кладу Apple и вызываю

    00:18:44 - 00:21:02

  • функцию и что напечатается А так Здесь ключевое отличие что у нас в самом протоколе ключевой момент что у нас в самом протоколе не объявлена эта функция и поэтому здесь у нас у нас вообще здесь структура да как вообще здесь всё будет работать а так как у нас здесь не не напечатана эта функция у нас в протокол VN Table в экзистенциальном типе нет этого объявления А значит когда мы будем обращаться к этому типу мы не найдём его в прокол witness Table Значит мы провалився к дефолтной реализации и получается вы видится it

    00:20:07 - 00:21:46

  • протокол Я даже напечатаю здесь ну вот я вот не очень понял а так какая будет диспетчеризация по итогу здесь будет статическая протокольная диспетчеризация Ну статическая диспетчеризация вот из этого метод да Угу О'кей А давай Да теперь сделаем класс что-то поменяется а нет ничего не поменяется также будет статическая потому что вы видится опять же и протокол Хорошо а теперь я здесь сделаю класс Угу Это наследование Ага О'кей а от наследовать тогда здесь будет кстати вот это интересный момент м

    00:20:57 - 00:22:34

  • [музыка] по идее Ну так как здесь нет нет а ждём а ожидаем мы тип родительский вот здесь [музыка] Ага здесь будет получается потому что ция у нас будет ВС будет замечательно здесь мы уже работаем не с экзистенциалистов чему как вообще работает диспетчеризация внутри с наследованием если мы находим этот метод У нашего ребёнка всё замечательно всё замечательно это мы по Даше кго дите по мед в родительской таблице здесь мы этот метод не нашли Ну а здесь мы остановились ещё на том этапе что мы нашли этот метод у ребёнка поэтому всё

    00:22:01 - 00:23:45

  • будет окей и будет [музыка] Ирак я вот не совсем а получается мы любые методы идём искать у ребёнка Ну смотря что мы здесь ожидаем если мы вот здесь ну ну может у нас есть какое-то ключевое слово которое подразумевает что вот этот метод он как бы есть у родителя есть у ребёнка А ну да очевидно орай пере определённый метод здесь его не было О'кей Тогда вопрос возвращается обратно всё-таки что будет происходить Угу а хорошо окей здесь мы Нет не нашли этот метод и так как мы ожидаем тип родительский

    00:23:07 - 00:25:03

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

    00:24:16 - 00:25:52

  • стека каждый раз создаёт и естественно то что я хотел от него получить это то что на самом деле стек - это не что иное как связанный список у которого собственно есть указатель на тот предыдущий элемент это когда мы вытаскиваем мы как бы достаём то что было то что было до него То есть когда там если мы возьмём ассемблерные код то когда вызывается у метода то строчка выполнения Возвращается на тот из которого был вызван код но к сожалению я не получил Это ответ опять же тут вопрос в том нужно ли это разработчику нет но

    00:25:26 - 00:26:37

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

    00:26:02 - 00:27:23

  • наверно попробуем поговорить про так да я слышу вот мне вот у меня есть очень интересная тема которую можно обсудить [музыка] аэ Давай наверное попробуем написать Вот такую задачку Аа Допустим Допустим у меня есть а метод по которому я могу получить Ну что-то давайте какую-нибудь единицу чего-то адвертайзинг да одно объявление то есть Каким образом это будет выглядеть там Get adverb ID какой-то вот каким-то образом он выполняется сечас интересно каким а но я хочу написать метод Get adverbs который

    00:26:52 - 00:29:14

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

    00:28:39 - 00:30:16

  • диспатч группу Ну пусть мы её где-нибудь создадим здесь Если слишком громко Бут звуки клавиатуры Говорите я буду что-нибудь с этим делать а пока всё хорошо создали группу здесь создадим сразу War где мы будем хранить наши наш массив а вербов начала он будет пустым и для начала пробежимся по айдини кам так вот здесь ди пусть будет для удобства ID и ID in здесь у нас мы будем здесь входить в нашу группу п Enter Тош будем прибавлять счётчик на на единичку то мы будем загружать наш нашу рекламу и [музыка]

    00:29:34 - 00:31:32

  • ID ID здесь у нас будет Так Это comp тут лта нет тогда здесь будет нам возвращаться и мы добавим в наш наша реклама которая нам пришла и покинем группу То бишь Уменьши счётчик на единичку И когда у нас счётчик станет опять ноль мы должны как-то выполнить какое-то действие напишем Group Будем считать что мы отдаём на M поток не помню как семантику этой функции по-моему Здесь пишется Ну в данном случае мы Лекси проверяем поэтому О'кей это не имеет значения и здесь мы через completion отдадим наш Угу Ну это самая простая такая

    00:30:53 - 00:33:04

  • реализация у всё замечательно но приложение падает может быть это связано с с Не потока безопасным а окей Возможно у нас будет ещё где-то память здесь течь смотря где у нас будет этот метод находиться и где у нас будет наша группа находиться Какие тут ещё проблемы есть это что запись в перенести просто внутрь метода на самом деле не сильно есть смысл находиться вне его [музыка] Но вот про поток и Безопасность это очень интересный вопрос Вообще в свифте коллекции потока безопасны или как в свифте у нас коллекции на самом деле под

    00:32:19 - 00:33:53

  • капотом хоть Мы все знаем Все мы слышали что коллекция под капотом это tye апе Казалось бы потока безопасная Но на самом деле чучуть об мав использует буфер который имеет ферен семантику и все его вообще элементы будут храняться храниться на куче А ну и работать как бы По ссылкам А это не совсем поток и безопасно Поэтому нам надо использовать какие-то инструменты синхронизации здесь самое что можно такое лёгкое - это наш мукс пишем его Ну мы же хотим чтобы код работал конечно замечательно тея программа падает приходи что-то

    00:33:10 - 00:34:50

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

    00:34:02 - 00:35:27

  • и сделаем это перед добавлением мы залом и после добавления мы UN всё будет замечательно Да всё стало замечательно но к сожалению мы как бы показываем прок говорит Это что за ерунда типа у нас же вот мы же у нас же порядок ашнико он вот такой а почему у вас данные вообще каком-то порядке то отображается ребят что происходит Угу Ну по идее да Потому что эти запросы все асинхронные будут они выполняться где-то в другом месте и в каком они порядке придут мы не знаем порядок будет Случайный Значит надо придумать какой-то инструмент

    00:34:53 - 00:36:40

  • синхронизации как это всё разрулить Угу Окей А поначалу возможно напишу не самым красивым образом в плане кода но потом если что как-то отредактировать словарик который мы создадим типа он будет это ашки это наши айдини стати даже пусть будет ны изначально проставить порядок Потому что изначально оно приходит отсортировано Ну в том порядке который нам нужен значит этот порядок нам надо как-нибудь запомнить м сделаем ещё один проход по этому массиву [музыка] м все будем и создадим здесь тчик акаунт я уверен что без него можно

    00:35:46 - 00:37:34

  • обойтись но поначалу сделаем не максимально красиво чтобы чтобы всё было круто будем добавлять по нашему аккаунту Насть будет у нас ключом добавлять значение айдини и на каждой следующей итерации мы будем акаунт плюс равно о чтобы они были последовательны на самом деле можно было бы через сделать чтобы не плодить счётчики Но пусть пока будет так а Итого мы получили массив он у нас будет словаре у нас будет выглядеть вот так то шь для наглядности сделаю Ну пусть будет ID 11 на два вот так Где это порядок А это сам

    00:37:02 - 00:39:01

  • наш айдини в конце нам надо это как-то соотнести с нашим результатом который можно это сделать здесь можно сделать для красоты отдельную функцию которая это всё разрулит но думаю сейчас это не самое главное Может может как-то можно скажем так уменьшить количество огородов Может когда можно сразу записывать на нужную позицию сразу на нужную позицию Да можно я здесь сделаю сразу тогда прямо в этом цикле и пому возвращает сначала индекс а потом элемент и тогда в принципе мы в любом случае будем работать никуда не деться почему она не

    00:38:13 - 00:40:12

  • комментирует ладно уберём И мы сможем в наш словарь по нашему ключу который будет индекс добавлять значение который мы получили вот здесь то бишь значение арба А и В целом Вот это нам нужен Словарь если обходиться без словаря может мы можем как-то сразу на нужное место в массив писать Мы конечно можем через какие-то инсерты это сделать но это звучит как не очень идеальное решение для понимания этого кода разработчиком это будет чуть посложнее писать по скорости и по памяти это будет абсолютно так же потому что мы будем

    00:39:29 - 00:41:11

  • тоже много времени терять на то что определить на какой позиции и куча бизнес логики я бы на самом деле оставил со словарём Ну хорошо Давай закончим тогда давай закончим Ну в смысле закончи свой кусок Угу Да вот это тогда мы пока закомментировать на выходе мы получаем словари с Вот примерно такой семантики м м и в колине мы отдаём отдадим dict sorted м очень не уверен что мы можем так написать Хотя нет кстати по-моему можем Я кстати сегодня по-моему также писал в Swift U сортировать их в for Ладно сделаем мы

    00:40:32 - 00:42:18

  • это доллар ноль [музыка] точка меньше дол но доллар 1 токе без подсказок компилятора не смогу сказать какой здесь тип будет но если здесь всё ещё будет тип словаря то можем сделать как-нибудь так хотя это звучит очень неправдоподобно потому что словарь неупорядоченный в отличие от массива но я сегодня вот так писал я не знаю как это работает под капотом и какой тип у нас здесь вернётся но я знаю что о на сработает Я сегодня такое писал Угу Ну возникает на самом деле Да вопрос в плане того что вернуть то мы должны в любом случае не

    00:41:48 - 00:43:30

  • словарь вернуть мы должны массив И массив ОТВ а пока что я не вижу чтобы ты воз Ну чтобы ты не возвращал это точно не массив от А у нас здесь будет да да да И мы это сможем спить к если у нас всё-таки здесь будет массив то мы это спим к доллар но точ могли написать е один слова чтобы ещ бы Один массив пробежаться бы по вот этому Дик чтобы сделать всё по красоте без этой всей функциональни но синтаксис кажется не самое главное Да я предлагаю прерваться тоже дать обратную связь и всё я замутил окей да Ну в целом в целом всё

    00:42:50 - 00:44:43

  • очень неплохо задачку решил очевидный мину то есть буквально каждый этап пришлось проговаривать то есть почему-то сначала не было известно Видимо что коллекции не потока безопасны Вот это как-то в процессе всё выяснять Вот это наверное такой момент который именно от сеньора хочется чтобы он увидел ну то есть от сеньора ты не хочешь чтобы ты ему рассказывал как решать задачи хочется чтобы он тебе рассказывал как реша более самостоятельно Конечно да Когда жм э сказки это больше уже похоже Ну на такого там в сторону Джуна вот а теперь

    00:43:52 - 00:45:14

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

    00:44:33 - 00:45:45

  • очень плохо Давайте дальше да Всё теперь я слышу А да Значит мы поговорили чуть-чуть про язык поговорили чуть-чуть мы можем пойти в UI поговорить чуть про UI и Наверное мы так и сделаем да давай Наверное мы поговорим про UI а потом возможно если у нас ещё останется какое-то время мы поговорим про платформу что хочется поговорить про UI Ну вот вопрос который волнует меня больше всего Вот смотри у меня есть какой-то внутри приложения таймер и [музыка] он тикает меня на экране часики Угу А на этом же экране скролл И почему-то

    00:45:09 - 00:47:00

  • как только я начинаю скролить часики перестают тикать в чём проблема а кстати я знаю ответ на этот вопрос я в реальном бою чиню такую штуку А когда мы создаём таймер если мы говорим про UI Kit А у него есть свойства а нуте при создании мы мы выбираем что-что сейчас я выключу демонстрацию пока она нам не нужна когда мы создаём таймер Мы выбираем На каком режим лупа он будет работать таймеры Если не ошибаюсь там есть дефолт и comeon дефолтный Ну дефолтный а comeon - это режим ран лупа который объединяет

    00:46:14 - 00:47:37

  • два режима то быш дефолтный и трекинг А И когда вот в чём состояла наша проблема то что таймер был в на дефолтном моде а и когда мы активно листа наш скролл то мей поток переводил наш режим лупа в UI трекинг то всё было направлено на то чтобы трекать наш UI изменение нашего юя и у таймера не было возможности корректно отрабатывать И как мы это бы почи сделали бы ему Мод который объединял бы трен и дел Угу Как хорошо тогда меня интересует вот такой вопрос Вот смотри у меня есть экран с какими-то

    00:46:55 - 00:48:33

  • обновляю данными по подписке Угу И я хочу понять В какой момент мне стоит подписываться А в какой момент стоит отписываться от обновления данных если мы говорим про Где бы ты в каких бы методах жизненного цикла ты бы поместил подписку В каких в каком отписку если с учётом того что этот экран может появ ИМХО то подписку Я бы наверно сделал где-нибудь Ну кстати у нас есть два способа Где мы можем это сделать либо во и в какого-нибудь либо от того насколько нам насколько там динамические данные насколько там

    00:47:44 - 00:49:31

  • динамически сложные подписки можно делать в принципе и так так второй способ во VI во VI плох тем что не сразу может подписка отработать не сразу мы можем подписаться и какие-то миллисекунды мы можем терять первый способ наверно плох тем что если у нас не отработает у нас где-то память поте подписка будет жить долго и мы можем Нет ну новые подписки мы не наладим потому что в принципе отработает один раз кстати есть случаи когда он отработает несколько раз Ну два таких способа оба кажутся возможными Ну да смотри Давай тогда

    00:49:00 - 00:50:24

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

    00:49:48 - 00:51:01

  • просто нет никакого смысла Вот соответственно вот в таком случае где мы будем подписываться и где отписываться но опять же Нана следующий релевантный жизненный цикл Мета жизненного цикла это раньше в свифте была такая небольшая особенность что мог вызываться несколько раз потому что у нас есть VI и VI unload Но кажется если это наш штаб бар то вряд ли будут какие-то очень необычные ивенты происходить поэтому мы сможем подписаться вде и спокойно жить Угу а окей мы подписались в Но тогда получается у нас Данные постоянно

    00:50:24 - 00:52:02

  • обновляются А мы хотим подписку остановить когда пользователь экран не видит Ага Окей я тогда делаем во View Will и во VI и во View disar Угу чтобы когда мы уходим с этого экрана там никакие события не прилетали Угу О'кей Хорошо а теперь мы допустим что это у нас не Tab viw А это презентует вот в данном случае что-то поменяется а кажется можно сделать здесь Точно точно так же на него постоянно висит сильная ссылка То есть он всегда в памяти в viw de Load мы не хотим класть потому что мы не хотим чтобы на контроле

    00:51:17 - 00:52:48

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

    00:52:06 - 00:53:38

  • VI и во Vi Пир чтобы оно работало только тогда когда у нас показан экран О'кей Тогда вопрос А что происходит когда вот мы берём пальчиком презентует вот так вот вниз жок потянули и отпустили обратно Аа кажется View Will Ага О'кей э это догадка Потому что есть много кажется разных реализаций либо это бам либо это вообще swiftui ну окей ладно в рамках ки та говорим предположу что здесь вызове метод VI des но мед VI не вызове это догадка Но конечно это надо тестить но сейчас я тогда скажу что отписку мы будем делать

    00:52:54 - 00:54:32

  • только в том случае когда экран пропадёт То бишь VI Vi чтобы мы отписались только когда он полностью пропадёт а подписку здесь можно сделать в таком случае Ну пусть будет тогда возникает вопрос Если отписку мы сделали только подписку мы сделали то сколько раз будем подписва будем подс сделаем во did который вызове в принципе один раз ну не учитывая вот этот не учитывая тот момент когда мы будем а мы будем тянуть вниз мы будем постоянно тянуть день и ночь Угу Ну Володе делать смысла нет потому что

    00:53:47 - 00:55:46

  • делать как жить что делать тогда использовать реактив а не цен который сам всё разрулит со своими умными Так а что нам мешает цент использовать вс-таки рисовые или комбайнов ские они более умные более оптимизированы А здесь нам надо будет больше руками у нас нет никаких инструментов вот мы у нас Legacy проект Мы точно не будем в него засовывать никакую реактив но нам у нас как бы не у нас пользователь бахнул и всё у него Данные перестали обновляться А нам только те приходит Ну почини как м подписку

    00:54:52 - 00:56:26

  • сделаем или или наоборот чтобы чтобы наверняка и у нас вообще там какой-то нам к нам приходят эти сервери Говорят у вас там не не один этот как его зовут соке открыт 50 на один запрос ребят что у вас происходит вообще чтобы всё точно было ой Ну мы очевидно делаем во который отработает условно один раз и мы делаем в ните который тоже условно отработает один раз и нам будет всё равно на вот эти наши сдвигая вниз но очевидно можно найти какой-то более оптимизированный вариант но железобетон так всё будет

    00:56:01 - 00:57:29

  • окей Окей Хорошо тогда вот давай ещё что хочу тебя спросить вопрос Вот есть у нас й и Bounce вообще что это такое Это вопрос на который отвечает на всех собеседованиях Frame - это относительно родительского superview B относительно своей системы координат вот что происходит вообще в целом когда мы двигаем scv У нас меняется точка orig У баса фрейм остаётся в принципе неизменным Угу А что происходит с вьюшка которые лежат в этом скл вю у них что меняется со вушками которые лежат в сл viw Ну да ну

    00:56:44 - 00:58:30

  • у нас же двигаются в юшки или как Или они не двигаются кто двигается м ну всё что меняется Это баунс эта точка Origin у баун То бишь Ну вообще баланс - это хранимые свойство Фрей вообще вычисляемое кстати Ну а и если у нас есть Вью которая расположена внутри этого скролла И если мы у неё вызовем условный фрейм то фрейм будет э такой же Ну он никак не будет меняться в зависимости от того как мы его скро Потому что супер Вью остаётся неизменная меняется только баунс если мы вызовем баунс о этой вюи это более интересный

    00:57:41 - 00:59:25

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

    00:58:32 - 01:00:05

  • чтом будет поместить э Юху прямоугольник Ну давай последний Тогда вопрос по UI вот если я хочу нарисовать вьюшку кастомной формы что мне для этого нужно А помню делал так делал это через безе пас Угу что это ну кривые безе которые позволяют нам у меня вот задача была нарисовать как бы промокод где вот так вырезы пока я с помощью этого класса через без рисовал вот этот прямоугольник задавал эту формулу там через синусы косинусы арктангенс котангенсы что-то высчитывание допустим интересный опыт был

    00:59:19 - 01:00:57

  • Ну в зависимости от того какая нам Юха нужна если нам нужно что-то очень кам без Ешки если можно обойтись обычной в юхо и наложить на её маску которая будет как бы вырезать эту в Юху Ну часть в юхи Окей так Кать ты мне скажи что у нас по таймингу Да я как раз к вам снова присоединилась потому что у нас уже пора завершать Наверное мы сейчас соберём такой от себя резюмирую момент Вот давай давай тогда уже сначала По последней секции Да давай Владимир и там и там не просто с другой стороны смотри Ты уже можешь сейчас как

    01:00:14 - 01:01:44

  • бы ну уже всё дальше Ну как Короче мы Владимира отправляем снова я думаю нет смысла уже Владимира куда-то отправлять мы сейчас просто об Давай по последней секции и я задам тебе итоговый вопрос тогда А у тебя будет вопросы а ты думаешь Нет нет не бойся я тебя собеседовать не буду мне Я просто не понял кому ты задашь вопрос Да тебе задам Или ты не готовился Давай так сейчас что тогда какой план Ну давай расскажи уже вот после про последней части и мы поговорим уже тогда подытожим ой Окей Ну в целом всё

    01:01:01 - 01:02:28

  • неплохо честно говоря Напомните мне о чём мы говорили до того как мы ушли на Frame B Я уже забыл к сожалению не записывал кто-нибудь помнит про таймеры и не по Да вот да вот в принципе в принципе всё неплохо про таймеры поговорили про й баус проговорили а-а но как-то в общем у меня что-то такого сильного не было чтобы меня там резную фик могу дать У меня обычно либо что-то режет либо что-то не режет Ну так что Кать можешь врываться задать Окей Смотри у меня наверное главный вопрос такие два вопроса нанял

    01:01:48 - 01:03:08

  • ли ты Владимира и на какой грейд ты бы его нанял А если бы нанял м так ну смотри тут [музыка] э как как обычно всё-таки происходит собеседование обычно собеседование оно идёт на какую-то конкретную позицию мы ожидаем от кандидата каких-то навыков то есть какие-то навыки они на самом деле приоритизировать и нам в целом вот если он что-то не шарит там в многопоточный Да но нам это не Сильно критично вот нам Главное чтобы он там разбирал swiftui если мы допустим ищем там человека на obc то нам опять нам просто да Если ты

    01:02:33 - 01:04:05

  • умеешь писать на obc всё Ты нанят вот поэтому в основном всё-таки какой-то навык он приоритизировать Почему я объясню почему просто Как сказать то есть в моём понимании Кто такой сеньор сеньор - это чел который уже понюхал вот понюхал максимально типа вот ты Только начинаешь говорить а он уже как бы вообще понимает О чём ты или допустим он начинает копать копать Ты понимаешь что там как бы ну типа далеко можно закопать какие-то опять такие моменты вот очень часто бывает когда человек не готов к Собес Ну вот

    01:03:28 - 01:04:54

  • реально не готов но ты начинаешь его раскручивать А там Знаешь вот он начинает что-то выкачивать то что он там когда-то 000 лет разбирался там до этого вот а бывает когда человек вот прям заряжен максимально вот он вот он все статьи на хабре прочитал пришёл всё готов Ты только задаёшь ему вопрос ответ на который наха не прочёл и всё начинает сыпаться просто моментально вот поэтому в целом собеседование это такой момент который в большей степени про то чтобы понять вот где кончаются где кончается то с чем человек на самом деле

    01:04:31 - 01:05:58

  • сталкивался А где начинается то что он вчера прочёл тейка в интернете Давай мы дадим Чуть более конструктивный ответ с которым Владимир грубо говоря вот допустим ты его сейчас Оценил на медла он хочет условно Ну давай так через год-полтора ну чтобы он больше ценился как Синьор Что ему надо изучать В какие стороны ему нужно фокусироваться чтобы приближаться к этому рейду Слушай это супер сложный вопрос мне кажется каждый вотт лой сидит По ту сторону экрана Он у него какие-то свои в голове понимания

    01:05:14 - 01:06:46

  • Кто такой Синьор и какими скила он должен обладать это вот дать какого-то комплексного ответа что вот ты Синьор если 2 3Т Нет мне кажется что м Если ты на 100% матчи с тем что требуется в компании требуется на вакансии ты там готов закрыть все их боли все их проблемы тебя не надо ничему учить тебе не надо ничего объяснять вот это ты Синьор мне так кажется Окей смотри вы провели Моко вое собеседование Ты дала задачи если мы резюмируем понятно что Владимир посмотрит потом на юту все твоей обратной связи которые ты давал Но если

    01:05:59 - 01:07:46

  • в общем рею вопросы где хорошо Где плохо где среднее вот каких темах как бы да В целом везде хорошо то есть я бы не сказал что где-то было прямо плохо нет в целом везде хорошо но везде можно лучше то есть везде можно глубже везде можно было развёрнуты и везде можно было бы там как-то ну я не знаю с меньшим количеством подсказок Да наверное вот с меньшим количеством каких-то там дополнительных вот этих намёков или всего прочего вот я бы так сказал ну то есть я бы Владимира нанял в целом Вот это наверное самый главный вот

    01:06:53 - 01:08:20

  • вопрос я бы нанял Я бы пришёл к нему сферо потому что в целом У меня очень плохая статистика по тому кому я в итоге даю офер вот я бы нанял Вот но опять же не я бы наверное даже midle п бы не поставил Нет я бы поставил Просто midle а что надо midle плю или это тоже должность без какой-то характеристики Ну в том плане что ты не можешь мне кажется mle плю Это если ты хотя бы одну из сфер Вот вот просто на Ну то есть вот у нас там критерии обычные типа у нас отлично хорошо [музыка] удовлетворительно точнее Нет там

    01:07:37 - 01:09:01

  • по-моему даже удовлетворительно нет отлично хорошо плохо Ноль вот так вот такие у нас грейды и типа вот если хотя бы одно прямо на Отлично вот прямо всё я просто аплодирую стоя хотя бы одна ну тема да которая была отвечено то это в принципе уже Да ну а все остальные на хорошо то это midle плюс для меня так я про понимаю что человек для тебя сенён когда он тебя где-то победил в какой-то области победил что-то Ну не знаю вот ну ты просто сказал про Отлично Что ты аплодирует не знаю вы как-то вот в

    01:08:19 - 01:09:26

  • какой-то теме у вас Баттл и он не Не ну ты знаешь просто когда я имею в виду аплодирую в том смысле что когда вот приходят на собеседование ребята которые знаешь ты вот задаёшь им такую задачку и они просто тупят на неё вот так вот и всё и просто и время уходит поэтому когда приходит человек который Ну понимает что ты от него хочешь он там не знаю у него есть какой-то минимальный опыт минимальный понимание того как это вообще всё устроено то это уже тебя радует А когда человек просто там ну ты ты вот Начал произносить

    01:08:52 - 01:10:09

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

    01:09:32 - 01:10:52

  • сеньор ской лыч Я думаю Владимира такая сма не устро механизм повышения он основан на нескольких пунктах это в том числе самостоятельная работа То есть когда как я уже сказал что там э ты тем более сеньор Чем более комплексную задачу ты способен выполнить самостоятельно без надзора без контроля без там подсказок и всего прочего вот а и наверное ещ Есть такой момент это зона ответственности То есть если ты пришёл на позицию красить кнопки и ты сидишь красишь кнопки и больше ничего не делаешь Ну ты хоть год хоть 3 года Сиди

    01:10:16 - 01:11:45

  • сиром ты не станешь если ты если ты начинаешь какую-то активность типа там я не знаю ребят Вот мы [музыка] Допустим что-то все по-разному пишем сетевой слой вот Каждый раз как не зайду в модуль так каждый там на Давайте может мы какой-то выберем шаблон и Давайте вот писать там и ты такой о Ну тебе говорят О'кей Разработай архитектуру сетевого слоя там воз Ну вот реши какую там библиотечку мы может подтянем или ещё что-то и ты такой О'кей я взял всё Ты справился ты это внедрил оп ты Галочка У тебя есть и чем больше Вот таких личных

    01:11:09 - 01:12:31

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

    01:11:50 - 01:13:22

  • болью от многих людей такое слышу ты приходишь на собеседование тебя о чем-то спрашивают ты там прикольно отвечаешь и думаешь что легко прол А тебя оценили Ну условно ниже чем ты когда-то себя считал тому что тебя не спросили Вот по самым твоим верхам А я бы условно Вот про UI мы с тобой поговорили Я бы тебе мог там рассказать много прикольных кейсов про Ну вообще связанные с UI какие я там прикольные кастомные элементы сделал Я в тебе смог назвать типа 50 способов оптимизировать коллекцию Я бы мог тебе рассказать про

    01:12:38 - 01:13:47

  • то как работает рендер серверы и Как оптимизировать хичи на этапе комита и всего такого Но типа меня об этом не спрашивают как понять Ну понятно ты со своей позиции считаешь что надо спрашивать о чём-то таком что более жизнеспособной задавал мне ты вот будем UI допустим рассматривать единственное что я помню Сейчас отличаются от тех вопросах которые ты спрашивал бы на условного самого там Холида вот если именно техническую часть брать Как мне тебе показать Вот весь мой потолок [музыка] ний тут два момента первый момент я к

    01:13:13 - 01:14:35

  • сожалению не подготовился И к сожалению у меня не было Вот максимально глубокого списка обычно у меня есть именно знаешь вот грубо говоря вот так так так вот что я там опускаюсь за самого низа Это первый момент а второй момент у нас нету времени на это то есть если брать э там собеседование в крупной компании то э суммарный объём технического собеседования может занимать не знаю 4 часа 5 часов и мало этого если ты там говоришь про тех Лида у тебя будет ещё отдельное собеседование которое там будет

    01:13:56 - 01:15:15

  • собеседовать твои способности как менеджера Да вот так что тут Да вопрос как за час определить человек сеньор мил джн мой ответ 100% никак Ну никак ты это не определишь пото что в принципе вот условный нам известный волк Вполне может просто все ответы все задачи подготовиться Выдумать себе Легенду прийти и за час Ну действительно никак ты это не определишь Вот но таковы реалии это это риски которые мы на себя берм то есть в основном задача не нанять гения задача отсеять шлаг вот поэтому как бы Мы готовы

    01:14:35 - 01:16:29

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

    01:15:35 - 01:16:49

  • более востребованные там для синьора скилы Потому что со беседуют обычно для того чтобы закрывать свои задачи и потребности то есть мы ищем челове мы понимаем что он должен нас для нас сделать Какие он должен решать задачи какие там импрув мониторинги и так далее и мы мы должны проверить что он с этим справится соответственно Ну не знаю наверное я бы предложила тебе в резюме или в пед проектах как-то описывать свои сильные стороны чтобы было понимание в чём ты крут может быть это на собеседовании

    01:16:12 - 01:17:22

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

    01:16:47 - 01:18:03

  • Так что всем пока пока-пока [музыка] [аплодисменты]

    01:17:26 - 01:17:44

Менторы

Специалисты своей области, которые смогут помочь вам

  • Нигма Нурия
    Нигма Нурия

    Middle .Net Developer

  • Сущенко Татьяна
    Сущенко Татьяна

    Senior Product Manager

  • Гудков Денис
    Гудков Денис

    Middle Python Developer

  • Курочкин Константин
    Курочкин Константин

    Ведущий программист

  • Гудман Макс
    Гудман Макс

    Backend Software Engineer (PHP)

  • Гребенкин Антон
    Гребенкин Антон

    Senior .NET/C# developer

  • Ахназаров Фёдор
    Ахназаров Фёдор

    Middle DevOps Engineer | Tbilisi, Georgia

  • Шорохов Дмитрий
    Шорохов Дмитрий

    Middle C# .NET

  • Жуков Александр
    Жуков Александр

    Senior PHP-разработчик

  • Мазикин Павел
    Мазикин Павел

    Middle python developer

© 2024 HireGuru. Сделано в Санкт-Петербурге с hireguru.ru