Как я вошел в IT и чего мне это стоило. Но результат превзошел все ожидания. Часть 2

Андрей Нивинский
android software developer

Как я писал ранее, в начале марта 2022 года на udemy я купил курс “Kotlin — профессиональный уровень”. Именно прохождение этого курса дало мне большой толчок в развитии. Этому способствовала подача материала, а именно автор курса, Андрей Сумин. Он не только в своих уроках делал приложение, и объяснял каждый свой шаг.

Система обучения имела примерно следующую структуру:

  • Автор показывает выполнение какого-то метода.
  • Автор объясняет что делает каждая строчка кода.
  • Автор говорит, что дает несколько секунд поставить видео на паузу, чтоб мы самостоятельно сделали следующий шаг по подобию того, что только что прошли.
  • Ты делаешь дальше самостоятельно, тем самым запоминая структуру кода и синтаксис.
  • Автор продолжает писать код, а ты сравниваешь, так ли ты написал.
  • После того, как первоначальный вариант кода написан, автор предлагает варианты улучшить написанный код и объясняет, в чем разница.
  • Если код можно еще улучшить, то показывает, как улучшить его дальше.
  • После прохождения нескольких тем, дает приложение, в котором нужно выполнить рефакторинг на основании ранее изученных тем.

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

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

Резюме направил наверное 150 штук.

Что из себя представляли собеседования

Компания №1. Не помню название (хедхантер): дали мне на время решить две алгоритмические задачи. В 1 час нужно было вложиться. Я успел сделать только одну, вторую как решать совсем не понял. Переключаться и лезть в “гугол” было нельзя. Естественно техническое собеседование я не прошел.

Компания №2. AlefDevelopment (хэдхантер). Нужно было написать приложение, которое скачивает картинки (я использовал Retrofit и Picasso), картинки имеют соотношение сторон 16:9, а мне их нужно было отображать одинаковыми квадратами, плитками в 2 столбца, если у нас вертикальный режим, а если горизонтальный, то 3 столбца. Вот тут я задание недопонял, т.к. оно было написано немного криво. В расчет брался планшет, как устройство, или же просто горизонтальная разметка? — по этому пункту я не прошел. И по клику на картинку она должна раскрываться в полный экран. Хорошо, хоть дали обратную связь, почему я не прошел. Это приложение я написал буквально за 3 часа.

Компания №3. Зайцев.нет (хабр. карьера): работать исключительно в офисе, офис в Челябинске. Был готов туда ехать работать. Собеседований было 3. Первое собеседование — техническое задание. Надо было какой-то алгоритм посчитать. Не помню точно, справился на отлично минут за 30-40. Второй этап: это решение задач через демонстрацию экрана, в общей сложности муштровали меня 2 часа. Надо было по циклу за один проход посчитать сумму чисел, за исключением самых минимальных и самых максимальных чисел. Здесь у меня возникли сложности. Как это сделать за один проход я не знал. Но хоть варианты накидал, рассуждал вслух. Через 2 дня раздумий мне сказали, что я еще зеленый. Но опять же, алгоритмы, а я в них не силен.

Компания №4. ООО “ВБЦ” (mobile dev jobs). Собеседование было сразу с тех. лидом. Длилось один час, отвечал на вопросы ЖЦ активити, ЖЦ фрагмента, viewModel, dataBinding, contentProvider, broadcastReceiver и прочие ругательства для обычных читателей. По моим ощущениям, ответил я правильно и уверенно на 80% вопросов. Обещал позвонить 21 марта с результатом — так и не позвонил. Но мне понравилось…

Компания №5. Не буду приводить название (хедхантер). Как я в неё попал - опишу более подробно ниже. Приведу скриншот сообщения от другого андроид-разработчика, который принимал у меня работу.

Как я вошел в IT и чего мне это стоило. Но результат превзошел все ожидания. Часть 2

Во вторник утром мне позвонили, побеседовали со мной на проверку моей общей адекватности и сказали примерно следующее “давай договоримся по деньгам, и погнали”. Итого с 16 марта 2022 года я получил приглашение на работу в качестве Android-разработчика.

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

Как я вошел в IT и чего мне это стоило. Но результат превзошел все ожидания. Часть 2

Вкусности и полезности

