스웨덴 사람이 성공한 직장인에서 승려로, 승려에서 다시 속세로 돌아와 명상 전문가로의 살아가면서 느꼈던 점들을 허심탄회하게 풀어놓은 책이다. 많은 사람들이 경험하는 심리적인 고뇌와 불안에 대해 자신의 경험을 솔직하게 풀어놓으면서 다양한 조언들을 제공한다.
요새 나도 회사에서 "왜 이렇게 일하지?" 혹은 "이랬어야 하지 않을까?"등등의 생각들로 스스로를 괴롭히던 모습을 다시 돌아보게 되었고, 이겨낼 수 있는 방법들을 찾은 것 같아서 좋았다. 예를 들어, 다른 사람과의 마찰이 있을 때 마음속으로 세번만 외친다면 더 겸손하게 건설적인 방향으로 나아갈 수 있는 마법의 주문을 알려준다. "내가 틀릴 수도 있습니다.". 나도 자연스럽게 내 머릿속에 떠오르는 생각들에 매몰되지 않았는지, 내가 옳다고 생각하는 것들을 편견과 선입견을 가지고 바라보지 않았는지, 현실을 너무 통제하려고 하지 않았는지 되돌아보게 되었다.
과거에 대한 미련과 미래에 대한 불안을 내려놓고 현재에 몰입할 수 있는, 심리적인 고뇌에서 현명하게 헤어나올 수 있는 내 자신이 되길 기도한다.
Command(변경) Query(조회) / Responsibility(역할) Segregation(분리)로 나눠서 보면 이해가 쉽다.
"변경역할을 수행하는 구성요소와 조회역할을 수행하는 구성요소를 분리하는 패턴"이라고 한다.
어떤 경우에 어떻게 사용하고, 어떤 효과가 있는지 알아보자.
왜 사용하는가?
일반적인 웹서비스의 기능은 CRUD(Create, Read, Update, Delete)이며, 도메인을 정의해놓고 변경, 조회 작업을 모두 수행한다. 간단한 기능에는 적합하지만, 서비스가 복잡해질수록 다양한 요구가 생기며, 변경 역할과 조회 역할은 다른 성격을 띄게 되어 분리의 필요성이 커진다.
ex) 홈페이지에 카테고리별 인기글을 노출시키고 싶다면?
-> 카테고리, 게시글이라는 도메인이 존재한다고 하면, 카테고리로 묶은 뒤 조회수로 정렬하여 가져와야 할 것이다. 이런 작업들이 여러 도메인에 걸쳐 전시 조회를 위해 존재한다!
즉, UX나 비즈니스 요구사항이 복잡해져 데이터를 관리하는 역할과 데이터를 조회하여 보여주는 역할이 구분되어야 할 때 CQRS 아키텍쳐를 고려해보면 좋을 것 같다. 조회 역할만 분리 시 조회 성능을 높일 수 있다.
어떻게 적용할까?
그렇다면 기존의 시스템에서 조회와 변경이라는 역할을 어떻게 분리해낼 수 있을까?
생각할 부분이 여러가지가 있지만, 우선 프로세스와 DB 관점에서 카테고리별 인기글이라는 기능에 대하여 조회와 변경 역할을 분리한다고 생각해보자.
프로세스와 DB
1. 같은 프로세스, 같은 DB
변경과 조회의 역할을 코드 수준에서만 분리하는 방법이다. 가장 간단하며, 구현하기 쉬우나 코드 상의 분리만 일어날 뿐 실제 변화는 거의 없다.
2. 같은 프로세스, 같은 DB(다른 테이블)
변경과 조회의 역할을 코드 수준에서 분리하고, 데이터 수준에서는 같은 DB 내의 테이블만 변경하는 방법이다. 명령 역할에서 데이터 변경 시 해당 변경을 [카테고리별 인기글] 테이블에도 반영해주며, 조회 역할은 카테고리별 인기글 테이블만 조회한다.
3. 같은 프로세스, 다른 DB : 레디스 사용
조회 역할을 위한 [카테고리별 인기글]을 별도 DB로 분리한다.(Redis를 사용하면 조회 기능을 향상시킬 수 있다.) 명령 역할에서 게시글이나 카테고리에 변경을 수행했을 때, 해당 변경 내용을 [카테고리별 인기글]을 가지고 있는 DB에 전파해주어야 한다. 변경 전파에 관한 내용은 더 아래에서 살펴보기로 하자.
4. 다른 프로세스, 다른 DB
마이크로서비스와 같이 코드, 데이터 단에서 별도의 서비스로 분리하는 방법이다.
도메인 변경 내용 전파
변경 역할을 하는 프로세스와 조회 역할을 하는 프로세스가 다른 DB를 사용하는 경우, 변경 역할 DB(게시글, 카테고리)의 변경 내용을 조회 역할 DB에 전파해야 한다. 유실되어도 되는 데이터인지, 기대 전송 속도가 얼마나 되는지에 따라 알맞게 사용하면 된다.
1. 직접 전파
2. 변경사항 발생 시 변경 내용을 DB에 저장하고, 전파기가 변경내역을 읽고 전파
3. CDC(Change Data Capture) 활용
데이터 구조
조회 역할을 하는 DB쪽의 도메인 설계는 어떻게 할까?
1. 변경 역할 DB의 도메인과 비슷하게 설계한다.
2. 조회가 들어오는 Query를 거의 그대로 저장한다.
이건 아직 어떻게 할지 모르겠다. 2번으로 해야할 것 같긴 한데 더 찾아봐야지. (좋은 자료 있으면 추천 부탁드립니다..)
정수들이 담긴 배열 nums와 목표 target이 주어질 때, 배열 nums 내의 특정 두 수의 합은 target이 된다.
해당 두 수의 index를 return해라.
2. 풀이
2가지 풀이 방법으로 풀어보자.
1) Two Pointer : 두개의 포인터를 가지고 배열을 탐색하는 기법이다. a. 배열을 오름차순으로 정렬한다. 이 때, 기존 idx를 보존할 수 있도록 [num, idx] 형태로 저장 후 정렬한다. b. 두개의 포인터(left = 0, right = len(nums)-1)를 만들고 합(nums[left][0] + nums[left][1])을 구한다. c. (반복) 합이 target보다 작은 경우 left를 오른쪽으로 한칸, 클 경우에는 right를 왼쪽으로 한칸 이동시킨다. d. 합이 target과 일치하면, 두 수의 idx를 반환한다.
시간 복잡도 : O(nlogn)
공간 복잡도 : O(1)
2) Hash Map : 배열을 순차적으로 탐색하며 확인한 내용을 해시 맵에 기록한다. Two Pointer 보다 속도가 빠르지만, 메모리를 추가적으로 사용한다.
a. nums를 순차적으로 탐색하며 아래의 과정을 수행한다. 탐색 과정의 정수 : num a-1) Hash Map의 key들 중 num이 있는지 확인한다. a-2) 있다면 해당 key의 value와 num의 idx를 return하고, 없다면 Hash Map에key: target - num.value: idx 로 기록한다. 시간 복잡도 : O(n) 공간 복잡도 : O(n)
12월부터 5개월간 정글 교육이 끝나고 7월 초까지 약 2달 반 남짓의 취준 생활을 하며, 총 9개의 회사의 채용전형을 경험했다. 교육이 끝난 후 배운 것들을 잘 정리하고 취업 준비하겠다는 생각이 무색하게, 수료 후 바로 다음주부터 취업 전형이 진행되어 면접 준비하랴 배운 것들을 정리하랴 정신없는 기간이었다.
우선 초반 몇 개의 면접을 보면서 느낀 점은, 공부하는 것과 면접을 보는 것은 너무나도 다르다는 것이다. 배웠던 내용도 중요하지만 면접을 위해 준비해야할 필수적인 것들이 있었고, 이걸 몰랐던 나는 면접을 보며 터득해야 했다. 처음 몇 개의 면접 때 대답하지 못했던 것들을 생각해보면 지금도 부끄럽기만 하다. 혹시나 정글 수료 후 면접을 준비중이라면, 아래 내용을 꼭 읽어보는 것을 추천한다. 스스로 공부가 부족하다고 느꼈던 DB나 네트워크 분야도 면접을 진행하며 조금이나마 채울 수 있었고, 회사에서 내주는 과제들을 수행하며 테스트 코드나 디자인 패턴에 대해서도 공부할 수 있었다.
SW사관학교 정글이라는 과정은 정말 만족스러웠지만, 목표는 취업인 만큼 결과도 무척이나 중요했다. 이전에 다니던 회사는 산학장학생으로 합격한 터라 취준이 생소한 나에게 취업 과정의 감정들은 참 낯설었다. 특히 처음 6개의 회사에서 탈락하는 와중에 동기들의 합격소식을 하나 둘씩 들으며, 자신감이 조금씩 떨어짐과 동시에 초조함을 느꼈다. 친구들 중에 1년 넘게 취업준비를 하는 친구가 있었는데, 도대체 어떻게 버텼을까라는 생각이 들었다.
아무튼 이런 과정들을 거쳐 최종적인 결과는..! 사실 지금도 잘 믿기지가 않는다. 스타트업 1곳과 '네카라쿠배' 중 2곳에 최종 합격했다. 이상하게도 3개 회사 모두 떨어질 것이라고 생각했는데 붙어서 신기했다. 모든 과정이 끝나고 원하는 목표를 이루고 나니 꿈만 같았고, 지금 생각은 부족한 나를 받아준 회사에서 열심히 일해야겠다는 생각뿐이다 :)
결론
0. 이력서 작성은 피드백을 꼭 받아보고, 코딩테스트는 꾸준히 준비해야 한다.
1. 면접 관련 질문은 한번은 꼭 읽어봐야 한다. (교육과정 정리 + 면접질문 공부 + 프로젝트 정리 필요!)
고려해야 할 사항 : 추가/삭제 같이 검색 이외의 작업에 들어가는 비용, 주어진 자료구조, 데이터의 형태 등을 종합적으로 평가하여 최적의 검색 알고리즘을 선택해야 한다. 배열이 주어지고 그 안에서 특정한 Key값을 찾는다고 할 때, 아래와 같은 방법들을 고려할 수 있다.
선형 검색(Linear Search)
무작위로 주어진 데이터에 대하여 순차적으로 검색하는 방법. 검색 시간이 데이터의 크기에 선형적으로 비례한다.
방법 : 맨 앞, 혹은 맨 뒤부터 순차적으로 Key 값을 찾는다.
종료 조건 : 1. Key와 일치하는 원소를 찾은 경우
2. 배열의 길이를 넘어선 경우
시간복잡도 : O(n)
* 보초법 : 배열의 맨 끝에 찾는 원소를 추가하여 매번 배열의 끝인지 확인할 필요를 줄이는 방법.
이진 검색(Binary Search)
정렬된 데이터에 대하여 효율적으로 검색할 수 있는 알고리즘. 한번 비교를 수행할 때마다 비교 대상의 데이터 수가 반으로 줄어든다.
방법 : 맨 왼쪽 끝 원소의 Index를 Left, 맨 오른쪽 끝 원소의 index를 Right라고 한 뒤, Center의 값과 Key값을 비교한다. 대소 여부에 다라 Left, Right 값을 변경한다.
종료 조건 : 1. a[Center]가 key와 일치하는 경우
2. 검색 범위가 더이상 없는 경우
시간복잡도 : O(logn)
해시(Hashing)
데이터를 저장할 위치를 해시 함수를 사용하여 결정하는 방법. 키값을 해시 함수를 통과시켜 해시값을 얻어낸 뒤, 해시값에 해당하는 인덱스에 키를 저장한다. 키를 해시값으로 변환하는 함수를 해시 함수, 해시 테이블에서 만들어진 원소를 버킷이라고 한다.
해시 함수의 예시 : 13으로 나눈 나머지
위와 같은 해시 함수에 대하여 같은 해시 값을 가진 키가 존재하는 경우 충돌이 일어날 수 있다. 예를 들어, 14도 13으로 나눈 나머지가 1이고, 27도 13으로 나눈 나머지가 1이기 때문에 해시 값이 같은 Key가 존재하게 된다. 이를 해시 충돌이라고 하고, 다음과 같은 두가지 방법으로 처리한다.
1) 체인법 : 해시값이 같은 원소를 연결 리스트로 관리한다.
2) 오픈 주소법 : 버킷이 가득 찬 경우를 대비하여, rehash 함수를 정의한다. 이후 가득찬 버킷에 추가할 일이 생기면, 빈 버킷을 찾을 때까지 rehash를 반복한다.
정말 믿기지 않지만, 마지막 프로젝트가 끝나고 이력서를 제출하는 것으로 137일간의(12월 7일 ~ 4월 22일) SW사관학교 정글 일정이 끝났다. 퇴사하느라 정신없이 입소했을 당시에는 정말 추운 겨울이었는데, 어느새 여름이 느껴진다. 기분이 복잡미묘하다. 취업에 대한 걱정과 사람들과 헤어지는 것에 대한 아쉬움. '드디어 해냈다'라거나 '정말 잘 끝냈다' 같은 기쁜 감정은 거의 없다는게 이상하다.
4달 반정도의 기간을 뒤돌아보면, 처음엔 정말 당황스러움의 연속이었지만 성공적으로 모든 게 끝났다는 것이 놀랍기만 하다. 나름 python을 공부한다고 회사 끝나고 공부하던 시절을 되돌아보면, 어떻게 공부해야 하는지, 어떤 것들을 공부해야 하는지 전혀 가늠이 잡히지 않던 시절이었다. 실제 들어왔을 때 Computer Science는 어떤 과목들을 배우는지 알 수 있었고, 모든 걸 다루진 못했지만 핵심 과제들을 꽤나 깊게 훑어볼 수 있었다.
이별에 대한 아쉬움만 제외하면 사람, 타이밍, 교육 모든 것이 완벽했던 시간이었다. 커리어 전환을 꿈꾸던 나에게 완벽한 기회였고, 다양한 분야의 사람들과 함께할 수 있는 기회였으며, 운영진 뿐만 아니라 서로에게 정말 많은 것을 배운 기회였다. 이 글을 빌어 운영진분들께 다시 한번 감사하다고 말씀드리고 싶다.
중요한 건 이제부터인것 같다. 사실 5개월이란 시간은 지금 생각해보면 사람이 바뀌기엔 너무나도 짧은 시간(할 땐 엄청 긴 것 같이 느껴졌지만)이다. 들어올 때는 5개월동안 열심히 해서 컴퓨터 전공한 사람과 비슷한 정도의 지식을 얻는 것이 목표였지만, 내가 얻은 가장 큰 것은 방향성과 습관, 할 수 있다는 자신감, 나와 함께 앞으로 나아갈 친구들인 것 같다. 공부의 방향성을 잡을 수 있게 되었고, 하루 온종일 시간을 쏟아 문제를 해결해나가며 할 수 있다는 자신감을 얻었고, 모르면 서로 물어보며 같이 성장할 친구들이 생겼다. 아직 많이 부족하지만, 할 수 있을 것 같다는 느낌(장병규 의장님은 효능감이라고 표현하셨다)을 가지고 계획을 잘 세우고 앞으로 나아가야겠다.