Cобеседования в IT — это всегда вызов и Android тут, конечно же, не исключение. Для успешного прохождения интервью в крупные и востребованные компании современный Android-разработик должен держать в голове огромное количетсво областей: от «базы» в виде Computer Science (структуры данных, алгоритмы) и навыков проектирования (архитектура, паттерны, System Design) до знания Java, Kotlin и, разумеется Android SDK. Добавим сюда и популярные фреймворки и библиотеки (которые к тому же устаревают каждые пару лет!) вроде RxJava и Kotlin Coroutines и получается совсем уж, на первый взгляд, неподъемный багаж необходимых знаний… К счастью, многие вопросы пересекаются между компаниями, так что наработав некоторую «базу» из них вы сильно повысите свои шансы на положительный результат и заветный оффер 🙂 Давайте разберем ТОП-5 вопросов, с которыми можно столкнуться в крупных компаниях на российском рынке, поехали!
1. Перечислите принципы, входящие в SOLID.
Вопрос вне времен и трендов: годы идут, а значительная часть интервью не обходится без этой темы. Чаще всего, все ограничивается перечислением и принципов и их коротким описанием, потому кратко давайте разберем их.
Single Responsibility
: часто неправильно понимается, как «модуль или класс должны отвечать за что-то одно». Это отчасти верно, но речь идет не только об ответственности класса, но еще и о причинах для его изменения, точнее о группе лиц, которым может потребоваться его изменить: «модуль должен отвечать только за одного актора» (где актор — 1 или более лиц, объединенных группой, например — «бухгалтерия», «отдел кадров»).
Open-Closed:
сущности программы должны быть открыты для расширения и закрыты для из изменений. Простое расширение (а не изменение) требований не должно вести к значительным изменениям кода, иначе — это архитектурная ошибка, произошедшая по причине нарушения этого принципа.
Liskov Substitution:
тут речь идёт о правильной иерархии наследования. Везде, где мы можем использовать 1 класс (базовый, например), мы должны иметь возможность использовать и его наследников без неожиданного поведения. Мораль — наследники должны писаться разумно и должны дополнять, а не замещать или искажать поведение базового класса.
Interface Segregation
: пожалуй, самый простой и понятный из принципов, где не часто бывают различные интерпретации. Принцип говорит о том, что несколько узко специализированных интерфейсов лучше, чем один большой. Один большой интерфейс может заставить классы, которые его реализуют, имплементировать методы, которые могут быть им и не нужны в конкретных случаях, что приводит к лишней работе или засорению кода пустыми реализациями.
Dependency Inversion
: Принцип гласит, что модули верхнего уровня не должны зависеть от модулей нижнего, и те и другие должны зависеть от абстракций И абстракции не должны зависеть от деталей, детали должны зависеть от абстракций. На практике это выглядит так: классы не должны создавать другие классы внутри себя, особенно конкретные реализации. Эти зависимости должны поставляться ИЗВНЕ, то есть инвертироваться.
Будьте готовы к усложнениям и вариациям, например:
-
Какой из данных принципов на ваш взгляд наиболее важный?
-
Какие нарушения принципов SOLID вы можете вспомнить в стандартных классах из Java, Kotlin или Android SDK?
Что почитать:
-
Роберт Мартин (Uncle Bob) — Чистая архитектура — собственно, это автор, который сформулировал принципы, входящие в SOLID, так что это информация напрямую от первоисточника
-
Baeldung (c примерами на Java)
2. Как работает HashMap
? Как происходит разбиение на бакеты? Что такое коллизии? Какую роль играют реализации equals/hashCode
методов у добавляемых объектов?
HashMap — излюбленная коллекция у многих собеседующих. Тема эта достаточно обширная, но, к счастью, материалов на этот счёт написано огромное количество:
-
можно посмотреть статьи в блогах: например, прямо тут на Хабре
-
литература: классикой для Java считается книга Роберта Лафоре — Структуры и алгоритмы данных Java
3. Что такое data
классы в Kotlin? Зачем они нужны, чем отличаются от обычных?
Data classes — это по праву одна из наиболее любимых многими фич Котлина! Собеседующие, правда, тоже попадают в эту категорию, потому они очень и очень любят задавать о ней вопросы. Начать знакомство с ними стоит в документации, чтобы понять базовые идеи.
Но стоит быть готовым и к усложнениям:
-
Чем
data
класс отличается отvalue
класса? (это довольно разные концепты, см. документацию для value класса) -
Что такое
data object?
В чем разницу междуdata class
иdata object
? (см. документацию) -
Какую информацию из data класса компилятор использует для генерации
equals/hashCode/toString
? (поля конструктора, переменные вне конструктора не используются) -
Что будет, если объявить поля конструктора
data
класса какvar
, а неval
? (ничего криминального, но это нарушает идею data классов — класс перестает быть неизменяемым, наличие сгенерированной функции copy() начинает выглядеть странно и т.д.) -
Есть ли у
data
классов какие-то недостатки? Нельзя ли просто все классы объявлять именно какdata
? (есть, например, они влияют на размер приложения из-за кодогенерации)
4. Какие «основные» компоненты Андроид вы знаете и почему они так называются?
Под “основными” понимаются те компоненты, которые могут являться точкой входа в приложение. Теоретически, приложение может состоять только из одного из таких компонентов, зарегистрированного в AndroidManifest
, в этом и заключается их особенность. Согласно документации, всего их 4:
Т.е. да, вы можете создать приложение, в котором нет никакого привычного UI и которое состоит из одного лишь BroadcastReceiver
или Service
и, возможно, даже выложить его в Google Play.
5. Как создать новую корутину? Перечислите все способы, которые знаете.
Основной способ запуска корутин — это использование т.н. Coroutine Builders:
-
launch: запускает новую корутину и возвращает связанный с ней Job. Этот
Job
не предоставляет типизированного результата, а просто служит индикатором выполнения + позволяет отменить выполняемую работу. Подходит, когда не нужен или не важен результат выполнения корутины, нужно просто запустить ее и выполнить. -
async: в отличии от
launch
возвращает неJob
, а Deferred<T>. Это future/promise, который по умолчанию уже находится в запущенном состоянии (это можно контролировать через параметрstart
). Чтобы дождаться результата выполнения необходимо вызватьawait
на возвращенномDeferred
объекте. Этот билдер удобен, когда необходимо получить результат выполнения работы корутины, а не простоJob
изlaunch
. -
runBlocking: запускает новую корутину и блокирует вызывавший поток до ее завершения. Возвращается не
Job
илиDefferred
, а обычный типизированный типT
. Этот способ не является основным, т.к. он сводит преимуществаsuspending
функций на «нет», но он бывает полезен в случаях, когда нужно вызывать корутины из какого-то старого кода, библиотек без поддержки kotlin и/или корутин + иногда используется при написании тестов.
launch
, async
являются extension функциями над CoroutineScope
, т.е. их нельзя вызвать вне контекста корутин (за счет этого наследуется context и прокидывается cancellation). runBlocking
же доступен отовсюду и не является extension функцией.
Все упомянутые билдеры получают CoroutineScope.()
лямбду на вход, внутри которой уже можно вызывать другие билдеры и suspend
функции.
На этом всё! Удачи на собеседованиях 🙂
А если вам интересн такой формат подготовки и вы хотели бы серьезно поднять свои шансы на заветный оффер, то рекомендую попробовать курс «Android собеседования от А до Я: популярные вопросы и ответы к ним«. Курс содержит разбор более 350-и популярных технических вопросов, которые встречаются на реальных Android собеседованиях в крупные компании в РФ — Ozon, Tinkoff, Альфабанк, Сбер и др.
ссылка на оригинал статьи https://habr.com/ru/articles/873088/
Добавить комментарий