구글 면접 후기

지난 11월 21일에 구글 코리아 on-site 면접을 봤고, 결과적으로 합격했다.
아직 최종 합격까지는 좀 더 남았지만, 어려운 일은 거의 끝난 것 같다.
6월에 퇴사해서 면접을 보기까지 적지 않은 공부를 했다.
대략 4개월정도 공부했는데, 당연하지만 그 시간동안 공부에 모든 것을 투자했다고 하기는 어렵다.
공부만 죽어라 한 것은 아니어서 열심히 했다고 자랑하기는 부끄럽지만,
적어도 나의 경험담이 누군가에게는 도움이 되지 않을까 싶어 글을 남겨본다.

나는 과학고를 나오지도 않았고, 어렸을 때부터 프로그래밍을 해온 것도 아니다.
주전공이 컴퓨터공학인 것도 아니다.
나는 우연한 계기로 프로그래밍을 접하게 됐고, 생각보다 괜찮고 재미있어서 복수전공을 시작했다.
2014년 9월쯤 처음 파이썬을 공부했다.
한 달 쯤 공부하니 뭔가 만들어보고 싶어서 또 한 달 걸려 간단한 자동화 프로그램을 만들어보고,
그리고 나서는 복수전공을 결심하고 방학 때 학교에서 열리는 C/C++ 특강을 들었다.

요컨대 나는 남들보다 특별히 유리한 조건에서 시작하지는 않았다.

2015년부터 컴퓨터공학을 복수전공 하면서, 나는 그저 ‘남들만큼’ 하기 위해서 아등바등했다.
많은 친구들이 어렸을 때부터 코딩을 해왔거나, 혹은 정보올림피아드 공부를 해왔기에 화려한 이력을 갖고 있었다.
그런 친구들은 여러 프로젝트에 참가해서 결과물을 갖고 있거나, 수상 실적을 보유하고 있다.
나는 기본적인 컴퓨터공학 지식을 갖추면서도 그런 친구들에게 많이 뒤쳐지지 않으려고 틈틈히 개발을 하고 동아리 활동을 했다.
정보올림피아드와 같은 competitive programming(이하 CP)는 너무 잘 하는 친구들이 많아, 기웃기웃 하기는 했지만 그다지 열심히 하지는 않았다.

2017년 말, 내가 졸업할 때쯤 되니 삼성을 비롯한 많은 회사에서 CP와 비슷하게 알고리즘, 자료구조 지식을 필요로 하는 입사 시험이 대세가 되어 있었다.
나는 뒤늦게 하루에 몇 문제씩 풀면서 코딩 연습을 했다.

2017년 초에 구글 인턴 면접을 봤다가 떨어졌었다.
그 때는 레퍼런스를 보면서는 코딩할 수 있지만, 없으면 제대로 하지 못하는 상태였다.
기본적인 클래스 짜기, 혹은 STL 자료구조를 사용하기도 쉽지 않았다.
고배를 마신 후 2017년 말에 구글 면접을 준비하면서 기본적인 언어 특성은 외워갔지만, 알고리즘 지식이 부족했다.
특수한 알고리즘을 알아야만 풀 수 있는 문제는 대개 면접에서 나오지 않지만, 학부 수준에서 다루는 트리, 그래프와 관련된 알고리즘은 자주 나오는 편이다.
가령 BFS, DFS 정도는 언제든지 쉽게 할 수 있어야한다.
2017년 말의 나는 알고리즘을 이해하고는 있었지만 그것을 이용해서 문제를 푸는 정도의 실력은 갖추지 못했기에 구글에서는 떨어졌다.
CP 관련 지식만을 중요시하는 회사만 있는 것은 아니기에, 다른 회사에는 무난하게 합격해서 입사했다.

2018년 6월, 고민 끝에 다니던 회사를 퇴직했다.
적당히 여행도 다니고, 사람도 만나다가 7월부터 공부를 시작했다.

가장 먼저 취약점이라고 생각했던 그래프 문제를 주로 풀었다.
푼 문제 수를 모아서 보고 싶어서 백준에서 주로 문제를 풀었다.
DFS, BFS 문제는 아주 다양하기 때문에 충분히 연습할 수 있었다.
DFS, BFS를 풀면서 자연스럽게 최단거리 문제도 풀게 되었고, 마지막으로는 위상 정렬 문제까지 풀게 되었다.
이 과정에서 공부했던 알고리즘이나, C++ 문법 등은 노트에 간략하게 적으면서 다시 검색하거나 상기해낼 수 있도록 했다.
실수해서 한참 고민했던 부분이나 어려웠던 점 위주로 간략하게 적어서 가급적 돌이켜볼 수 있도록 했다.