Во-первых, для того, чтоб научиться быстро печатать, я использовал тренажер Stamina. В настоящее время доступна онлайн версия. Скорость моей печати на кириллице — 405 знаков в минуту, точность 99.9%; скорость моей печати на латинице — 206 знаков в минуту, точность 94.6%.

Во-вторых, для того, чтоб следить за режимом работы и отдыха, я использую приложение Stretchly — за заданный промежуток времени выводит большой баннер на экран с таймером обратного отсчета, когда тебе можно вернуться к работе + говорит, что нужно сделать: закрыть глаза, посмотреть на источник натурального света, потянуться, сходить попить воды...

В-третьих, на “ОЗОН” купил очки компьютерные Xiaomi для блокирования синего света, который является вредным для зрения. Глаза от монитора перестали болеть. Рекомендую. Обошлись в 2960 руб.

События, происходившие с момента смены профессиональной деятельности.

Первая моя работа, название которой я не буду приводить по этическим соображениям была “галерой”. Итак, “галера” - это компании, работающие по схеме аутсорсинга или аутстаффинга. В свою очередь, аутсорсингом называется передача выполнения каких-либо функций от одной компании другой за вознаграждение. В нашем случае одна компания передает разработку какого-нибудь программного продукта другой. Аутстаффинг - это когда компания сдает в аренду своих сотрудников другой компании. То есть, торговля людьми на законных основаниях. Я работал только по схеме аутсорсинга. Подробнее, как я в нее попал: на hh.ru я откликнулся на вакансию, в воскресенье утром в телеграмм мне написала мадам с целью пройти аттестацию (я по-другому не могу это назвать) на разработчика в их компанию. В качестве этой аттестации необходимо было найти и устранить баг: там текст налазил на картинку, нужно было отодвинуть; а также сделать доработку - нужно было нарисовать шкалу и посчитать математику, что если пользователь кладет в корзину товаров на сумму более 2000 руб, то доставка становится бесплатной. Таких как я, желающих начать свой путь в андроид разработке, набралось 5 человек, нас добавили в общий телеграмм-канал, где каждый получил одно и тоже задание. Из всех пяти только я один дошел до логического финала: исправил баг и сделал доработку. В понедельник со мной был разговор для проверки общей адекватности и я получил предложение о работе - 16 марта 2022 года. 22 марта - был первый мой рабочий день в этой компании. С учетом уровня знаний и нулевого опыта мне предложили 50 000 рублей. По сути, я был бы готов работать и за еду, как говорят, потому что у меня есть другие доходы, которые перекрыли бы все мои расходы. Я также собеседовался в Zaycev.net, там тоже предлагали 50 000 руб плюс обязательный переезд в Челябинск, т.к. удаленку они не рассматривали вообще. В принципе, согласно исследованию (не знаю кого), джун в андроид разработке может ориентироваться на зарплату 50 - 120 тысяч рублей. Так что я прошел по нижней границе.

На этой работе мне досталось плохо оптимизированное приложение, которое дико тормозило.

Ниже будут некоторые технические подробности.

Попробую объяснить простым языком, что такое отсутствие оптимизации верстки.

Разберем всем известное приложение ОЗОН.У нас на экране есть отображаемые элементы, они расположены каскадом, то есть что-то на переднем плане, что-то на заднем плане. Я выделил цветными рамками группы элементов. Поисковую строку “Искать на озон” и нижнее навигационное меню мы рассматривать не будем. Основной контейнер, который содержит в себе все меняющиеся элементы, выделен красной рамкой. Если смотреть сверху вниз, то у нас:

- рекламный баннер (рамка цвета хаки),

- блок с категориями, её еще называют “карусель”, но на самом деле этот контейнер называется ViewPager (сейчас работники озона набегут и скажут, что это кастомная вьюха. Люблю вас!), выделена розовой рамкой.

- заголовок “Лучшие предложения” скорей всего лежит просто во фрагменте. Тут ничего интересного, в рамку выделять не стал.

- дальше у нас контейнер RecyclerView с лучшими предложениями - темно синяя рамка, который содержит в себе карточки товаров. Карточка товаров выделена черным цветом.

