안녕하세요, 윤진입니다.


본 포스팅은 아주 지극히 개인적이며 주관적인 포스팅임을 먼저 밝혀드립니다.

전혀 공식적이지 않은 내용이며,

"어떤 질문이 오갈까요?"라는 제목은 제목 그대로 제가 여러분에게 하는 질문입니다.

알고 계시는 분은 대답해주세요;

저도 궁금합니다. 하핫;


사실 본 포스팅은 블로그에 면접에 대한 문의가 들어와서-

제 경우에는 어떤 식으로 대응했었는지 흐려진 기억을 쥐어짜내어 적었습니다.

거기에 파릇파릇한 SCSA 5기들에게 자문을 구해서 SCSA에 특화된 면접내용을 덧붙였습니다.

질문 내용을 그대로 붙이면 향후 문제(!)가 될 수 있기 때문에 적당히 각색해서 붙입니다.


사실 어느 면접이나 으레 물어보는 질문들이 있습니다.

면접관이 면접대상자를 파악하기 위해 날리는 질문입니다.

우선 일반적인 질문들부터 다뤄보겠습니다.



- 자기소개를 해보세요.

자신에 대해 할 말이 무척이나 많겠지요.

제 이야기를 들어준다는데 하루종일 떠들어도 지치지 않겠네요.

하지만, SCSA가 소프트웨어와 관련된 직무이니만큼,

자신을 잘 나타내는 핵심 키워드를 몇 개 뽑아서 소프트웨어와 잘 버무려야합니다.

뜬금없는 취미나 특기만 줄줄이 나열하는 것보다는,

면접관이 SCSA에 적합한 인재라는 생각이 들도록 소개를 하는게 좋겠죠?

취미가 코딩이고 특기가 앱개발이면 더할 나위없이 좋겠지만,

SCSA에 지원하는 사람 중에 그런 사람은 없을테니 걱정하지 마세요.



- 본인의 강점은 무엇이고 단점은 무엇인지?

자신의 장단점에 대한 문의도 자주 등장합니다.

이럴 때는 뜬구름 잡는 얘기보다는 선명한 경험을 바탕으로 장단점을 이야기하는 것이 좋습니다.

"저는 정의롭습니다" 보다는 "저는 불법복제하는 친구의 싸대기를 때릴 수 있을 정도로 정의롭습니다"가 좋겠죠;


장점이나 단점 모두 면접관의 날카로운 필터링에 걸려 반격기가 들어올 수 있으니 대비해야합니다.

예를 들어 장점으로 정의로움을 어필했다면,

때로는 정의로움이 조직의 피로를 가중시킬 수 있는데 어떻게 생각하냐고 물어올 수 있습니다.

그럴때는 너무 당황하지 말고 상대의 의견을 받아들이면서 적당히 포장할 필요가 있습니다.



- 친구는 많이 사귀는 편인지 깊게 사귀는 편인지?

업무를 하다보면 다양한 사람과 여러가지 일을 진행하기 마련입니다.

많이 사귀는 것도 중요하고 깊게 사귀는 것도 중요합니다.

여기에 정답이 있는지는 모르겠습니다.

그저 자신의 성향을 분명히 이야기한 후 소프트웨어 개발업무와 잘 연결지으면 됩니다.


사람을 쉽게 사귀는 스타일이라면 소프트웨어 협업을 할 때 유리하겠군요.

소프트웨어 협업을 위해서는 아주 디테일한 수준까지 정보가 공유되어야할텐데요,

정보를 공유하려면 여느 인문학과 마찬가지로 '대화'가 가장 빠르고 정확합니다.

pseudo 코드, 수식, 프로그래밍언어, 다이어그램... 아닙니다.

동료를 대하는데 어려움이 없다면 협업도 보다 수월하겠지요.

결국엔 소프트웨어 개발도 인간관계를 빼고는 논할 수 없습니다.



- 존경하는 사람은 있는지?

존경하는 사람을 보면 그 사람의 성향을 간접적으로 살펴볼 수 있습니다.

예전에는 어디서나 그럴듯하게 이야기할 수 있는 이탈리아 정치가나 중세철학자를 먼저 떠올렸었는데요,