틈틈히 코포를 치면서, 부족하다고 느껴지는 부분을 메우려고도 노력했다.
하지만 대회가 주로 밤에 열리다보니 문제 풀기에 급급했고, 틀리거나 못 푼 문제를 review하기는 쉽지 않았다.
다만 인상깊었던 문제나 정말 궁금한 문제는 친구들에게 물어가면서 다시 공부했다.

8월부터는 disjoint set과 같은 자료구조나, LIS/LCS와 같이 유명한 알고리즘 위주로 공부했다.
특별히 순서를 갖고 공부한 것은 아니었다.
백준에 있는 알고리즘 분류를 훑으면서 잘 풀 자신이 별로 없는 것 위주로, 많이 푼 사람 수로 정렬해서 조금씩 풀었다.
이런 과정에서 다른 사람의 코드를 항상 읽으려고 노력했고, 마음에 안 드는 부분은 친구들과 공유하면서 어떻게 개선할 수 있는지 물어보았다.
CP 분야는 초보자가 물어보면 잘 대답해주는 문화가 형성되어 있는 편이라 그런지, 친절하게 대답해주는 친구들이 많아 도움을 많이 받았다.
irc나 트위터 등에서 프로그래머들과 쉽게 교류할 수 있는 환경에 있어서 그랬을 수도 있다.
이렇게 두 달 간 학부 수준에서 다루었던 알고리즘이나 자료구조를 활용해서 문제를 푸는 걸 연습했다.

그러다 8월 말 키우던 고양이가 갑자기 FIP라는 불치병에 걸렸다.
갑작스레 걸려서 심하게 앓다가 결국 세상을 뜨고 말았는데, 투병으로부터 고양이를 보내주기까지 나 또한 너무나 힘겨웠다.
병수발을 들면서도 나을 수 없을 거라는 절망때문에 심적으로 지쳐 가면서도 혹시 모른다는 희망으로 포기하지 못했다.
하지만 증세가 빠르게 악화되어서 일주일만에 결국 뇌사에 이르렀고, 결국 안락사 후 장례를 치러 줄 수 밖에 없었다.
그 과정 동안 너무도 우울하고 힘들어서 공부에 전념하기는 힘들었다.
잠도 늘고 늦잠 자는 게 일상이 되어서 너무 힘들었다.

9월 말쯤 부터는 코딩 인터뷰 완전 분석이라는 책을 보기 시작했던 것 같다.
첫 파트는 면접 예의라든지 경향이라든지에 관련된 내용이라 스킵했고, 문제가 나오는 부분부터 봤다.
긴 코드를 짜야 할 것 같은 문제들은 직접 코딩을 하는 식으로 풀었다.
조금 어려운 문제는 나중에 다시 풀기 위해서 체크해두었는데, 마지막에는 결국 안 봤다.
하지만 다시 봤으면 좋았을 것 같다.
조금 짜증나고 이상한 문제들도 있긴 했지만, 정말로 면접에 나올 만한 문제도 꽤 많았기 때문이다.
이 과정에서, 가령 정렬 파트를 공부한다면 문제와 상관없이 직접 정렬 함수를 종류별로 구현해보았다.
Minimum spanning tree 이야기가 나오면 MST 문제를 백준에서 찾아 푸는 식으로.

그와 동시에 COCI도 같이 풀기 시작했다.
COCI 최근 문제는 너무 어려워서, 2006년 문제부터 하루에 한 세트씩 풀려고 노력했다.
물론 모든 문제를 풀지는 못했고, 최소한 3 문제 이상은 풀려고 했다.
COCI는 모든 문제의 테스트케이스와 해설, 정답 코드가 제공되어 있는데다가 백준에 번역된 문제도 제공되어 있어서 풀기 좋았다.
2시간 정도 잡고 문제를 풀되, 가장 마지막에 손댄 문제는 한 시간 정도씩은 고민했다.
고민한 후에는 답지를 보고, 답지가 이해가 안 되면 코드를 보고, 그래도 안 되면 친구들에게 물어 가며 공부했다.
여기에서 내가 모르고 있었거나 미숙했던 알고리즘이 나오면 그 알고리즘 문제를 찾아서 다시 연습했다.