Если рассмотреть “Лучшие предложения” с точки зрения каскада, то у нас на заднем фоне красная рамка, затем идет RecyclerView темно-синего цвета рамка, и она включает в себя карточку товара, черного цвета. Эта карточка товара у нас лежит на самом переднем плане из этих групп.

<p>Так вот, основные ошибки верстки заключаются в том, что мы отрисовываем элементы, которых никто не видит, потому что сверху этого элемента находится новый элемент. Тогда зачем отрисовывать нижний, если он не доступен пользователю, а процессорное время (мощности телефона) мы используем? Так делать нельзя. Также вспоминаем пример ОЗОНа, у него на главной странице 3 уровня вложенности. Максимально допустимый по стандартам - 4 уровня вложенности. В сказках говорится, что Кощей «бессмертный», однако у Кощея есть смерть, хоть она и спрятана. По одной из версий, смерть его находится на конце иглы, игла в яйце, яйцо в утке, утка в зайце, заяц спрятан в ларце, ларец висит в цепях на дубу, который растёт на чёрной горе или на далёком острове Буяне. Я насчитал тут 7 уровней вложенности. Надеюсь, приведенная мною аналогия понятная. Так вот, если превышать максимально допустимое количество вложенностей, то процессору нужно больше времени на их отрисовку, отсюда появляются глюки. Если у тебя телефон последнего поколения, в нем 8 гигов оперативки, то за это переживать не стоит. Но если у тебя 2-3 гб оперативки, 4 ядра процессор не первой свежести, то медленную работу приложения ты заметишь, тебя это начнет раздражать и ты удалишь это приложение.</p><p>Главный поток (main thread) нужен лишь для того, чтоб отрисовать изображение на экране пользователю. Отрисовка происходит каждые 16 миллисекунд или 60 раз (кадров) в секунду. Рассмотрим пример: ты завершаешь аренду каршеринга, сделал фотографии автомобиля и нажимаешь на кнопку “завершить”. Что происходит в этот момент? Фотографии должны загрузиться на сервер. Сейчас камеры у всех хорошие, каждая фотография “весит” примерно 3+ мб. А у тебя этих фотографий 4 (у автомобиля же четыре стороны). И ты всю логику загрузки фотографий оставил (не переключил) на главном потоке. Получается главный поток идет в сеть и выгружает фотографии туда. Сколько времени это займет? Ну пусть у тебя хороший интернет и это займет 5 секунд. Так вот все эти 5 секунд ничего больше с отображаемыми элементами на экране нельзя будет сделать. У пользователя появится ощущение, что телефон завис. Но, операционная система настроена таким образом, что если отображение не обновляется больше 2 секунд, то выскакивает ошибка “Приложение не отвечает” (Application is not responding - ANR). И тогда пользователь при виде этой ошибки думает, что приложение кривое и его надо удалить. </p><p>Как надо делать:</p><p>У нас в телефонах сейчас многоядерные процессоры. В моем конкретно телефоне их 8, так вот берем и все задачи, которые не связаны с отображением выносим в другой поток, то есть выделяем руками ядро, на котором будут происходить вычисления. Если вычисления тяжелые и выполняются на самом устройстве, то у нас количество таких потоков равно количеству ядер. Например, играя в какие-то игры мы можем наблюдать глюки, когда один персонаж наносит удар другому персонажу, тут срабатывает математика (каким орудием, какая броня, текущее количество жизни, уровень персонажа, другие мультипликаторы, которые показывают количество нанесенного удара) по вычислению урона, приложение подтормаживает на пол секунды и рядом с персонажем мы видим текст, показывающий объем нанесенного урона. Так вот здесь мне кажется, тоже напутали с потоками. Такая математика в главном потоке вычисляться не должна. Но здесь я залез в огород геймдева (game development), сейчас опять понабегут и заклюют меня.</p><p>Какой из этого нужно сделать вывод? Все вычисления, которые направлены не на отрисовку интерфейса, нужно выносить в отдельные потоки.</p>

