Kotlin Android 개발자 기술 면접 정리

Kotlin Android 개발자 기술 면접 정리
Cozy CodingPosted On Aug 21, 202411 min read

현대 안드로이드 개발에서 코루틴은 중요한 요소가 되었는데, 더 간결하고 가독성이 좋은 방식으로 비동기 및 동시 코드를 작성할 수 있습니다. K/otlin 안드로이드 개발자로서, 코루틴과 그 사용법에 대한 견고한 이해가 중요합니다. 이 기사에서는 2024년에 접할 수 있는 일부 주요 코루틴 인터뷰 질문을 살펴보며, 다음 직군 면접 준비에 도움을 주겠습니다.

이미지

  1. Kotlin에서 코루틴이란 무엇인가요?
  • 코루틴은 비동기, 논블로킹 코드를 작성하기 위한 Kotlin의 내장 솔루션입니다. 이를 통해 개발자들은 일반 동기 코드처럼 보이는 순차 코드를 작성할 수 있으면서 일시 중단 함수와 구조화된 동시성을 활용할 수 있습니다.
  1. 코루틴과 스레드의 차이점은 무엇인가요?
  • 스레드는 운영 체제에 의해 관리되며 메모리 및 컨텍스트 전환 측면에서 비교적 비용이 많이 듭니다. 반면에 코루틴은 가벼우며 적은 수의 스레드에서 멀티플렉싱될 수 있습니다. 스레드 관리를 명시적으로 필요로 하지 않고 동시성을 처리할 수 있는 방법을 제공합니다.
  1. 코틀린에서 코루틴을 어떻게 생성하나요?
  • launch 또는 async 빌더를 사용하여 코루틴을 생성합니다. launch 빌더는 fire-and-forget 스타일의 코루틴에 사용되고, async는 코루틴에서 결과를 반환해야 할 때 사용됩니다. 두 빌더 모두 코루틴을 시작하기 위해 코루틴 스코프가 필요합니다.
  1. 코루틴 스코프는 무엇인가요?
  • 코루틴 스코프는 코루틴의 수명을 정의하고 취소를 관리합니다. 코루틴이 실행되는 컨텍스트를 제공하며 보통 활동(Activity)이나 뷰 모델(ViewModel)과 같은 컴포넌트의 라이프사이클에 매핑됩니다.
  1. 코루틴에서 중단 함수(suspend function)의 역할은 무엇인가요?
  • 중단 함수는 스레드를 차단하지 않고 일시 중단하고 나중에 다시 시작할 수 있는 함수입니다. 코루틴 내부나 다른 중단 함수에서만 호출할 수 있습니다. 중단 함수는 코루틴의 구성요소이며 순차적이고 구조화된 비동기 프로그래밍을 가능하게 합니다.
  1. 코루틴에서 Dispatchers의 목적은 무엇인가요?
  • Dispatchers는 코루틴이 실행될 스레드 또는 스레드 풀을 정의하여 코루틴이 작동하는 컨텍스트를 제공합니다. 일반적인 Dispatchers에는 메인/UI 스레드에서 코루틴을 실행하는 Dispatchers.Main과 I/O 바운드 작업을 수행하는 Dispatchers.IO가 있습니다.
  1. 구조화된 동시성(Structured concurrency)이란 무엇인가요?
  • 구조화된 동시성은 코루틴을 올바르게 처리하기 위해 자식 코루틴이 부모 코루틴이 취소될 때 취소되도록 강제함으로써 보장하는 패턴입니다. 이는 리소스 누출을 방지하고 특정 범위(scope) 내의 모든 코루틴이 성공적으로 완료되거나 함께 취소됨을 보장합니다.
  1. 코루틴에서 예외를 어떻게 처리할 수 있나요?
  • 코루틴에서는 기본적으로 예외가 호출 스택을 올라가게 됩니다. 예외를 처리하려면 코루틴 내에서 try/catch 블록을 사용하거나 CoroutineExceptionHandler를 사용하여 처리되지 않은 예외에 대한 전역 예외 핸들러를 설정할 수 있습니다.
  1. launch와 async 빌더의 차이는 무엇인가요?
  • launch 빌더는 결과를 반환하지 않는 호출 및 잊기 코루틴에 사용됩니다. 코루틴을 시작하고 즉시 실행을 계속합니다. 반면에 async 빌더는 미래 결과를 표현하는 Deferred 객체를 반환합니다. 나중에 결과를 검색할 수 있도록 동시 계산을 수행하고 결과를 얻을 수 있게 합니다.
  1. 어떻게 코루틴을 취소할 수 있나요?
  • 코루틴은 해당 Job 객체에서 cancel() 함수를 호출하거나 관련 코루틴 스코프를 취소함으로써 취소할 수 있습니다. 취소는 협력적이며, 코루틴 코드는 주기적으로 isActive 속성을 사용하여 취소 여부를 확인하고 실행을 정상적으로 중지해야 합니다.
  1. 코루틴에서 launch와 runBlocking 함수의 차이점은 무엇인가요?
  • launch는 새로운 코루틴을 시작하고 현재 스레드를 차단하지 않고 즉시 Job 객체를 반환하는 코루틴 빌더입니다. 주로 '시작하고 끝내기' 스타일의 코루틴에 사용됩니다.
  • runBlocking은 현재 스레드를 블록하고 내부의 코루틴이 완료될 때까지 기다리는 코루틴 빌더입니다. 주로 테스트 작성이나 최상위 코루틴 코드 실행에 사용됩니다.
  1. 긴 실행 코루틴을 어떻게 처리하여 주요/UI 스레드가 차단되지 않도록 할까요?
  • 긴 실행 코루틴은 주요/UI 스레드가 차단되지 않도록 다른 스레드에서 실행되어야 합니다. Dispatchers.Default 디스패처를 사용하거나 newFixedThreadPoolContext()를 사용하여 사용자 지정 스레드 풀을 생성하여 긴 실행 코루틴을 실행할 수 있습니다.
  1. 코루틴 컨텍스트의 개념을 설명하고 코루틴 실행에 어떤 영향을 미치는지 설명해주세요.
  • 코루틴 컨텍스트는 코루틴의 동작 및 컨텍스트를 정의하는 요소들의 집합입니다. 이러한 요소에는 디스패처, 예외 처리기 및 기타 컨텍스트 요소가 포함됩니다. 이는 CoroutineContext 인터페이스에 의해 표현됩니다. 컨텍스트는 부모 코루틴에서 자식 코루틴으로 전파되어 실행에 영향을 미칩니다.
  1. withContext은 코루틴에서 어떤 목적을 가지고 사용되나요?
  • withContext는 현재 코루틴의 컨텍스트를 다른 디스패처로 전환할 수 있는 중단 함수입니다. 현재 코루틴을 일시 중단하고 지정된 디스패처로 전환한 뒤 제공된 코드 블록을 실행한 다음 코루틴을 원래의 컨텍스트로 다시 재개합니다.
  1. 코루틴을 사용할 때 동시성 문제(경쟁 조건 등)를 어떻게 처리하나요?
  • 코루틴은 기본적으로 단일 스레드나 디스패처 내에서 코드를 순차적으로 실행하여 경쟁 조건에 대한 보호를 제공합니다. 공유 가능한 가변 상태에 동시에 접근해야 한다면 Mutex나 Atomic 타입과 같은 동기화 메커니즘을 사용하여 스레드 안전성을 보장할 수 있습니다.
  1. 코루틴 취소와 스레드 인터럽트와의 차이를 설명해 드릴게요!
  • 코루틴 취소는 코루틴이 명시적으로 취소되는 협력적인 프로세스입니다. 이를 위해 해당 코루틴의 Job 객체를 이용하여 cancel()을 호출하거나 연관된 코루틴 스코프를 취소합니다. 취소는 협력적이며, 코루틴이 자원을 정리하고 실행을 고요하게 중지할 수 있습니다. 반면에 스레드 인터럽트는 한 스레드에서 다른 스레드로 보내는 인터럽트 신호이며, 갑작스러운 종료와 잠재적인 리소스 누출을 유발할 수 있습니다.
  1. 코루틴이 무한히 실행되는 것을 방지하기 위해 어떻게 타임아웃을 지정할 수 있나요?
  • 코루틴에 타임아웃을 지정하려면 withTimeout 또는 withTimeoutOrNull 함수를 사용할 수 있습니다. withTimeout은 지정된 시간을 초과할 경우 TimeoutCancellationException을 throw하며, withTimeoutOrNull은 예외를 throw하지 않고 대신 null을 반환합니다.
  1. 독립적으로 코루틴을 실행하는 것과 비교했을 때 구조화된 동시성을 사용하는 장점은 무엇인가요?
  • 구조화된 동시성은 부모 코루틴이 취소되면 자식 코루틴도 취소되도록 강제하여 코루틴의 라이프사이클 및 취소를 관리하는 데 도움을 줍니다. 이를 통해 리소스 누출을 방지하고 범위 내의 모든 코루틴이 함께 완료되거나 취소되도록 보장하여 더 나은 제어와 신뢰성을 제공합니다.
  1. 코루틴은 코루틴 실행 체인의 다른 부분에서 발생한 예외를 어떻게 처리하나요?
  • 코루틴은 기본적으로 예외를 호출 스택으로 전파합니다. 코루틴에서 예외가 발생하면 부모 코루틴이나 코루틴의 범위로 전파됩니다. 예외 처리를 위해 코루틴 내에서 try/catch 블록을 사용하거나 CoroutineExceptionHandler를 사용하여 전역 예외 처리기를 설정할 수 있습니다.
  1. 코루틴 채널의 개념을 설명하고 코루틴 간 통신에 어떻게 사용될 수 있는지 알아보세요.
  • 코루틴 채널은 논블로킹 방식으로 데이터를 주고받음으로써 코루틴 간 통신을 제공합니다. 채널은 생산자-소비자 패턴, 스트림 처리 또는 코루틴이 데이터를 교환해야 하는 다른 시나리오를 구현하는 데 사용될 수 있습니다. 채널에는 Channel, BroadcastChannel 및 ConflatedBroadcastChannel과 같은 다양한 유형이 있으며, 각각이 고유한 특성과 사용 사례를 갖습니다.
  1. 코루틴에서 async와 await의 목적은 무엇인가요?
  • async는 미래 결과를 나타내는 Deferred 객체를 반환하는 코루틴 빌더입니다. 동시 실행을 허용하며, 나중에 await나 다른 Deferred 함수를 사용하여 결과를 검색할 수 있는 방법을 제공합니다.
  1. 구조화된 동시성은 범위 내의 모든 코루틴이 함께 완료되거나 취소된다고 보장합니다. 이는 더 이상 필요하지 않을 때 코루틴과 관련된 리소스를 자동으로 취소하고 해제하여 리소스 정리를 관리하는 데 도움이 됩니다.

  2. 코루틴 스코프의 개념과 중요성에 대해 설명해주세요.

  • 코루틴 스코프는 코루틴의 수명을 정의하고 취소를 관리합니다. 코루틴을 시작하고 관리하는 구조화된 방법을 제공하여 동시 작업의 더 나은 제어와 조직을 가능하게 합니다.
  1. 코루틴 빌더란 무엇인가요?
  • 코루틴 빌더는 코루틴을 생성하고 시작하는 함수입니다. Kotlin에서 일반적으로 사용되는 코루틴 빌더에는 launch, async, runBlocking, withContext 등이 있습니다.
  1. 코루틴에서 공유되는 가변 상태를 처리할 때 스레드 안전성을 어떻게 보장하나요?
  • 코루틴 내에서 공유되는 가변 상태에 접근할 때 락, 뮤텍스 또는 원자 연산과 같은 동기화 메커니즘을 사용하여 스레드 안전성을 보장할 수 있습니다. Kotlin의 Mutex 및 Atomic 유형을 사용하여 스레드 안전성을 달성할 수 있습니다.
  1. 코루틴 디스패처(dispatcher)의 개념과 사용법을 설명해 드리겠습니다.
  • 코루틴 디스패처(dispatcher)는 코루틴이 실행될 스레드나 스레드 풀을 결정합니다. 디스패처는 코루틴이 실행되는 컨텍스트를 지정하고 코루틴 간의 스레드 간 전환을 처리합니다. 일반적인 디스패처로는 Dispatchers.Default, Dispatchers.IO, Dispatchers.Main 등이 있습니다.
  1. 코루틴에서 구조화된 오류 처리를 어떻게 핸들링하나요?
  • 코루틴에서는 코루틴 내부에서 try/catch 블록을 사용하거나 CoroutineExceptionHandler를 이용하여 전역 예외 처리기를 설정하여 오류를 처리할 수 있습니다. 또한 supervisorScope 또는 supervisorJob을 사용하여 부모 코루틴에 영향을 미치지 않도록 자식 코루틴의 실패를 격리할 수 있습니다.
  1. 코루틴 Flow의 개념과 다른 데이터 스트림 처리 방식에 비해 어떤 이점이 있는지 설명해 드릴까요?
  • 코루틴 Flow는 코틀린에서 소개된 반응형 스트림 처리 라이브러리입니다. 값의 스트림을 비동기적으로 순차적으로 나타내는 방법을 제공합니다. 코루틴 Flow는 코루틴의 이점(구조적 동시성 및 취소 지원 등)을 반응형 스트림의 기능과 결합한 것입니다.
  1. launch와 async의 반환 유형에는 무엇이 다른가요?
  • launch는 코루틴의 라이프사이클을 나타내는 Job 객체를 반환하며, 코루틴을 관리하고 취소할 수 있습니다. 반면에 async는 미래 결과를 나타내는 Deferred 객체를 반환하며, await 또는 유사한 함수를 사용하여 결과를 검색할 수 있습니다.
  1. 비동기 작업에서 취소를 처리하는 방법은 무엇인가요?
  • 코루틴에서의 취소는 협력적입니다. 코루틴 내에서 주기적으로 isActive 속성을 확인하거나 ensureActive() 또는 yield()와 같은 함수를 사용하여 취소 지점을 확인함으로써 취소를 처리할 수 있습니다. 또한 withTimeout 또는 withTimeoutOrNull을 사용하여 코루틴에 대한 시간 제한을 설정할 수도 있습니다.
  1. 결과 처리 측면에서 launch와 async의 차이는 무엇인가요?
  • launch는 결과를 직접 반환하지 않으며, 주요 목적은 수행 및 잊기 방식의 코루틴을 수행하는 것입니다. Job 개체를 반환하며, 이를 사용하여 코루틴의 라이프사이클을 관리할 수 있습니다.
  • 반면 async는 미래 결과를 나타내는 Deferred 개체를 반환합니다. 이 결과는 Deferred 개체에서 await()를 사용하여 얻을 수 있습니다.
  1. 코루틴 내에서 발생한 예외를 어떻게 처리할 수 있나요?
  • async를 사용할 때 예외는 Deferred 개체 내에 지연되어 래핑됩니다. 이러한 예외를 처리하기 위해 try/catch 블록 내에서 Deferred.await()를 사용하여 잠재적인 예외를 catch하고 적절히 처리할 수 있습니다.
  1. 코루틴 컨텍스트 전파란 무엇인가요?
  • 코루틴 컨텍스트 전파는 부모 코루틴에서 자식 코루틴으로 코루틴 컨텍스트 요소가 자동으로 전파되는 것을 의미합니다. 이를 통해 자식 코루틴이 동일한 코루틴 컨텍스트, 디스패처, 예외 핸들러 및 기타 컨텍스트 요소를 상속받을 수 있도록 보장합니다.
  1. 관련 있는 여러 코루틴을 취소하는 방법은 무엇인가요?
  • 관련 있는 여러 코루틴을 취소하려면 coroutineScope 또는 supervisorScope를 사용하여 코루틴 스코프를 만들 수 있습니다. 해당 스코프를 취소하면 해당 스코프 내에서 시작된 모든 코루틴이 취소됩니다.
  1. 코루틴에서 yield() 함수의 목적은 무엇인가요?
  • yield() 함수는 코루틴을 일시 중단하여 다른 코루틴이 실행되도록 하는데 사용됩니다. 이는 협력적 멀티태스킹과 유사하며, 코루틴이 자발적으로 실행 양보하여 다른 코루틴이 실행될 수 있는 기회를 주는 것과 비슷합니다.
  1. 중첩된 코루틴과 구조화된 동시성의 개념을 설명해 드릴까요?
  • 구조화된 동시성은 부모 코루틴 범위 내에서 자식 코루틴을 실행하는 아이디어를 장려합니다. 중첩된 코루틴을 사용할 때, 부모 코루틴은 모든 자식 코루틴이 완료될 때까지 기다린 뒤에 자신도 완료됩니다. 이는 계층 구조 내의 모든 코루틴이 적절히 정리되고 취소되도록 보장합니다.
  1. 코루틴은 어떻게 블로킹 작업을 처리하나요?
  • 코루틴은 논 블로킹 대안을 사용하거나 블로킹 작업을 별도의 스레드나 디스패처로 이동시킴으로써 블로킹 작업을 처리할 수 있습니다. 이렇게 하면 코루틴이 실행을 일시 중단하고 그 동안 다른 코루틴이 계속 실행될 수 있게 됩니다.
  1. 코루틴에서 CoroutineScope 인터페이스의 목적은 무엇인가요?
  • CoroutineScope 인터페이스는 코루틴이 시작되고 관리되는 범위를 정의합니다. 이를 통해 launch 및 async와 같은 코루틴 빌더를 제공하며 coroutineContext 및 Job 객체를 제공하여 취소와 구조화된 동시성을 지원합니다.
  1. 코루틴의 타임아웃을 어떻게 처리할 수 있나요?
  • withTimeout 또는 withTimeoutOrNull 함수를 사용하여 코루틴의 타임아웃을 처리할 수 있습니다. 지정된 타임아웃이 초과되면 withTimeout는 TimeoutCancellationException을 throw하고, withTimeoutOrNull은 예외를 throw하는 대신 null을 반환합니다.
  1. 코루틴 취소 전파라는 개념을 설명해 드릴게요.
  • 코루틴 취소 전파는 부모 코루틴에서 자식 코루틴으로 취소가 자동으로 전파되는 메커니즘을 말합니다. 부모 코루틴이 취소되면 모든 자식 코루틴도 취소되어, 코루틴이 올바르게 종료되고 리소스가 해제됨을 보장합니다.
  1. 코루틴에서 CoroutineExceptionHandler 인터페이스의 목적은 무엇인가요?
  • CoroutineExceptionHandler 인터페이스는 코루틴 내에서 발생하는 uncaught 예외를 처리하기 위해 사용됩니다. 이를 통해 코루틴에서 던져지는 예외를 중앙 집중식으로 처리할 수 있는 전역 예외 핸들러를 정의할 수 있는 방법을 제공합니다.
  1. 코루틴의 순차 실행을 어떻게 보장할 수 있나요?
  • await() 및 invokeOnCompletion()과 같은 순차 구성 연산자를 사용하여 코루틴의 순차 실행을 보장할 수 있습니다. 이러한 연산자를 사용하면 코루틴 간의 의존성을 정의할 수 있어 특정 순서로 실행되도록 보장할 수 있습니다.
  1. 코루틴의 asFlow() 함수의 목적은 무엇인가요?
  • asFlow() 함수는 컬렉션, 반복 가능한 객체 또는 다른 유형의 객체를 코루틴 플로우로 변환하는 데 사용됩니다. 이를 통해 동기 데이터 원본을 비동기 스트림으로 변환하여 코루틴 플로우 연산자를 사용하여 처리할 수 있습니다.
  1. 예외 처리 상황에서 구조화된 동시성 개념을 설명해보겠습니다.
  • 구조화된 동시성은 예외가 부모 코루틴의 컨텍스트 내에서 적절히 처리되도록 보장합니다. 자식 코루틴에서 예외가 발생하면, 부모 코루틴으로 전파되어 중앙 집중식 예외 처리와 정리가 가능해집니다.
  1. 동시에 실행되는 코루틴의 수를 제한하는 방법은 무엇인가요?
  • 한정된 크기의 Semaphore 또는 사용자 정의 CoroutineDispatcher를 사용하여 동시에 실행되는 코루틴의 수를 제어할 수 있습니다. 이를 통해 동시에 실행되는 코루틴의 수를 제한할 수 있습니다.