이 두가지를 병행하면서, 10월부터는 간간히 친구에게 부탁해서 mock interview를 보기 시작했다.
실제 면접 시간과 비슷하게 잡고, 실제 면접 보는 것처럼.

11월에 면접 일정이 잡히고 나서는, 컴파일 하기 전에 최대한 오류를 고쳐서 한 번에 컴파일 되도록 짜는 연습을 했다.
테스트 케이스를 직접 만들어서 코드를 돌려보지 않고 검증하는 연습도 조금씩 하고.
또 mock interview나 문제 풀었던 경험을 통해서, 문제를 받았을 때 어떻게 접근할지 구체적으로 정한 뒤 거기에 맞춰 문제를 풀도록 연습했다.
문제를 풀 때 간과한 점이 있으면 다시 접근 방식을 업데이트 해 가면서, 면접일에도 실수하지 않도록 주의를 기울였다.
가장 마지막으로 정리한 접근 방식은 다음과 같다:

  1. 받은 문제를 간략하게 요약한다
    • 문제를 오인했는지, 혹은 빠뜨린 조건이 있는지 확인할 수 있다.
  2. 이 문제를 풀 때 유의해야 할 부분 및 접근할 방식을 정리한다.
    • 특별히 주의할 부분을 문제를 풀다보면 잊기도 하기 때문에, 미리 정리한다.
    • 주의사항을 통해서 접근 방식이 좌우되기도 하니, 먼저 정리한 것을 유의하며 어떻게 풀 지 정한다.
  3. 그렇게 풀었을 때 예상 시간복잡도.
    • 보통 면접관이 먼저 물어보긴 하지만 어차피 계산해야 하므로 염두에 두는 의미다. 또 너무 naive 한 알고리즘은 바로 개선할 수도 있다.
  4. 코드 작성 후, index에 유의하여 테스트 케이스를 넣어본다.
    • 입력으로 0이나 n에 대해서 인덱스 계산이 잘못 일어날 수도 있으니 염두에 둔 테스트 케이스를 짜서 검증한다.

이렇게 정리된 접근법을 당일에도 잊지 않도록 적어두었다가, 면접 직전에 다시 읽고 상기해서 면접을 봤다.
면접 문제는 생각보다 어려운 것도, 이런 건 안 나오겠지 싶어서 조금 미숙했던 부분에서도, 생각보다 쉬운 문제도 나왔다.
그렇다고 하더라도 핵심 이론은 전부 학부 수업 내에서 다뤄지는 거였다.
면접이 다 끝난 뒤에는 할 만큼 했다는 생각이 드는 동시에, 더 잘 볼 수도 있었는데-하는 아쉬움도 많이 남았다.

면접 직후 느꼈던 아쉬운 것들에는 이런 것들이 있었다:

  • 학부 알고리즘, 자료구조 수업을 조금 더 차근차근 전부 훑어보았으면 좋았을 것 같다.
  • 코딩 인터뷰 완전 분석 책에 실린 문제를 두 번 이상 풀었으면 좋았을 것 같다.
    풀 때는 정말 싫었지만, CP와는 조금 다른 유형의, 책에 실린 문제와 비슷한 유형의 문제가 면접에 실제로 나왔다.
  • COCI를 꾸준히 풀되 한 번에 2시간씩만, 그 이상은 바로 풀이를 보면서 공부했으면 좋았을 것 같다.
    그 이상 고민해야만 풀리는 문제는 안 나오는 것 같다.
    실제로 나온다고 하더라도, 그 이상 고민하는 게 큰 의미는 없는 것 같다.
    수능 수학 문제 공부할 때, 한 문제 가지고 몇 시간씩 고민하는 것보다 답지를 보고 공부한 뒤 비슷한 문제를 계속 풀어보는 게 나은 것처럼.
  • 한 번에 컴파일 에러 없이 코딩하는 연습을 더 많이 했으면 좋았을 것 같다.
    저런 연습을 너무 늦게 시작해서, 면접 당일에도 자잘한 실수들이 있었다.
    물론 그런 실수를 아예 안 하는 사람이 많지는 않을 것 같지만, 실수는 적을 수록 좋으니까.
  • 컴퓨터 구조에 대한 복습을 했으면 더더욱 좋았을 것 같다.
    물론 이건 너무 큰 욕심이다.
    굵직한 내용만 염두에 두고 있어도 충분히 괜찮다.
    물론 세세한 내용까지도 염두에 두고 코딩했으면 더 좋았을 것 같다.

