공휴일을 제외한 평일 오전 9시부터 오후 6시까지 스케줄이 잡혀있다 보니 자연스럽게 잠도 줄고 부지런해진 것 같다.
원래도 잠이 많은 편은 아니었지만 스스로 준비를 하다 보니 동틀 때쯤 자서 8시간 정도 뒤에 일어나곤 했는데 강의 때문에 6~7시간 자고 일찍 일어나는 게 습관이 들었다.
또한 싸피를 진행하면서 만족스러울 만큼 많이 배웠다고 생각한다.
싸피의 1학기는 2주 정도의 몸풀기 느낌인 스타트 캠프를 시작으로 알고리즘, 서버, 웹, 프레임워크를 배운다.
솔직히 처음 싸피에 참여하는 내 태도는 "프레임 워크만 배우면 되겠다."였다.
이미 대부분의 기업 코테는 합격선이었으며 팀플이라 소규모 프로젝트였지만 팀장과 팀원의 입장에서 PHP를 이용한 DB 연동 수준의 웹 프로젝트를 여러 번 했었기에 프레임 워크에 대한 경험만 부족할 뿐이지 어느 정도 준비된 취준생이란 착각을 했었다.
심지어 파이썬의 자동화 도구를 이용한 웹 크롤링과 보안성도 떨어지는 md5 암호화 알고리즘을 접목한 경험이 우물 안 개구리처럼 자만심을 부추긴 것 같다.
현실은 간단한 웹에 쉬운 것만 찾아서 간단한 모듈 몇 가지를 사용한 것뿐이었는데 말이다.
물론 알고리즘과 웹 기본을 나갈 땐 비교적 여유롭긴 했다.
이미 알고 있었기 때문에 딱히 집중하진 않았지만 백엔드와 프레임 워크를 배울 땐 맘 편히 쉴 수 있는 날이 거의 없었던 것 같다.
1학기는 하나의 프로젝트에 점차 배운 것들로 살을 붙여 나가는 방식이며 2명의 팀을 이룬다.
그렇기 때문에 중간중간 내 것으로 만들지 못하고 지나가면 뒷부분들에 영향을 받게 되고 더군다나 두 명이서 진행하기 때문에 팀원에게 피해를 끼치기 싫어서 더더욱 열심히 하게 됐다.
보통의 학사 팀플은 4~5명이 진행하느라 부분적으로만 경험 가능하고 흔히 말하는 프리 라이더(Free Rider)처럼 책임감 떨어지게 행동하는 경우도 은근히 많지만, 2명이 진행하기 때문에 전체적으로 경험 가능하고 서로 책임감 있게 행동하여 원활한 협업이 이루어진다는 게 큰 장점 같다.
많이 배웠지만 그중에서도 크게 역량 성장을 이룬 점을 뽑자면 스프링 부트와 Mybatis를 이용하여 REST FUL 한 백엔드 구축, Vue를 이용한 SPA (Single Page Application) 형태의 프론트 엔드 구현, 여러 가지 Api 사용, 유지보수를 고려한 기능 분리(디자인 패턴 적용 등) 이렇게 뽑을 수 있을 것 같다.
처음 학습하고 사용하느라 많이 헤매고 어려워했던 부분도 있었지만 고생한 만큼 다양한 것을 배우고 면접에서도 풍부한 내용으로 어필할 수 있겠다는 근거 있는 자신감이 생기기도 했다.
특히 정해진 틀 안에서 단순 반복적으로 코드만 양산하는 코더(Coder)가 아닌 개발자(Developer)가 되기 위해서 스스로 어떻게 하면 효율적으로 코드를 관리할 수 있을까 고민을 많이 했던 것 같다.
물론 처음부터 그렇게 생각하진 않았지만 유튜브 라이브 강의를 들으며 교수님께서 이 코드를 왜 이렇게 구분하여 작성했는지 설명을 듣다 보니 필자 또한 막무가내로 작성된 프로젝트 코드를 수정하려 열어봤을 때 엄청 막막했던 경험이 떠올라서 실무를 대비한다는 생각으로 차후 유지보수를 고려해 고민하며 코드를 작성했다.
이렇게 생각하고 고민하는 개발자가 되겠다는 초기 마음 가짐을 잘 실행한 것 같아 뿌듯하기도 하다.
이제 절반이 지났고 2학기는 7주에 하나씩 총 3개의 프로젝트를 진행한다고 한다.
개인적으로 취업 준비로는 프로젝트만 한 것이 없다고 생각하기 때문에 기대 반 설렘 반이다.
물론 2학기가 끝나기 전에 취업에 성공한다면 더할 나위 없이 기쁘겠지만 안되더라도 분명 싸피를 수료할 즈음엔 어디라도 갈 수 있는 충분한 역량을 쌓을 수 있을 것이라 자신한다.
1학기 프로젝트를 마무리하면 1주일의 방학과 함께 한 달 정도 잡페어 등을 하며 여유로운 기간이 있다는데 남은 2학기를 달리기 위해 충분한 휴식을 취할 생각이다.
프로젝트 마무리를 하고 종강식을 진행했는데 기대치 않았던 프로젝트 최우수상을 받게 되었다.
사실 디자인도 이쁘지 않고 입과 목표로 삼았던 면접에서 충분히 어필할 수 있도록 강점을 갖기 위해 주로 고민을 많이 했었는데 그게 다른 팀들에게 아이디어를 주고 점수를 후하게 받은 게 아닌가... 싶다.
프로젝트 상은 다른 팀의 평가로만 이루어지는데 리허설 발표 때 상당히 반응이 좋았기 때문이다.
솔직히 반응이 좋았어도 1등 까진 생각지 못했었는데 어안이 벙벙하긴 했다.
아마 명세서를 위주로 구현하려는 다른 팀과 다르게 우리 팀이 자랑할 수 있을만한 아이템을 강점으로 삼아 발표를 한 게 큰 것 같다.
국비지원 때 파이썬으로 웹 크롤링을 접목하고 이를 실무자분께 호평받은 경험을 살려 이번에도 보안 취약점을 대비한 암호화 알고리즘, 뉴스 웹 크롤링, UX를 고려한 다음과 카카오 API 사용, 이메일 발송을 구현했고 강점으로 삼았기 때문이다.
덕분에 이 글을 쓰면서도 13팀 중 1등을 해서 상을 받았단 사실에 상당히 기분이 좋다.
개발자가 되기 위해 고민하는 사람이 있다면 일단 지원부터 해보란 말을 하고 싶다.
싸피를 통해제대로 된 프로젝트 경험을 쌓으며 면접에서 충분히 자기 어필을 할 수 있기 때문이다.
또한 협업 하는 경험과 교수님들께 다양하게 배우는 내용이 피가 되고 살이 되어 분명 테스트나 면접에서 자신감의 원동력이 될 것이다.
비전공자는 파이썬반, 전공자는 자바반이며 전공자 중에 따라가기 벅찬 느낌을 받는 사람은 비전공자반으로 갈 수도 있다.
왼쪽 위칸인 [0,0]에서 출발 후 오른쪽 아래칸인 [N-1, N-1]에 도착하는 경로를 생각하는 그래프 탐색 문제였다.
다만 흔히 Queue나 Stack을 이용하여 BFS, DFS로 탐색하는 방법이 아닌 Priority Queue를 사용한 다익스트라 문제였다.
이 문제에서 중요한 점은 거리의 최소가 아니라 비용, 즉 가중치의 최소가 중요하기 때문이다.
상당히 돌아가는 경로라 하더라도 비용이 최소면 해당 경로를 택하기 때문에 가중치의 합을 기준으로 최소 비용 경로를 고려해야 한다.
Priority Queue를 이용한 원리는 다음과 같다.
먼저 시작 노드에서 이동 가능한 노드를 가중치의 합과 함께 Priority Queue에 넣는다.
가중치의 합이 가장 작은 노드를 선택한 뒤 해당 노드에서 이동 가능한 노드를 가중치의 합과 함께 Priority Queue에 넣는 행동을 [N-1, N-1]에 도착할 때까지 반복한다.
[N-1, N-1]에 도착하면 해당 가중치를 저장하고 반복을 종료한다.
한 번은 중간에 이동 가능한 노드인지 체크하는 과정에서 이미 방문한 노드가 최소 가중치의 합을 보장하는지 의문을 품는 질문을 본 적이 있었는데 결론부터 말하자면 각 노드에서 가장 먼저 선택되었을 때의 가중치가 최소다.
Priority Queue를 통해 매번 가장 작은 가중치의 합을 선택하기 때문에 두 번째 방문할 때는 같거나 클 수밖에 없기 때문이다.
이제 전체 코드를 통해 설명하도록 하겠다.
import heapq
inf = float('INF')
dir = [[1, 0], [-1, 0], [0, 1], [0, -1]]
res_num = 1
while True:
n = int(input())
if n == 0:
break
else:
graph = []
queue = []
res = [[inf for i in range(n)]for j in range(n)]
for i in range(n):
graph.append(list(map(int, input().split())))
heapq.heappush(queue, (graph[0][0], 0, 0))
res[0][0] = graph[0][0]
while len(queue) > 0:
temp = heapq.heappop(queue)
if temp[1] == n-1 and temp[2] == n-1:
break
for i in range(len(dir)):
dy = temp[1]+dir[i][0]
dx = temp[2]+dir[i][1]
if 0 <= dy < n and 0 <= dx < n and res[dy][dx] > temp[0]+graph[dy][dx]:
res[dy][dx] = temp[0]+graph[dy][dx]
heapq.heappush(queue, (temp[0]+graph[dy][dx], dy, dx))
print("Problem %d: %d" %(res_num,res[n-1][n-1]))
res_num += 1
4번째 줄까지는 Priority Queue를 사용하기 위한 heapq 선언, 방문하지 않은 노드는 무한대 선언, 노드의 방향 선언, 문제 번호 선언이다.
5번째 줄의 while문을 통해 0을 입력받을 때까지 반복적으로 문제를 처리했다.
12번째 줄의 res는 노드의 최솟값을 갱신하는 리스트로 마지막에 res [N-1][N-1]을 출력하면 된다.
15번째 줄은 시작 노드의 가중치와 y좌표, x좌표 순서대로 넣음으로써 자동으로 MinHeap 구조인 heapq에서 최소 가중치를 꺼내도록 하였다.
18번째 줄의 반복문은 Priority Queue가 빌 때까지 계속 원소를 꺼내는 작업을 하는데 도착지점에 도달한다면 탈출하도록 구현하였다.
방향 탐색을 하기 위해 22번째 줄에서 이동 가능한 노드인지 체크한 후 Priority Queue에 넣어주도록 구현하였다.
구현 방법이나 알고리즘 측면에서 어려운 문제는 아니었지만 우선순위 큐를 거의 사용해보지 않았다면 충분히 떠올리기 어려울 수 있다고 생각한다.
필자 또한 다양한 그래프 문제를 경험해봤지만 습관처럼 BFS, DFS를 사용했기에 해당 문제를 보고 바로 Priority Queue를 떠올리진 못했다.
라인 필기 테스트만 3번째라 익숙해질 만도 한데 여전히 자신 있게 "많이 맞췄다!"라고 할 수 없다는 게 많이 아쉽기도 하다.
필기 테스트는 컴퓨터공학 기준으로 한 번쯤은 강의를 들어본 CS(Computer Science) 전반에 걸쳐서 문제가 나온다.
깊게 물어보는 것은 물론 강의에서 언급하지 않거나 "이런 게 있다" 하고 넘어간 부분에서도 나오기 때문에 열의를 가지고 다양하게 자료를 찾아보는 습관이 중요한 것 같다.
예를 들면 이번에 나오진 않았지만 TCP에서 네트워크 상의 효율을 위해 개발된 Nagle Algorithm의 수도 코드를 기반으로 출제될 수 있는 것처럼 직접적으로 강의를 하진 않아도 관심 가지고 찾아봄으로써 다양한 지식을 쌓는 게 중요하다.
범위도 넓은데 그 넓은 범위에서 골고루 나오는 것도 평소 실력을 테스트하겠단 의도 같다.
또한 이론만 아는 게 아니라 코드로 구현할 수 있는 부분(OOP, SQL 등)은 직접 구현해봐야 익숙하게 풀 수 있는 문제들이 꽤 있었다.
체감상 저번 필기 테스트보다는 조금 쉬운 편으로 나온 것 같지만 아마 합격하기엔 부족하지 않을까 생각한다.
그래도 다행인 점은 저번 시험 볼 때는 자바를 잘 모르는 상태라 OOP에 관한 지식을 외우다시피 했기 때문에 좀 더 디테일하게 물어보면 헷갈리거나 모르는 상황이 많았는데 SSAFY를 통해 자바와 OOP개념을 배운 결과 이해를 기반으로 접근할 수 있었다는 게 그만큼 성장한 것 같다.
원래 외우는 걸 별로 안 좋아하고 이해하는 것이 장기적으로 도움된다 생각하기 때문이다.
여담으로 수능 볼 때도 근의 공식조차 외우지 않은 상태에서 들어갔다. (시간도 넉넉했었고 30초면 충분히 유도할 수 있기 때문에)
필기 테스트엔 자신이 없어서 SSAFY 복습도 하고 다른 코테도 보면서 기대 없이 결과를 기다려야겠다.
결과 메일 오는 대로 포스팅을 수정하도록 하겠다.
불합격 후기
오늘 (2022.04.11 월) 필기 테스트 결과 메일이 왔다.
필기 테스트 이후 9일 만에 메일이 왔는데 예상은 했지만 그래도 불합격 메일을 확인하니 좀 씁쓸하기도 했다.
아무래도 결과가 서류와 필기 테스트를 합쳐서 나오다 보니 서류가 부족했는지 CS가 부족했는지 감이 잡히지 않는다.
또한 CS를 준비한다 해도 범위가 너무 방대하고 어느 정도 수준까지 해야 될지 감도 잡히지 않아서 라인은 나한테 상당히 어려운 기업 같다.
여태 프로젝트를 진행하면서도 DB만 사용했었는데 최대한 다양한 Data를 사용하도록 파일도 얻고 Python의 자동화 도구를 이용한 웹 크롤링도 해봤지만, Data를 넣는데 많은 시간이 걸리고 파일을 얻기 위해 찾아다녀야 한다는 단점들 때문에 API를 활용하는 게 좋아 보인다.
다만 SSAFY에서 강의를 듣는데 API 사용을 어려워하기도 했고 API를 활용하면 코드로 필요한 Data를 얻어서 다양하게 활용할 수 있으므로 나중을 위해 정리하는 겸 API에 대해 알아보자.
Web을 기준으로 대표적 비동기 통신 방식인 AJAX를 사용하여 정리하도록 하겠다.
API란?
API란 Application Programming Interface의 약자로 일종의 소프트웨어 인터페이스이며 다른 소프트웨어에 서비스를 제공하는 것이다.
보다 이해하기 쉽게 말하자면 엄청나게 많은 Data를 저장한 DB에서 개발자가 코드를 이용하여 필요한 Data를 불러오는 것을 뜻한다.
물론 아무나 접근할 수는 없게 회원 가입한 유저에게 유일한 서비스 키(Service Key)를 제공하여 인증된 사용자에게만 필요한 Data를 제공한다.
또한 개발자마다 코드 스타일이 다르고 각기 다른 코드에 동일한 결과를 제공하는 것은 불가능하기에 API를 제공하는 곳에서 요청(Request) 방식과 응답(Response) 방식을 구체적으로 명세해놓고 있다.
하지만 필자처럼 API를 처음 접하는 경우엔 해당 문서가 아무리 친절하고 세세하게 설명해놓았다 하더라도 코드를 복붙 하는 수준이 아니라면 어떻게 구현해야 하는지 감이 잡히지 않을 수 있다.
실제로 카카오 지도 API는 주석과 샘플 코드, 실제 작동방식 등을 Javascript, Javascript+HTML까지 구분하면서 아주 쉽게 이용할 수 있도록 해놨지만 같은 카카오의 개발 가이드에서 주소 검색하기 API는 Request에 대한 정보와 설명을 해놨기에 필요한 부분을 생각해서 조합하는 것은 예상외로 막힐 수 있기 때문이다.