영어 데일리

아무도 대답 할 수 없었던 안드로이드 인터뷰 질문들, 당신은 가능한가?

현욱 정리장 2025. 10. 31. 10:32

https://medium.com/proandroiddev/as-an-interviewer-i-asked-these-android-questions-can-you-answer-them-d623472568f7

 

The Android Interview Questions Nobody Could Answer — Can You?

Warning: This may be harder than you think.

proandroiddev.com

 

3년 이상의 경력을 가진 개발자로써,
나는 팀원 채용 면접에서 면접관으로 참여해왔었습니다.

 

그 시간에 나는 구글에서 흔히 볼 수 있는 퀴즈식 질문들을 넘어서고 싶었다. 

이것들은 간단한 기억만으로도 답변이 가능하다. 

 

대신에 지원자의 깊은 이해도를 진짜로 시험할 수 있는 정교한 질문에 집중했다.

나의 많은 질문들 사이에 , 그중 3가지 아무도 정확하게 대답하지 못했던 질문이 있었다.

이 포스트에서  나는 3개의 질문을 공유하고자한다.

이것을 답변할 수 있나요?

 

질문 1

이 코드 내에서 print 문들이 실행되는 순서는 어떻게 될까요? 또 왜 그렇게 될까요?

// in Activity
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
       
    lifecycleScope.launch {
        println("a")
    }
    
    GlobalScope.launch {
        println("b")
    }

    println("c")
}

 

내가 기대 했던 대답 

a -> c -> b

 

코루틴은 논블로킹(Non-blocking) 이라고 종종 설명되는데, 
그 이유는 실제로 스레드를 막지 않고 실행되기 때문입니다.

 

그래서 코루틴 스코프를 열고 실행하더라도 메인 쓰레드는 블록킹 되지 않습니다. 

대신 내부의 코루틴 스케줄러가 dispatchers를 통해 비동기적으로 작업을 처리합니다. 

 

이러한 관점에서 c가 먼저 실행되는 것처럼 느껴질수도 있지만, 

하지만 lifecycleScope는 기본적으로 Dispatchers.Main.immediate를 사용합니다. 

이 디스패처는 현재 쓰레드가 메인 쓰레드 일 경우 별도의 디스패처 없이 즉시 실행됩니다. 

 

그 결과로써 a 가 먼저 실행됩니다.

그리고 c가 동기적으로 실행됩니다.

마지막으로 별도의 스레드 풀에서 논블록킹으로 실행되는 b가 출력됩니다. 

 

그러므로 마지막 결과는 a - > c > b 입니다

 

질문 팔로업

그러면, 현재 코루틴 스코프를 유지한 채, a b c 가 그 순서대로 출력하게 하려면 ? 

 

내가 기대한 답변 

  • GlobalScope의 launch에 Dispachers.Main을 추가하거나 Dispatcher.Unconfined 을 추가하세요. 
GlobalScope.launch(Dispatchers.Main.immediate) { // or Dispatchers.Unconfined
    println("b")
}
  • GlobalScope의 launch에 CoroutineStart.UNDISPATCHED를 추가하세요
GlobalScope.launch(start = CoroutineStart.UNDISPATCHED) {
    println("b")
}

 

 

DIspatchers.Unconfined는 현재 쓰레드 에서 즉시 실행되고, DIspatchers.Main.immediate 는 메인 쓰레드 내에서 즉시 실행됩니다. Activity 는 메인쓰레드 에서 실행되기 때문에 

이 문맥에서는 두 디스패처 모두 즉시 실행을 시작합니다.

따라서 이 접근방식은 유효합니다.

 

추가적으로 CoroutineStart.UNDISPATCHED는 코루틴 빌더들에서 사용할 수 있는 시작옵션으로, 

현재 호출된 프레임 안에서 즉시 실행을 시작하도록 허용합니다.

 

첫 번째 suspend  되기전까지는 바로 실행됩니다. 

이것은 또한 현재 쓰레드에서 즉시 실행됨을 보장하며 

따라서 원하는 실행순서를 달성하는 또 다른 유효한 방법입니다. 

 

이 질문의 의도 

이 질문은 너가 코루틴 논블록킹 동작을 얼마나 이해하고 있는지와, 

DIspatcher와 CoroutineScope를 구분하고 효과적으로 사용하는 능력을 테스트 하기 위함입니다.

 

질문2 

다음 데이터 클래스 들 중에서 컴포즈 컴파일러가 안정적이라고 고려하는것은 무엇인가요? 

data class A(val value: Int)

data class B(var value: Int)

data class C(val value: MutableState<Int>)

data class D(val value: List<Int>)

data class E(val value: SnapshotStateList<Int>)

data class F(val value: I)

sealed interface I {
    data object Child : I
}

 

내가 기대하는 답변 

A C E

 

컴포즈에서는 클래스 내부의 속성이 불변인지 혹은 컴포즈 런타임이 그 타입을 추적할 수 있는지 여부에 따라 안정성이 결정됩니다.

 

  • A: 안정적입니다: 왜냐하면 내부 프로퍼티가 불변이기 때문입니다.
  • B: 안정적이지 않습니다: 왜냐하면 내부 프로퍼티가 변하고, 추적할 수 없는 속성이기 때문입니다.
  • C: 안정적입니다: 왜냐하면 내부 속성은 변하지만, 컴포즈 런타임이 추적가능하기 때문입니다.
  • D: 안정적이지 않습니다: 왜냐하면 List<T>는 읽기만 가능한 API고, 불변성을 보장하지 않기 떄문입니다.
  • E: 안정적입니다. 왜냐하면 mutable list 는 컴포즈 런타임이 추적 가능하기 때문입니다. 
  • F: 런타임: 그 이유는 해당 프로퍼티가 인터페이스 타입이기 떄문이며, 그 구현체는 오직 런타임 시점에만 결정되기에 컴파일 시점에는 안정성을 판정할 수 없습니다.

그래서 A C E 가 답변입니다.

 

살재 컴포즈 컴파일러 기준 작성 

stable class A {
  stable val value: Int
  <runtime stability> = Stable
}
unstable class B {
  stable var value: Int
  <runtime stability> = Unstable
}
stable class C {
  stable val value: MutableState<Int>
  <runtime stability> = Stable
}
unstable class D {
  unstable val value: List<Int>
  <runtime stability> = Unstable
}
stable class E {
  stable val value: SnapshotStateList<B>
  <runtime stability> = Stable
}
runtime class F {
  runtime val value: I
  <runtime stability> = Uncertain(I)
}


이 질문 의도 
이 질문 테스트는 너가 컴포즈 안정성 규칙을 이해하고 있는지와 Stable과 불안정한 타입을 올바르게 구분하고 적용할수 있는 능력 

 

move beyond ~를 넘어가다 

crafting questions 정교한 질문 

even when ~ 할 때 조차도

from this perspective 이러한 관점에서 

consequently 그 결과로써 

distinguish 구별하다