잘 했다고 생각한 점들도 있었다:

  • 평소에 코딩할 때 가급적 함수를 잘 쪼개고, 단순히 복사 붙여넣기 하지 않기 위해서 최선을 다하면서 짰던 것.
    당연하지만 면접에서도 저런 요소를 평가하지 않겠는가?
    꾸준히 코드 퀄리티를 높이도록 연습해왔기 때문에 당일에도 자연스럽게 그렇게 짤 수 있었다.
  • 문제 접근법을 정리하고, 그 방식 토대로 풀도록 연습했던 것.
    평소에 자주 실수하는 부분을 실수하지 않도록 접근 방식을 정리해뒀어서, 실수가 줄었던 것 같다.
    문제의 조건이나, 유의사항 등을 면접 중간에 적으면서 정리해둬서, 잊지 않고 코드에 반영시킬 수 있었다.
  • 공부하면서 새로이 알게되었거나, 깨달은 점을 노트에 정리해두었던 것.
    공부를 하는 중간 중간, 이전에 어떤 공부를 했는지 되돌아 보면서 복습도 하고 의욕도 되살아났었다.
    마지막에 공부했던 걸 쭉 훑어보는 데도 도움이 됐었다.

내가 공부했던 과정이 최적은 아니겠지만, 꽤 나쁘지 않았던 것 같다.
또 앞으로 언젠간 알고리즘 공부를 할 때, 다시 참고할 수 있을 듯하다.

기업 면접 수준의 cp를 준비할 때는 이런 것들에 집중하면 좋을 것 같다:

  • 학부 자료구조, 알고리즘
    정말로 이 안에서 모든 게 다 해결된다. 미진한 부분이 있으면 반드시 복습해야 하고, 없다고 해도 한번 훑어서 손해 볼 것 없다.
  • 다른 잘 하는 사람들의 코드
    코드 퀄리티를 위해서 반드시 다른 사람들의 코드도 확인해야 한다.
    단순히 문제를 푸는 데에만 집중하지 않고, 가독성 좋은 코드를 효율적으로 짜기 위해서 노력하는 사람들이 꽤나 있다.
    그런 코드를 찾아서 읽어보는게 도움이 많이 된다.
    또 그런 코드들은 사용하는 언어의 syntatic sugar를 잘 사용한 경우도 많다.
    그런 syntatic sugar를 찾아서 공부하는 것도 아주 많은 도움이 된다.
  • 언어의 기본적인 문법과 자료구조
    사용하는 언어에서 어떻게 class를 만들고, 배열을 선언하고, 메모리를 할당하는지 정도는 당연히 파악해야 한다.
    나는 이런 것조차 제대로 하지 못해서 고배를 마셨었다.
    또한, 그 언어에 내장된 자료구조가 무엇이 있는지, 또 어떤 특징이 있고 어떤 기능을 제공하는지 파악해두어야 한다.
    물론 모든 것을 파악할 필요는 없다.
    C++ 기준으로 vector, queue, stack, set, priority_queue, map, list 정도면 충분하다.
    물론 많이 알 수록 더 좋지만, 위에서 언급한 것들도 잘 모르는 상태라면 우선 그런 것들부터 제대로 알고 써보는 게 훨씬 중요하다.
  • 나에게 어려운 문제를 오래 고민하기보다, 빠르게 솔루션을 읽거나 주변 사람들의 도움을 받아서 해결하기
    백준의 경우, 질문 게시판이 있어서 푼 사람이 많은 문제는 내가 막힌 부분에 대한 질문이 있을 가능성이 높다.
    그렇지 않더라도, 예의 바르게 막힌 부분에 대해서 잘 정리해서 질문하면 누군가는 잘 대답해준다.
    CP 분야의 아주 좋은 문화이다.
    따라서 그저 끙끙대기보다는, 빠르게 물어보고 반복해서 학습하는 게 더 낫다.