Так вот, основные ошибки верстки заключаются в том, что мы отрисовываем элементы, которых никто не видит, потому что сверху этого элемента находится новый элемент. Тогда зачем отрисовывать нижний, если он не доступен пользователю, а процессорное время (мощности телефона) мы используем? Так делать нельзя. Также вспоминаем пример ОЗОНа, у него на главной странице 3 уровня вложенности. Максимально допустимый по стандартам - 4 уровня вложенности. В сказках говорится, что Кощей «бессмертный», однако у Кощея есть смерть, хоть она и спрятана. По одной из версий, смерть его находится на конце иглы, игла в яйце, яйцо в утке, утка в зайце, заяц спрятан в ларце, ларец висит в цепях на дубу, который растёт на чёрной горе или на далёком острове Буяне. Я насчитал тут 7 уровней вложенности. Надеюсь, приведенная мною аналогия понятная. Так вот, если превышать максимально допустимое количество вложенностей, то процессору нужно больше времени на их отрисовку, отсюда появляются глюки. Если у тебя телефон последнего поколения, в нем 8 гигов оперативки, то за это переживать не стоит. Но если у тебя 2-3 гб оперативки, 4 ядра процессор не первой свежести, то медленную работу приложения ты заметишь, тебя это начнет раздражать и ты удалишь это приложение.

Главный поток (main thread) нужен лишь для того, чтоб отрисовать изображение на экране пользователю. Отрисовка происходит каждые 16 миллисекунд или 60 раз (кадров) в секунду. Рассмотрим пример: ты завершаешь аренду каршеринга, сделал фотографии автомобиля и нажимаешь на кнопку “завершить”. Что происходит в этот момент? Фотографии должны загрузиться на сервер. Сейчас камеры у всех хорошие, каждая фотография “весит” примерно 3+ мб. А у тебя этих фотографий 4 (у автомобиля же четыре стороны). И ты всю логику загрузки фотографий оставил (не переключил) на главном потоке. Получается главный поток идет в сеть и выгружает фотографии туда. Сколько времени это займет? Ну пусть у тебя хороший интернет и это займет 5 секунд. Так вот все эти 5 секунд ничего больше с отображаемыми элементами на экране нельзя будет сделать. У пользователя появится ощущение, что телефон завис. Но, операционная система настроена таким образом, что если отображение не обновляется больше 2 секунд, то выскакивает ошибка “Приложение не отвечает” (Application is not responding - ANR). И тогда пользователь при виде этой ошибки думает, что приложение кривое и его надо удалить.

Как надо делать:

У нас в телефонах сейчас многоядерные процессоры. В моем конкретно телефоне их 8, так вот берем и все задачи, которые не связаны с отображением выносим в другой поток, то есть выделяем руками ядро, на котором будут происходить вычисления. Если вычисления тяжелые и выполняются на самом устройстве, то у нас количество таких потоков равно количеству ядер. Например, играя в какие-то игры мы можем наблюдать глюки, когда один персонаж наносит удар другому персонажу, тут срабатывает математика (каким орудием, какая броня, текущее количество жизни, уровень персонажа, другие мультипликаторы, которые показывают количество нанесенного удара) по вычислению урона, приложение подтормаживает на пол секунды и рядом с персонажем мы видим текст, показывающий объем нанесенного урона. Так вот здесь мне кажется, тоже напутали с потоками. Такая математика в главном потоке вычисляться не должна. Но здесь я залез в огород геймдева (game development), сейчас опять понабегут и заклюют меня.

Какой из этого нужно сделать вывод? Все вычисления, которые направлены не на отрисовку интерфейса, нужно выносить в отдельные потоки.

Конец технической части

Примерно через месяц работы мне дали второй проект - грузоперевозки. Его нужно было довести до ума, но не срослось. К сожалению раскрыть ТЗ я не могу, меня ограничивают подписанные мною документы. Но основную проблематику я выделю. Как выглядит вообще процесс: заказчик со своей идеей и ТЗ приходит к исполнителю (в данном случае к нам в компанию). Исполнитель оценивает трудозатраты на разработку, считает себестоимость, умножает эту себестоимость на процент своей жадности, прибавляет непредвиденные издержки и показывает итоговую стоимость заказчику. Если заказчика цена и сроки разработки устраивают - подписывается договор, авансируется и разработка стартует. Так вот спустя какое-то время заказчик меняет дизайн. Что это значит? Это значит, что нам нужно перерисовывать дизайн, то есть это дополнительное время (зарплата) разработчика и издержки бизнеса (разработчик занят), которое по подписанному договору не оплачивается. Потом у заказчика произошла внутренняя оптимизация серверной части, они изменили свою базу данных. А у меня в тот момент все сетевые запросы были написаны. Таким образом, чтоб у меня приложение вообще стало запускаться и работать (при первом запуске и заставке была авторизация пользователя), мне нужно было переписать все сетевые запросы. Этот объем работы также не учтен в подписанном договоре. И таких изменений у заказчика было много. Думаю, что это ошибка проджект менеджера со стороны заказчика. Но это не моего уровня вопрос, поэтому более подробно не напишу.

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