요즘에는 주변에 있는 히어로 개발자들이 먼저 떠오릅니다.

정말 대단한 사람들이 너무나 많죠.

"소프트웨어 업계는 좁고, 대단한 사람은 많다"

하지만, 그렇다고 소프트웨어 업계 종사자들 가운데 존경하는 사람을 고를 필요는 없습니다.

줄리어스 시저의 창의적인 전략을 언급하며 소프트웨어 업계에서도 이런 사람이 필요하다고 해도 되겠죠.



- 어떤 리더의 유형이 되고 싶은지?

입사한 직후에는 피라미드 조직에서 바닥을 담당하는 막내이지만,

시간이 지나면 막내에서 벗어나 피라미드의 정점 쪽으로 조금씩 걸어갈겁니다.

그럴 때 어떤 리더가 될지 생각해보세요.

소프트웨어 개발은 철저히 지식노동이기 때문에,

꼰대(!)같은 보스는 개발자들을 유연하게 이끌기 힘듭니다.


어느 면접에서나 묻는 위와 같을 질문들이 나올테고,

다음으로 SCSA에 특화된 질문들이 이어질 겁니다.


실제 면접에서 아래 질문이 그대로 나올리가 없습니다.

이번 기회에 SCSA에 대해 다시 한 번 진지하게 고민해봐주세요.

여러분의 인생이 걸린 일이 될 수도 있으니까요.



- SCSA에 왜 지원했는지?

"어쩌다 보니 그렇게 됐어요."

"취업하려고..."

너무 솔직한 대답입니다.

제가 심사위원이면 탈락 버튼을 누를 수도 있겠네요;


왜 개발자가 되었느냐는 질문에 '치킨집 테크트리'를 타기 위해서라며 농담하던 개발자가 있었는데요,

사실은 소프트웨어 개발을 정말 즐기는 개발자였습니다.

개발이 재미있으니 개발자가 된 셈입니다.

"왜 지원했는지"에 대한 대답도 위의 개발자의 예와 마찬가지일거란 생각이 듭니다.

과연 소프트웨어 개발을 즐기고 있는지 혹은 즐길 준비가 되어있나요?



- 과거 소프트웨어 분야에 관심이 있었는지?

당장 스마트폰만 꺼내보아도 소프트웨어 애플리케이션이 잔뜩 있을텐데요.

소프트웨어는 생활에 밀접하게 붙어있어서 주위를 둘러보면 쉽게 찾아볼 수 있습니다.

관심도에 따라 천차만별의 답이 나올 수 있겠네요.

소프트웨어를 사용하다가 흥미를 느껴 프로그래밍 서적을 뒤적여본 사람도 있을테고,

소프트웨어 UI에 불만을 느껴 고객센터에 개선을 요구한 사람도 있을 것이며,

그저 늘 사용하는 소프트웨어에 고마움을 느껴 앱스토어에서 별점을 후하게 준 사람도 있겠죠. 

어느 대답이든 소프트웨어 자체가 무엇인지 명확히 인지하면 됩니다.



- 과거 소프트웨어 분야에 경험이 있었는지?

더 나아가 소프트웨어를 '사용한' 경험을 넘어 '만든' 경험이 있는지 물어볼 수도 있습니다.

한 번 만든 사람은 다음에는 좀 더 익숙하게 만들테니까요.

C언어나 자바로 "Hello world."라도 찍어봤거나,

엑셀파일을 만들때 비주얼 베이직으로 코딩한 경험이라도 있으면 좋겠지요.

전혀 경험이 없지만 지금이라도 개발이 뭔지 알고 싶으신 분은,

타이젠 SDK를 받아서 샘플앱을 하나 만들어서,

코딩이 어떤 건지 간단히 살펴보는 것도 좋겠네요.

(이 와중에 타이젠 홍보; 용서해주세요.)



- 자신의 전공을 잃는 것인데 괜찮은지?

장차 자신의 전공과 소프트웨어가 만날 수도 있습니다.

하지만 SCSA에서 개발자 교육을 받고 신입사원으로 부서에 배치되면,

한참동안은 자신의 전공과 만날 일은 없을 겁니다.

