[번역] 코딩 인터뷰에서 Golang을 사용해야하는 이유

Why You Should Use Golang in Interviews의 원저자에게 허락을 맡고 번역한 글입니다
자연스러운 전개를 위해 번역 중 약간의 의역이 들어갔습니다
go go gopher!

요즘 다음에 있을 면접을 위해 코딩 인터뷰를 준비하는데, 연습으로는 대부분 Leetcode에 있는 데이터 구조와 알고리즘 문제를 풀고 있다. Python과 Java는 이런 인터뷰를 위해 가장 많이 쓰이는 언어이다. Python은 그 간결함과 슬라이싱, 맵과 리스트같이 사용하기 쉬운 자료 구조를 포함한 문법적 유용성 덕분에 인기가 많다. Java는 굉장히 유연한 데다가 자료 구조를 가르치거나 구현할 때 잘 맞는 객체 지향적 추상화 덕분에 많이 쓰인다.

그렇다면 왜 Go를 사용해야할까?

Go는 Python과 Java의 장점을 잘 섞어놓은 언어이다. 또한 코딩 인터뷰에 도움이 되는 많은 요소들을 가지고 있다. 여기에 더해서 언어 자체가 가능한 한 단순하게 만들어져있어 쓰고 배우는 데 어렵지 않다


1. Go는 놀랄 정도로 단순하다

Go는 Python과 C에서 좋은 점들을 가져와 디자인되었다. 코딩 인터뷰를 볼 때에는 단순함이 중요하다. 인터뷰가 시작되면 문제를 생각하고, 설명하고, 알고리즘을 짜는데 오직 45분에서 60분의 시간밖에 주어지지 않는다. 이 때문에 Python이 코딩 인터뷰에 잘 맞는 것일 것이다.

Go는 문제를 푸는 사람으로 하여금 중요하지 않은 부분을 직접 만들거나 구현체 세부 사항을 생각하는데 신경쓰지 않고도 C 또는 Java 같은 미세한 제어를 수행할 수 있게 해주는 반면 Python의 단순성과 용이성을 제공한다.

여기에 몇가지 예제가 있다:

Hello World

간단하지 않은가?

Two Sum
Depth First Search

2. Go는 자료 구조를 만들기에 좋다

위에서 예제를 통해 트리 자료구조를 만들어봤다. 연결 리스트 또한 이와 많이 비슷하다.

트리나 연결 리스트에 포인터를 사용하면 Python이나 Java에서의 값의 직접 전달(pass-by-value)이나 숨겨진 포인터를 쓰는 것보다 자료 구조를 더 섬세하게 다룰 수 있다. 이것은 C에서 포인터를 사용하는 것보다 훨씬 쉽다.

Go는 또한 최대한 표현력을 가지면서도, 최대한 간결할 수 있도록 세 가지의 내장 자료 구조를 가지고 있다. 바로 맵, 배열(고정 크기 배열), 슬라이스 (조정 가능한 배열)이다. 이것들은 Python에 내장된 맵과 리스트, 셋, 튜플과 비슷하다. (셋과 튜플은 Go의 배열과 맵으로 구현할 수 있다) 내장된 자료 구조를 갖고 있거나 이를 구현하기 쉽다는 것은 장황하게 짜여진 Java보다 낫다고 생각된다. 특히 시간이 없을 때는 더욱 그렇다. Go에서는 또한 함수에서 하나 이상의 반환을 할 수 있다. 위의 twoSum 함수에서 그 예를 확인할 수 있다:

index, ok := m[target — num]

이러한 특징은 index 가 존재 할 때(ok가 참일 때) 와 그렇지 않을 때를 다루는 것을 정말 쉽게 만들어준다.

3. Go는 타입을 가지고 있다 (정적 언어이다)

Python으로 코딩 인터뷰를 준비하다보면 자주 타입의 부재 때문에 곤경을 겪는다. 그리고 그 곤경은 스트레스가 높은 환경에서 수정과 디버깅을 하기 어렵게 만든다. 그 예중에 하나는 코드 내에서 내가 슬라이싱하고 있는 대상이 문자열인지, 맵인지, 리스트인지, 리스트라면 변수 값은 어떤 것이 들었는지같은 것들을 전혀 알수 없다는 것이다. Go에서 타입을 활용하는 것은 정말 쉽다. 하나의 함수로 예를 들어 보자면:

sumSlice

이 함수를 Python으로 변환하면 다음과 같다:

sum_lst