Как происходит процесс получения нового проекта в разработку со стороны линейного андроид разработчика, если ты в компании единственный, а значит твое мнение по умолчанию экспертное. Сарказм! Когда приходит заказчик со своим проектом, то первоначально он общается с проджект менеджером со стороны исполнителя (с нашей стороны). Они обсуждают ТЗ. Первоначально, проджект менеджер должен понять, как это приложение будет работать, какие бизнес-задачи будет выполнять и так далее. После того, как понятна суть работы приложения, составляется документ, в котором кратко описывается каждый экран и его функциональность. Этот документ уже спускается ко мне, где я должен оценить, сколько моего времени уйдет на то, чтоб каждый экран отрисовать и наполнить логикой. То есть работа моя делится на 2 части: это отрисовка (что-то типа дизайна), это самая простая часть, и логика или алгоритмы, которые отрабатываются, когда пользователь взаимодействует с экраном - это самая сложная часть. После того, как я оцениваю свою работу в часах, проджект менеджер выставляет ценник заказчику. Если заказчик подписывает договор, то в работу вступает дизайнер, который отрисовывает в фигме (figma.com) дизайн. Этот дизайн согласуется с разработчиком (со мной) на предмет “а всю ли эту красоту ты можешь нарисовать или возникнут сложности?”, если я говорю, что какой-то элемент для меня сложный (да, бывает скиллухи не хватает), дизайнер перерисовывает это так, чтоб я осилил, и если я согласовываю, то дизайн направляется заказчику. Если заказчик согласовал - то я уже беру этот макет/дизайн в работу и начинаю делать новое приложение.

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

Конечно, во время разработки ты приложение видишь по-другому и оцениваешь это со стороны конечного пользователя. Например, как-то я в заказ получил задачу, чтоб пользователь при заказе каждый раз вбивал свой адрес, начиная с города, который нужно выбрать из списка, все остальное - вводить руками с клавиатуры. Меня, как конечного пользователя это бы раздражало: я хочу один раз ввести адрес, и чтоб приложение в следующий раз само заполняло уже введенный мною ранее адрес и дало отдельно возможность адрес изменить. Естественно эту идею я донес до проджект менеджера, чтоб он обсудил с заказчиком, но заказчик оказался непреклонен. Что интересно, спустя 2 недели после публикации этих изменений в Google Play я получил задание все-таки сохранять ранее введенный пользователем адрес. Всё-таки низкие оценки приложения в Google Play сделали своё дело.Другой момент, попроще, заказчик хотел чтоб при регистрации нового пользователя клиент вводил телефон формата +7… Я предложил либо ввод телефона через “8”, либо вообще без этого кода, чтоб пользователь не искал символ “+” на клавиатуре. В итоге сделали так, что “+7” я сам подставляю, а от пользователя требовали ввести остаток. Таким образом мы вместе делаем взаимодействие с приложением более дружелюбным к пользователю. На своих идеях я не зацикливаюсь и не отстаиваю, бизнесу виднее, что ему нужно. Я работаю по принципу “кто платит, тот музыку и заказывает”.