(자신의 전공이 영어영문학과이거나 수학과라면 바로 써먹을 수 있겠네요.)

대학생활 4년간 배운 내용은 접어두고 다시 초심자로 돌아가 모든 것을 새로 배워야 하는데요,

자신이 가진 것을 '포기'하는 것에 대해 진지하게 고민해봐야 합니다.

자신의 각오와 의지를 충분히 보여주세요!



- 앞으로 소프트웨어 개발을 할 수 있겠는지?

컴공과 학생들이 대학 4년에 걸쳐 배우는 것을,

SCSA는 반년 남짓한 시간동안에 훑습니다.

아무리 노력해도 절대시간이 부족하기 때문에 수많은 난관이 버티고 있을 겁니다.

어쩌면 매일매일이 좌절의 연속일지도 모르겠네요.

혹은 자신이 천직을 찾았다고 신나게 배우는 사람도 있을 수 있겠죠.

이왕 시작했으면 끝까지 가봐야합니다.

이 길이 아니다 싶으면 애초에 도전하지 않는게 현명할 수도 있습니다.

이런 경우 빠른 포기가 능사일 수도 있겠죠.



면접에서 가장 중요하게 보는 것은,

지원자의 의지가 아닐까 싶습니다.


SCSA 면접을 보는 분들에게 좋은 결과 있길 기원합니다.

끝_


추신 : 면접에 대해 여러가지 의견을 들려주신 김기현님, 조예나님, 최수웅님, 홍소희님에게 감사드립니다.

  1. 민근 2015.11.01 12:20

    이렇게 친절히 글을 올려주셔서 감사드립니다!!:)
    전형이 끝나면 좋은 소식으로 직접 감사의 마음을 전하겠습니다!!

  2. 2016.05.06 04:07

    3일뒤에 면접을 보게 됩니다. 주옥같은 글을 발견하며 놀랐고, 조금 더 진지하고 솔직하게 임해야 겠다는 각오를 다지게 되었습니다! 다시 한 번 댓글을 달게 되기를 바라며 감사의 말씀을 올립니다^^

성격을 도무지 종잡을 수 없다고 하여,

'세 쌍둥이'로 불린 한 임원 분이 계셨습니다.

세 쌍둥이 중 첫째 분은 언제나 매우 인자한 미소로 '훌륭하다', '잘했다'를 연발하셨습니다.

둘째는 잔혹하고 포악하여 물건을 던지거나 육두문자를 섞어가며 인신공격을 하셨습니다.

셋째는 조울기가 다분하여 '분'단위로 성격이 바뀌어 어느 장단에 춤춰야할지 갈피를 잡을 수 없었습니다.

문제는 같은 내용의 보고를 해도,

어느 분을 만나느냐에 따라 결과가 달라진다는데 있었습니다.


그런 임원분에게 과감히 반론을 제기했다가 소리 소문도 없이 퇴직한 용자가 계셨습니다.

용자는 퇴직하기 직전,

한 책을 열심히 홍보하고 다니셨죠.

바로- <조엘 온 소프트웨어>

지금은 어디서 무얼 하고 있을지 모르는 용자를 기리며,

<조엘 온 소프트웨어>의 한 챕터에서 제시한 7가지 간단한 코딩문제를 풀어보겠습니다.


1. 원래 저장위치에서 문자열을 역순으로 변환하기


문자열을 역순으로 변환하려면,

- 문자열의 길이를 알아낸 후,

- 문자열의 첫번째 문자와 마지막 문자를 서로 교환하고,

- 문자열의 두번째 문자와 마지막 문자 - 1을 서로 교환하고...

위의 절차를 반복하면 됩니다.


int strrev(char *src)
{
char *end_pointer = NULL;

if (!src) return -1;
if (!*src) return -1;

end_pointer = src + strlen(src) - 1;

while (src < end_pointer) {
char tmp = *src;
*src = *end_pointer;
*end_pointer = tmp;
src++;
end_pointer--;
}

return 0;
}

위의 strrev 함수를 사용하여 'Hello'를 뒤집어보죠.

$ ./test
origin word : (Hello)
reverse word : (olleH)


하지만, strrev는 바이트 단위로 swap하고 있기 때문에,