테이블 태그를 Markdown 형식으로 변경하세요.

  1. 코루틴 플로우에서 flowOn 연산자의 목적은 무엇인가요?
  • flowOn 연산자는 플로우의 하위 연산자가 실행되어야 하는 디스패처를 지정하는 데 사용됩니다. 이를 통해 플로우의 실행 컨텍스트를 전환하여 하위 연산자가 특정 디스패처에서 실행되도록합니다.
  1. 여러 코루틴 플로우를 하나의 플로우로 결합하는 방법은 무엇인가요?
  • 여러 코루틴 플로우를 zip, combine, flattenConcat 또는 flatMapConcat과 같은 연산자를 사용하여 결합할 수 있습니다. 이러한 연산자를 사용하면 여러 플로우에서 방출된 값들을 하나의 플로우로 병합하여 복잡한 데이터 처리 시나리오를 지원할 수 있습니다.

코루틴에서 차가운 플로우와 뜨거운 플로우의 차이는 무엇인가요?

  • 차가운 플로우는 터미널 연산자가 적용될 때만 값의 발행을 시작합니다. 차가운 플로우의 각 수집기는 동일한 집합의 발행된 값들을 수신합니다.
  • 다른 한편, 뜨거운 플로우는 수집기가 있는지 여부와 관계없이 값을 발행합니다. 뜨거운 플로우에 추가된 수집기는 추가된 이후에 발행된 값들을 수신합니다.