В новом приложении я избежал ошибок предыдущих разработчиков, которые делали “первое приложение”. Прежде всего, создавая приложение, необходимо держать в уме, что оно будет дорабатываться, изменяться, расширяться. И проектируя структуру приложения, необходимо следовать принципам объектно-ориентированного программирования и принципам SOLID. Я не буду описывать, что это такое, иначе мы уклон перетянем с непосвященного читателя в F.A.Q. по архитектуре приложений. Приведу пример с зависимостями:Чтоб собрать компьютер, который состоит из монитора, клавиатуры, мыши и системного блока, нам не нужно производить эти четыре устройства. Чтоб собрать системный блок, нам нужен жесткий диск, процессор, оперативная память… Нам тоже не нужно это все производить. Нам лишь нужно знать, где это взять. В реальной жизни у нас есть поставщики этих комплектующих на конвейер, с которого в конечном итоге сходит готовое устройство. В программировании тоже самое, это называется инъекцией зависимостей. Я внедрил Koin, который позволяет сделать примерно следующее “эй, андроид, мне нужно X, Y, Z, а ну-ка пошурши по сусекам, создай это и принеси мне вот сюда, да поживее”. Таким образом мне не нужно выполнять логистику нужных мне элементов (классов), а нужно лишь объявить, что я ищу, и куда это положить. Это позволяет расширять функционал приложения очень легко, когда руками протаскивать ничего не нужно.Самые сложные задачи это те, которые ты раньше не делал, то есть нет опыта, на технологиях, которые не знаешь. То есть все приходится учить, и тут же внедрять. Выучить можно всё, но время идет, и за оплаченное время бизнес хочет от разработчика какую-то отдачу. Сложность написания приложения с нуля, особенно когда ты один и посоветоваться не с кем, заключается в выборе правильной архитектуры и набора технологий, на которых оно будет написано. Я пошел по пути наименьшего сопротивления: на udemy я покупал курс “Андроид - профессиональный уровень”, там мы писали приложение “математика для детей”, там автор использовал все современные технологии полноценного “тяжелого” приложения. Я просто взял и скопировал архитектуру. Потом, когда я общался уже с миддл-разработчиком, который пришел на моё место, он оценил эту архитектуру и сказал, что ему все в коде нравится. В настоящее время я не могу ответить, что лучше - писать приложение с нуля или исправлять баги приложения. Т.к. не понятно само определение слова “лучше”. Я тут напишу про ощущения: когда ты пишешь приложение с нуля, или делаешь какой-то раздел, которого раньше не существовало, ты берешь на себя ответственность, ты получаешь удовлетворение созидателя, да и в целом, когда ты пишешь приложение ты в нем все знаешь, т.к. это твое детище. Ты меньше вникаешь в чужой код, просто берешь и делаешь. Здесь наверное противоречие об ответственности по моему предыдущему подразделу, что я не хотел брать на себя ответственность, но там имелось ввиду ответственность в решениях. Когда же ты правишь баги, тебе надо:

- прочитать чужой код (а это бывает не так просто),

- понять почему работает не так,

- найти место в котором идет сбой,

- затем уже придумать, как это решить.

И всегда присутствует мысль в голове “какой криворукий так написал?”. Когда пишешь приложение (раздел) с нуля, первые три пункта из списка выше отсутствуют.

Когда пишешь приложение с нуля, то нужно выбрать правильные технологии под цели и срок жизни приложения. Обычно выбором технологий занимается Тех-лид в команде. Опять же, это не отдельный человек, если вас в команде всего 10, а роль. Эту роль на себя может взять старший разработчик или тим-лид, если таковой в компании присутствует. Технологии в основном не отличаются настолько, что их нужно учить с нуля. У всего есть общие черты, но ты в основном упираешься в их ограничения. Приведу пример на автомобилях: вы хотите, чтоб у вас автомобиль был супер быстрым - например, это БМВ с самым современным их двигателем. Но тут вы упираетесь в ограничение - вы не хотите иметь большой расход топлива (занимать процессорное время), на нашем языке будет звучать как “тяжелый”. Посмотрели по сторонам и увидели Тесла, ваша задача иметь быстрый автомобиль выполняется, а ограничение в высокий расход топлива отсутствует. Как итог с технологий двигателя внутреннего сгорания мы переползаем на “электричку”.

Продолжение следует

3737
21 комментарий

Интересно, пишите еще

5
Ответить

Написал. Уже опубликованы 3-я и 4-я части

3
Ответить

Умеешь, могёшь, отец.

3
Ответить

Комментарий недоступен

1
Ответить

Комментарий недоступен

1
Ответить

Достаточно ведь просто число и количество вхождений хранить, ну и сумму всех, да.
Итого - время О(N), память О(1).

2
Ответить

а в питоне
```
return sum(sorted(digits)[1:-1])
```

Ответить