ASCII처럼 바이트당 한 글자가 지정된 코드페이지에서만  원하는 결과값을 얻을 수 있습니다.

유니코드 한글을 입력하면 아래처럼 엉뚱한 값이 찍히게 됩니다.


$ ./test
origin word : (안녕하세요.)
reverse word : (.��츄옕핅눕�)

이를 해결하기 위해서는 유니코드계열 함수를 사용하면 됩니다.

유니코드 관련 함수는 차후에 다시 다루기로 하죠. :)



2. 연결 리스트를 역순으로 만들기


연결리스트에 삽입된 n개의 노드를 모두 순회하기 위해서는 최소 n번 동안 한 노드에서 다음 노드로 이동해야 합니다.

총 3개의 노드로 이뤄진 아래 그림의 linked list를 보면,

first 노드에서 last 노드까지 3번의 노드간 이동으로 3개의 노드를 탐색하였습니다.

(first 노드에 다다르는 것도 한 번이라 셈함)



위의 linked list를 역순으로 배치하려면,

리스트를 순회하기 위해 소요되는 최소한의 횟수인-

'n'번(!) 이상 노드를 거치면서 loop를 돌아야합니다.

그렇게 하여 아래 그림처럼 next가 가리키는 노드의 방향을 바꿔야 합니다.



prev -> cur -> next로 이동하며 각각의 노드의 next 값을 아래의 루틴처럼 변경합니다.

다음에 탐색하여 나갈 다음 노드를 next 변수에 저장해두고,

현재(cur) node의 next를 이전(prev) 노드로 저장하고,

다음 순회 때에는 현재 노드가 이전(prev) 노드가 되고,

이전(prev) 노드가 현재(cur) 노드가 되어야 합니다.


typedef struct {
void *data;
node *next;
} node;

node *reverse_list(node *first)
{
node *cur = first;
node *prev = NULL;
node *next = NULL;

if (!first) return NULL;
if (!first->next) return NULL;

do {
next = cur->next;
cur->next = prev;

prev = cur;
cur = next;
} while (next);

return prev;
}

O(n)의 복잡도로 순회를 하며 리스트를 역순으로 변경합니다.



3. 한 바이트에서 1인 비트 세기


한 바이트 곧 8비트에서 1인 비트를 세려면,

비트를 하나씩 오른쪽으로 옮겨서 1과 &연산을 해보면 됩니다.


위의 옅은 파랑 영역이 1과 &연산을 하는 구역이다.

이를 코딩해보면 아래와 같습니다.


unsigned char count_bit(unsigned char number)
{
unsigned char count = 0;

while (number) {
count += number & (unsigned char) 1;
number = number >> 1;
}

return count;
}


'unsigned'는 오른쪽으로 shift 시에 가장 왼쪽에 있는 비트가 '0'으로 채워지게 합니다.

'signed' 타입은 가장 왼쪽의 비트가 '1'일 때,

오른쪽으로 shift시키면 다시 1로 채웁니다.

signed로 변수의 타입을 지정하고 while 루프를 돌리면,

'>>' 연산의 결과가 계속 1로 채워지기 때문에 무한루프에 빠지게 됩니다.


여기서 한 걸음 더 나아가-

비교적 작은 배열을 하나 만들어 캐싱을 해도 됩니다.


#define MAXIMUM 256
static struct {
unsigned char count[MAXIMUM];
} s_info;

unsigned char count_bit(unsigned char number)
{
unsigned char count = 0;

while (number) {
count += number & (unsigned char) 1;
number = number >> 1;
}

return count;
}

void cache_bit(void)
{
int i = 0;

for (; i < MAXIMUM; i++) {
s_info.count[i] = count_bit(i);
}
}


최초 실행 직후 caching을 위한 배열을 구성합니다.

그 이후로는 캐싱된 배열에 접근하여 O(1)로 비트 개수를 얻습니다.

캐시를 한꺼번에 하지 않고 필요할 때마다 하나씩 할 수도 있을 것입니다.

어느 쪽이든 자기 상황에 맞게 구성하면 됩니다.



4. 이진 검색


이진검색은 O(logn)으로 데이타를 검색할 수 있습니다.