Python의 한줄짜리 답변은 무시하자, Go로 짜여진 함수를 보면 꽤나 깔끔하다! 설명을 조금 하자면, sumSlice[]int 타입의 slice 를 입력으로 받아 int 값을 반환하는 함수이다. tot 변수는 int 타입으로 추론되기 때문에 우리가 굳이 직접 타입을 선언할 필요가 없다. range slice 는 Python의 enumerate(slice) 와 같은 역할을 한다. 여기서 _ (index값을 무시한 것)은 int 타입으로 추론되고 val 또한 int 타입으로 추론된다. 결국 이것은 간결함을 유지하면서도 필요한 타입 정보를 모두 가질 수 있다는 것을 의미한다.

4. Go는 포인터를 가지고 있다

연결 리스트를 뒤집어보라는 요청을 받고 나면 왜 포인터가 중요한지 알 수 있을 것이다

위에서 포인터를 통해 무거운 데이터 구조를 보다 세밀하게 제어할 수 있는 방법에 대해 언급했다.

여기에 추가로, 포인터를 활용하면 쉽게 메모리를 관리할 수 있고 구조체를 수정하거나, 구조체를 복사해서 사용하고 싶지 않을 때 더욱 효과적일 수 있다. 코딩 인터뷰에서는 빠르고 효율적인 메모리 관리가 중요하다.

5. Go는 Generic이 없다.

이것은 Go의 흥미로운 디자인 선택이다. 나는 예쁜 추상화를 위해서(가끔 지나치게 장황한 추상화를 하기도 한다) generic을 잘 활용하는 편이다. 당신이 generic에 대해서 어떻게 생각하는지와 상관 없이, 그것을 없애는 것은 언어를 단순하게 만든다. 그리고 코딩 인터뷰에서는 보통 generic이 중요하지 않다. 코딩 인터뷰에서는 integer나 string같이 하나의 타입만 다루는데 이것은 generic 없이도 코드를 더 깔끔하고 쉽게 짤 수 있게 해준다. 살다 보면 가끔은 지나친 추상화가 필요하지 않을 때가 있는데, 특히 코딩 인터뷰에서 그렇다.

다른 장점들

상단에서 언급된 대부분은 클래식한 자료 구조나 알고리즘 코딩 인터뷰를 위한 것이다. 물론 그 외에 다른 장점들도 많다!

6. Go를 통해 면접자에게 인상을 남길 수 있다

솔직히 이 점이 내가 Go로 코딩 인터뷰를 준비하는 이유이다. 면접자들은 보통 정말 많은 사람들을 본다. 그 사이에서 눈에 띄고 싶다면? 답은: Go를 사용하는 것이다! 만약 당신이 수백 명의 다른 개발자들과 똑같다면 면접자는 아마 Python이나 Java를 사용한 사람들은 기억하지 않을 수도 있다. 하지만 아름답고, 간결함을 자랑하는 Golang을 사용한 한 명의 괴짜(혹은 천재?)는 기억할 수 있다.

이 글이 나온 이후에 많은 사람이 golang을 사용하게 되어 여기로부터 오는 이득이 희석될 수 있다. 그러면 나는 OCaml이나 F#같은 것을 사용해야 할 것이다. 이것이 바로 Efficient Interviewing Language Hypothesis 에서 나오는 끝없는 순환이다. (하하)

7. Go는 훌륭한 동시성 지원을 가지고 있다

또한 무엇이 1x의 지원자를 10x의 지원자와 구분할 수 있을까? 바로 단순히 알고리즘 문제를 푸는 것을 넘어서서 하드웨어적이거나 실제 실무의 문제들을 더욱 효과적으로 구현할 수 있도록 고려하는 것이다. 예를 들어 동시성, 캐시, 한정적인 메모리, 다수의 머신을 지원하는 등의 문제가 있을 수 있다.

Jane Street는 이것을 그들의 인터뷰 가이드Think about Real Computer 문단에서 이렇게 묘사했다.

하지만 시스템 개발에 대한 몇몇의 직무에서 우리는 깊은 지식을 기대한다. 당신이 캐시의 효과나 IO 패턴 혹은 메모리, CPU의 가용성과 같은 것을 고려한다면 일반적으로 그것은 큰 가점이 될 것이다.

Go는 동시성을 염두에 두고 서버/시스템 언어로 쓰이도록 디자인되어 있다. CPU의 성능을 최대한으로 쓸 수 있도록 하는 것은 Go의 목표이다. 만약 면접자에게 큰 인상을 주고 싶다면 goroutine을 활용해 알고리즘을 더욱 빠르게 만들어 볼 수 있다.

여기에 A Tour of Go에서 가져온 goroutine으로 만든 이진 트리의 예가 있다:

goroutine으로 해볼 수 있는 다른 예로 이론적으로 빠른 점근적(asymptotic) 속도 향상을 위한 병렬 합병렬 정렬이 있다.

병렬 합

면접자들은 동기화에 대해서도 관심이 많다. 동기화를 하다보면 자주 어려운 버그들을 만나게 되어 기능을 제대로 구현하는 것이 쉽지 않다. Go는 안전한 코드를 쉽게 짤 수 있게 해준다. 만약 당신이 mutex를 활용하거나 워커 풀을 잘 만들어 쓰고 싶다면 Go로 해보는 것을 추천한다.

8. Go는 시스템 설계 질문에 도움이 된다

시스템 설계 문제는 인터뷰를 볼 때 자주 나오는 문제중에 하나이다. 면접자는 어떤 문제를 효과적으로 풀기 위해서 어떻게 시스템을 구성할 것인지 물어본다. Go는 서버/시스템을 위해 만들어진 언어이고 아키텍쳐를 효율적으로 만들며 간단하게 묘사하기 쉽다. 예를 들어서, Go에서는 HTTP 엔드포인트와 API를 만들기 쉽다. 만약 높은 성능이 필요하다면 goroutine과 동기화를 사용하면 된다. Go는 또한 시스템을 위한 실제 서비스에서도 많이 쓰인다. 가장 유명한 것들 중 하나로 Kubernetes가 있다.

9. 다시 한 번 생각할 수 있다

이건 연습을 할 때 큰 도움이 된다. 가끔 나는 문제를 풀다 막히거나 답을 생각해 낼 수 없을 때가 있다. 다행히 인터넷에는 도움이 되는 자료가 많지만 대부분 Java나 Python으로 이루어져 있다. Go는 이들과 문법이 비슷해서 이를 Go로 변환하는 것은 크게 어렵지 않지만 다른 언어로 문제를 푼다는 것은 단순히 복사하는 것에서 벗어나 지금 쓰고 있는 것에 대해서 다시 한 번 생각하게 만든다. 바로 그 생각이 실력을 향상시키는 비법이다.

10. Go로 일을 구할 수 있다

나는 Go를 좋아한다. Go는 굉장한 언어이다. 혹시 Google 혹은 Go를 사용하는 회사가 이 글을 보고 있다면, 나는 그곳에 가서 이 굉장한 언어를 계속해서 사용할 수 있다. (연락 주세요!)

그래서 왜 Golang을 사용해야 할까?

지금까지 왜 Go로 프로그래밍 인터뷰를 봐야 하는가에 대해서 알아봤다. 하지만 그렇다고 모든 사람이 Python이나 Java를 사용하지 않고 (아니면 Javascript나 C++ 혹은 그 무엇) Go를 선택한다는 이야기는 아니다. 요약하자면, Go는 Python의 단순함, C의 세밀한 컨트롤, 그리고 Java의 추상화와 조직화 특성을 가지고 있다. 거의 프로그래밍 인터뷰로 유명한 회사가 프로그래밍 인터뷰를 위한 완벽한 언어를 만든 것 같다. 이것은 Interviewer wow factor와 더불어 Go를 프로그래밍 인터뷰에서 사용하기에 훌륭한 언어로 만들어 준다.

Go LeetCode Examples

여전히 증명이 필요한가? 최고의 방법은 한 번 사용해보는 것이다! 다음은 몇가지의 Leetcode 예제들이다.

Basic: Two Sum

list (slice)인 num 을 받아서, 합해서target 이 될 수 있는 값의 index를 반환해준다. 만약 답이 없으면 nil 을 반환한다. 이건 실제로 존재하는 인터뷰 문제이므로 당신이 Go가 얼마나 대단한지 알 수 있는 좋은 예제가 될 수 있다.

twoSum

LeetCode Easy: Remove Duplicates from Sorted List

정렬된 연결 리스트를 받아서 중복된 모든 요소들을 지워준다. 결과적으로 모든 요소들은 유일한 값을 갖게 된다. 아래는 포인터를 활용한 단순한 답이다.

deleteDuplicates

LeetCode Medium: Find First and Last Position of Element in Sorted Array

오름차순으로 정렬된 integer 배열인 nums 와 integer의 target 을 받아서 target 값의 시작하는 위치와 끝나는 위치를 찾는다. 만약 target 이 발견이 안되면 [-1, -1]를 반환하면 된다.

시작점과 끝점을 찾는데 두 개의 이진 탐색으로 풀었다.

searchRange

LeetCode Hard: LRU Cache

O(1)의 get/set 기능을 하는 LRU 캐시를 만들어라. 답은 해시 맵과 연결 리스트를 사용했다.

LRUCache