코루틴 플로우에서 백프레셔를 어떻게 처리할 수 있나요?

  • 코루틴 플로우의 백프레셔는 buffer, conflate 또는 collectLatest와 같은 플로우 연산자를 사용하여 처리할 수 있습니다. 이러한 연산자를 사용하면 값의 발행 및 소비 속도를 제어하여 백프레셔로 인한 오버플로우나 지연을 방지할 수 있습니다.
  1. 코루틴 취소 범위의 개념을 설명해 드릴까요?
  • CoroutineCancellationScope은 CoroutineScope 인터페이스에 의해 정의되며, 코루틴을 시작하고 관리하는 범위를 생성할 수 있도록 합니다. 해당 범위가 취소되면 해당 범위 내에서 시작된 모든 코루틴이 취소되어 적절한 정리와 종료가 보장됩니다.

코루틴은 현대 안드로이드 개발의 기본적인 부분이 되었으며, 코루틴에 대한 강력한 이해는 Kotlin 안드로이드 개발자에게 꼭 필요합니다. 본 문서에서는 2024년에 만날 수 있는 주요 코루틴 면접 질문 중 일부를 다뤘습니다. 이러한 질문과 그에 대한 답변을 숙지함으로써 면접에서 자신의 지식과 능숙함을 효과적으로 보여 줄 준비를 하게 될 것입니다. 계속해서 연습하고 코루틴을 탐구하여 자신감 있고 숙련된 Kotlin 안드로이드 개발자로 성장해 나가세요.