n개의 데이타 중에 검색하고자 하는 데이타를 순차적으로 찾으려면,

평균 n/2번 검색을 수행하고 나서야 데이타를 얻을 수 있습니다.


하지만, 순차탐색 대신 데이타가 속한 영역을 반씩 줄여가며 검색하고자 합니다.

이를 위해서는 먼저  데이타가 정렬되어 있어야만 합니다.

데이타가 삽입, 삭제, 갱신되는 시점에 데이타들은 reordering을 합니다.


그리고 검색하게 되면,

이진검색은 정렬된 n개의 데이타 중에 n/2번째에 위치한 데이타를 꺼내와서 찾고자 하는 데이타 value와 크기를 비교합니다.

if (value < (n/2)), value는 0과 n/2 사이에 있을테고,

else 라면, value은 n/2와 n 사이에 있겠죠.



위의 그림은 나름 worst case를 준비한 것입니다.

9개의 데이타 중 3번을 검색하여 1을 찾아내는 과정을 보여줍니다.

순차탐색에서는 한 번에 1을 찾아냈을 것입니다.

하지만, 이러한 극단적인 일부 케이스에서는 순차탐색이 더 좋을지는 몰라도 n의 갯수가 늘어날수록 이진검색의 위력이 세집니다.


int binary_search(int array[], int size, int value)
{
int first = 0;
int last = size - 1;
int mid = 0;
int i = 0;

if (!array) return -1;
if (size < 0) return -1;

while (first != last) {
mid = (first + last) / 2;
if (array[mid] > value) {
last = mid - 1;
} else if (array[mid] < value) {
first = mid + 1;
} else {
return mid;
}
}

if (array[first] == value) return first;

return -1;
}

이 함수에서는 검색한 값이 없을 경우 -1을 리턴하게 하였습니다.



5. 문자열에서 '연속적으로 문자가 반복되는 길이 run-length'가 가장 긴 부분문자열 찾기


첫번째 문자부터 마지막 문자까지 한 번만 훑는 평이한 알고리즘을 짜보았습니다.

이전 문자와 비교하여 같으면 count를 하나씩 올리도록 하였습니다.

O(n)보다 나은 알고리즘이 있을까요?


unsigned int count_longest_run_length(const char *string)
{
unsigned int count = 1;
unsigned int max = 0;
char cur = 0;
char pre = 0;

if (!string) return 0;
if (!*string) return 0;

while (cur = *string) {
if (cur == pre) {
count++;
if (max < count) max = count;
} else {
count = 1;
}
pre = cur;
string++;
}

return max;
}


6. atoi


ascii to integer. 아스키 문자열을 integer로 변환해주는 함수입니다.

문자열을 앞 부분부터 한 글자씩 읽어서 아스키 숫자값이 아니면 리턴합니다.

아스키 숫자인 경우에만 자릿수를 고려하여 더해줍니다.


int _atoi(const char *a)
{
int i = 0;
char tmp = 0;

if (!a) return 0;
if (!*a) return 0;

while (tmp = *a) {
tmp -= '0';
if (tmp < 0 || tmp > 9) return 0;
i = i * 10 + tmp;
a++;
}

return i;
}



7. itoa (스택이나 strrev를 써야 하기 때문에 좋은 문제임)


integer to ascii. 정수형 integer를 radix 진수 문자열로 변환하는 간단한 함수를 만들어 보았습니다.

itoa는 (integer % 10) 나누어 최하위 자리부터 문자로 변환합니다.

따라서 최하위 -> 최상위로 변환작업을 마친 후 스택이나 strrev로 문자열을 뒤집어줘야 합니다.

아래 코드에서 strrev는 위의 1번에서 만들어둔 strrev를 그대로 사용하였습니다.


char *itoa(int integer, char *buf, int buf_size, int radix)
{
int i = 0;

if (!buf) return NULL;
if (!buf_size) return NULL;
if (radix <= 0) return NULL;

for (; integer; i++, buf_size--) {
if (!buf_size) return NULL;
buf[i] = integer % radix + '0';
integer /= radix;
}

if (strrev(buf) < 0) {
return NULL;
}

return buf;
}



끝_


+ Recent posts