밤 10시, 서울의 한 프로그래밍 북카페.
"저기요, 혹시 이 자리 사용 중인가요?"
노트북 화면에 집중하고 있던 내가 고개를 들어보니, 커피 한 잔을 든 여자가 서 있었다. 까만 머리카락, 지적인 인상, 그리고 맥북 프로와 코틀린 스티커가 붙은 노트북 가방.
"아니요, 괜찮아요." 내가 자리를 정리하며 말했다.
그녀는 내 화면을 흘끗 쳐다봤다. "안드로이드 개발하시나요? 코루틴 쓰고 계시네요."
내 심장이 빠르게 뛰기 시작했다. 개발자 여성을 만날 확률이 별을 따는 것만큼 희박한데, 코루틴까지 아는 여성이라니.
"네, 맞아요. 코루틴으로 비동기 작업 리팩토링 중이에요. 혹시 개발자신가요?"
"네, 저도 안드로이드 개발자예요. 김서연이라고 합니다."
그렇게 우리의 lifecycleScope
가 시작되었다. 처음에는 낯선 관계였지만, 이제 우리의 관계는 특정 생명주기 안에서 움직이게 되었다.
일주일 후, 우리는 공동 프로젝트를 진행하기로 했다. 핫한 데이팅 앱을 만들자는 것이 서연의 제안이었다.
하지만 점점 우리의 관계는 단순한 동료를 넘어 미묘한 감정이 싹트기 시작했다.
"이 기능, 어떻게 구현하는 게 좋을까요?" 서연이 내 노트북 화면을 가리키며 가까이 다가왔다.
"음, 메인 기능은 부모 코루틴으로 두고, 세부 작업들은 자식 코루틴으로 구현하면 어떨까요? 구조화된 동시성 패턴으로요."
"그러니까... 부모 관계가 취소되면 자식 관계도 모두 취소된다는 거죠?" 서연이 의미심장한 미소를 지으며 물었다.
"정확해요. 마치... 우리 둘 중 한 명이 이 프로젝트에서 빠지면, 우리의 모든 계획도 자동으로 취소되는 것처럼요."
"그런 일은 없었으면 좋겠네요." 서연이 작게 속삭였다.
"이번 주말에 시간 있어요?" 어느 날 저녁, 프로젝트 마무리 후 서연이 물었다.
"네, 괜찮아요. 뭐 계획 있으세요?"
"세 가지 제안이 있는데..." 서연이 장난스럽게 말했다. "어떤 유형의 데이트를 원하는지 물어볼게요."
"첫 번째는 launch
타입이에요. 남산 타워에 올라가서 서울 야경을 보는 거죠. 특별한 결과를 기대하기보다는 그냥 좋은 시간을 보내는 거예요."
"두 번째는 async
타입. 비밀 장소로 당신을 데려갈 건데, 나중에 특별한 선물을 드릴게요. 결과를 기다릴 가치가 있을 거예요."
"세 번째는 runBlocking
타입. 영화관에서 3시간짜리 영화를 보는 거예요. 끝날 때까지 자리에 앉아있어야 하죠!"
나는 웃음을 터트렸다. "세 가지 다 매력적이네요. 근데 runBlocking
은 메인 스레드를 차단하니까, 다른 계획을 못 세울 것 같아요. async
로 해볼까요? 나중에 무슨 결과가 나올지 기대되네요."
"좋아요! 그럼 토요일 오후 2시에 await()
를 호출하세요." 서연이 윙크하며 말했다.
토요일이 왔고, 서연은 나를 한강 공원으로 데려갔다. 피크닉 도구와 와인, 치즈를 준비해온 완벽한 데이트였다.
하지만 갑자기 하늘에서 빗방울이 떨어지기 시작했다.
"이런, 일기 예보에 비 소식은 없었는데!" 서연이 당황했다.
"try-catch
블록이 필요한 상황이네요." 내가 웃으며 말했다.
try {
// 원래 계획: 피크닉
picnicAtHanRiver()
} catch (e: RainException) {
// 예외 발생 시 대체 계획
indoorCafeDate()
} finally {
// 어떤 상황에서든 실행
haveFunWithSeoYeon()
}
"네, 맞아요. 하지만 더 좋은 방법이 있어요. supervisorScope
를 쓰는 거죠." 서연이 제안했다.
"피크닉 계획이 실패해도 다른 계획들은 계속 진행할 수 있게요. 한 가지 계획의 실패가 전체 데이트를 망치지 않도록!"
우리는 근처 카페로 대피했고, 비 내리는 한강을 바라보며 더 깊은 대화를 나눴다. 때로는 예외가 더 특별한 경험을 만들어내기도 한다.
한 달이 지나고, 우리는 서로에게 더 끌렸지만 아직 감정을 고백하지는 않았다.
어느 날 밤, 나는 용기를 내어 메시지를 보냈다.
"지금 바빠요? 당신에게 말하고 싶은 게 있어요."
서연의 답장이 즉시 왔다. "네, 말씀하세요."
그런데 문자 메시지로는 내 마음을 제대로 전할 수 없을 것 같았다. 더 안전하고 직접적인 통신 방법이 필요했다.
// 채널 생성
val heartChannel = Channel()
// 내 감정 전송
launch {
heartChannel.send(Feeling.Love)
heartChannel.send(Feeling.Care)
heartChannel.send(Feeling.Hope)
}
// 서연의 수신 대기
launch {
for (feeling in heartChannel) {
processFeeling(feeling)
}
}
"서연씨, 우리 직접 만나서 이야기할까요? 채널처럼 안전하게 마음을 주고받을 수 있는 곳에서요."
그날 밤, 한강변 벤치에서 우리는 서로의 감정을 고백했다. 마치 채널처럼 안전하게 감정을 주고받았고, 더 이상 버퍼링 없이 서로를 이해하게 되었다.
연인이 된 후, 우리의 관계는 단순한 일회성 데이터 교환이 아닌 지속적인 감정의 흐름이 되었다.
"나 오늘 집에서 코틀린 책 읽다가 당신 생각나서 사진 찍었어." 서연이 메시지와 함께 사진을 보냈다.
이렇게 서로의 일상을 공유하는 것은 마치 Flow
와 같았다. 하나의 감정이나 생각이 아니라, 시간에 따라 여러 감정과 경험이 지속적으로 흘러갔다.
// 서연의 일상 공유 Flow
val seoYeonFlow = flow {
while (true) {
val moment = captureSpecialMoment()
emit(moment) // 특별한 순간을 전송
delay(Random.nextLong(1000, 86400000)) // 랜덤한 시간 간격
}
}
// 내 Flow 구독
launch {
seoYeonFlow.collect { moment ->
cherish(moment) // 매 순간을 소중히 여김
sendLoveBack() // 사랑을 다시 보냄
}
}
"Flow가 있어서 우리 관계가 더 풍요로워진 것 같아요." 어느 날 서연이 말했다. "매 순간 서로에게 새로운 가치를 전달하고, 끊임없이 진화하는 느낌이에요."
6개월이 지난 어느 날, 우리는 휴가를 계획했다. 제주도 3박 4일 여행.
"이번 여행 동안은 회사 연락 다 끊고, 우리만의 컨텍스트에서 지내요." 서연이 제안했다.
코루틴 컨텍스트처럼, 우리는 여행이라는 특별한 환경에서 우리만의 규칙과 분위기를 만들었다. 디스패처(우리가 무엇을 할지), Job(여행 일정), 그리고 우리만의 요소들로 구성된 완벽한 컨텍스트였다.
val ourVacationContext = dispatcherOf(JejuIsland) +
jobOf(FourDaysTrip) +
elementsOf(NoWork, OnlyUs, FullRomance)
제주도의 푸른 바다를 배경으로, 우리는 더 깊은 사랑을 확인했다. 외부 세계와 단절된 우리만의 컨텍스트에서, 우리는 서로에게 더 집중할 수 있었다.
1년이 지나고, 서연이 해외 취업 제안을 받았다. 실리콘밸리에 있는 대형 테크 기업이었다.
"어떻게 해야 할지 모르겠어..." 서연이 울먹였다. "이건 내 꿈이었지만, 우리 관계는..."
마치 갑작스러운 코루틴 취소처럼, 우리의 미래가 불확실해졌다. 하지만 코루틴 취소가 항상 나쁜 것은 아니듯이, 이것이 우리 관계의 끝을 의미하지는 않았다.
"서연아, 너의 꿈을 응원해. 우리 관계는 취소되는 게 아니라, 일시 중단되는 거야. 나중에 다시 재개될 수 있어."
// 장거리 연애 시작
val longDistanceRelationship = launch {
try {
while (isActive) { // 관계가 활성화되어 있는 동안
sendLoveMessage()
videoCall()
planNextVisit()
delay(24.hours) // 매일 연락
}
} catch (e: CancellationException) {
// 취소 시 정중히 정리
farewell()
} finally {
// 어떤 상황이든 사랑은 남음
saveMemories()
keepHopeAlive()
}
}
서연은 미국으로 떠났지만, 우리의 관계는 취소되지 않았다. 대신 우리는 새로운 형태의 관계를 구축했다. 어려운 상황이었지만, 협력적인 취소 메커니즘처럼 우리는 서로의 입장을 존중하며 지속 가능한 방법을 찾았다.
2년 후, 서연이 한국으로 돌아왔다. 그녀는 실리콘밸리에서의 경험을 살려 서울에 자신의 스타트업을 설립했다.
"돌아와서 정말 기뻐요." 공항에서 서연을 꼭 안으며 말했다.
"나도. 이제 우리의 GlobalScope
를 시작할 준비가 됐어."
"GlobalScope? 그거 메모리 누수 위험 있다고 하지 않았어?" 내가 농담했다.
서연이 웃었다. "맞아요. 그래서 이걸 준비했죠."
그녀는 작은 반지 상자를 꺼냈다.
"이건 우리만의 CoroutineScope
예요. 영원히 함께하는 스코프. 메모리 누수 없이, 서로를 책임지는 관계. 우리의 구조화된 동시성 인생을 함께 시작해볼래요?"
답은 물론 "네"였다.
우리의 새로운 코루틴 스코프는 그렇게 시작되었고, 우리는 여러 비동기 작업(결혼, 집 마련, 창업, 가족 계획)을 효율적으로 함께 관리해나갔다.
사랑도 코루틴처럼, 잠시 일시 중단되더라도 결국 재개되어 더 아름다운 결과를 만들어낸다는 것을 우리는 알게 되었다.
val ourLove = SupervisorJob() + Dispatchers.Life
val eternalScope = CoroutineScope(ourLove)
eternalScope.launch {
liveHappilyEverAfter()
}