경력 개발자의 이직 회고록(시리즈)

======================================================================

======================================================================

======================================================================

목차

  • 개요(들어가기 앞서...)
  • 회사 생활(회고 - 1)
  • 다시 이직(회고 - 2)
  • 회고(회고 - 3)
  • 앞으로

개요(들어가기 앞서...)

하필 글 쓸 때 25년도 1월 1일이다. 의도하지는 않았지만 의도한 걸로 합시다;(뭐, 마무리는 1월 말에 했지만 ㅋㅋ)

이 시리즈를 작성할 때 굉장히 들뜬 마음에, 뿌듯한 마음에 작성했던 기억이 있다. 좋은 회사에 들어가서 내가 생각했던, 목표했던 개발자로 한 걸음 갔다는 생각이기 때문이다. 이 기분과 기운(정보)을 블로그로 공유하고 싶었다. 시리즈 9편 작성 후 어언 4년 가까이 흘렀다. 6개월 후 회사 생활에 대한 경험 및 생각을 작성하고 싶었다. 하지만 일과 사람에 치이다 보니 2년 반이 지났고, 다시 이직하고 1년이 지났다.

트라우마가 있었다. 자신감도 많이 잃었고, 주눅 들었다. 일상에는 크게 지장은 가지 않았지만 어색한 내 자신을 계속 보는 것이 너무 힘들었다. 괜찮다고 매번 내 자신에게 되새기지만, 나를 조이며 나는 내 자신을 계속 괴롭히고 있었다. 

 

회사 생활 (회고 - 1)

회사생활은 전반적으로 만족하지 못했다. 항상 불안감과 무력감이 동반했다. 무력감은 결국 내 자신을 무기력하게 하였다. 이 무기력은 정말 오래갔다. 최근 괜찮아졌지만, 아직 트라우마가 있다. 이 트라우마가 긍정적인 영향도 있지만, 결국 건강하지 못한 트라우마이다. 그때 나는 출근 중에 이등병 때 했던 생각을 똑같이 했다. 그냥 자빠져서 병원에 입원하고 싶네? 이런 생각 말이다. 그래도 버티면 나아질 수 있다고 생각했다. 버티다 보면 나도 발전하고, 주변에서도 인정을 해주기 때문이다. 과거 군대도 같았기 때문에 이런 생각을 했다. 일병 말호봉까지 개같이 일 하니, 결국은 인정받고 잘 적응했다. 버티면 나아지지 않을까 생각했다. 2년이 지나도 나아진 것은 없고, 목표도 잃어버린 무력한 내 자신 밖에 남지 않았다. 

 

크게 세 가지를 생각해본다. 

  • 기본기의 부재
    • 제일 큰 요인인 것 같다 ㅎㅎ 모든 문제의 시작이기 때문이다. 기술에 대한 기본기를 말하는 것이 아니다. 사람으로서의 기본기를 얘기하는 것이다. 의사소통 능력, 문제에 대한 정의 능력, 절충안/최적안을 판단하는 통찰 능력, 구조적인 사고, 전체 흐름 파악, 기민함, 임기응변 등 다양하다. 그냥 쉽게 얘기해서 일 센스가 많이 부족한 것이다. 이쯤 되면 내가 뭔 병신인가? 생각이 든다 ㅋㅋㅋ..
  • 나약한 마음가짐
    • 부드럽고 여유가 있는 사람을 보면 항상 부럽다. 행동이 아니라 마음을 얘기하는 것이다. 마음에 여유가 있는 사람은 외부와의 갈등이 있어도 갈대처럼 대응을 잘할 수 있다. 외부와의 갈등이 있을 때 자신은 꺾이지 않는다. 쓰러져도 다시 일어난다. 자기 회복능력이 정말 탁월하다. 필자는 외부와 갈등이 생겨 쓰러지면 잘 일어나지 못한다. 이미 이런 무력감에 학습되어 있어 그런 것 같다. 이 부분은 유년 시절, 학창 시절 영향도 있는 것 같다. 분명 성인이 돼서 잘 이겨내고, 강해진 줄 알았지만 전혀 아니었다 ㅎㅎ 정리하면 문제가 생겼을 때 회복탄력성이 좋지 못했다.
    • 갈등이 생겼을 때 외부에 도움을 제대로 청하지 않았다. 어차피 도움을 청해봤자, 얘기해 봤자 해결되는 것도 없고, 되려 이슈 인력으로 낙인이 되기 때문이다. 당사자와 얘기해도 해결되지 않는 문제를 제3자한테 얘기해서 해결이 될까? 이런 생각을 했기 때문이다.
    • 지속적인 갈등으로 인해 자존감(심) 다 하락했다. 내 성격이 원래 이랬나? 생각할 정도로 남 눈치를 보고, 내 자신을 계속 자책하는 모습이 있었다. 필자는 남에게 피해를 주기도/받기도 하기 싫어하는 사람인데, 계속 피해를 주는 사람이 됐기 때문이다. 
  • 환경의 문제
    • 도움 받을 수 있는 환경이 전혀 아니었다. 조직장은 파트장한테 업무와 인력 관리를 위임하였다. 파트장과 갈등은 계속됐기 때문에 필자는 고립의 연속이었다. 솔직히 할 말이 너-무 많다. 지금까지 업무를 진행하면서 억울한 것도, 불합리한 것도 정말 많았지만 결국 갈등을 해소하지 못했다. 애초에 이런 구조를 만든 조직장이나, 파트원이 제대로 일할 수 있는 환경을 제공하지 못한 파트장이나, 갈등을 해소하기 위해 주변에 적극적으로 도움을 구하지 못 한 본인이나 똑같다. 
    • 필자는 환경에 정말 취약한 동물이다. 아니 짐승이다. 환경을 조성하지 않으면 하지 않거나, 그 환경에 지배받는 / 영향을 제대로 받는 특징이 있다. 이를 장점으로 여태껏 활용했다. 공부를 해야 하기 때문에 집을 가지 않고 학교 도서관에 억지로 있거나, 일단 영어 공부를 해야 하니, 학원부터 등록하거나, 일단 환경에 나를 던져서 적응해 가는 식이다. 그리고 환경에 영향을 많이 받기 때문에 그 환경에서 벌어지는 모든 일을 학습하고, 모방을 한다. 지금까지의 생존방식이고 어떻게든 생존을 했다. 장점으로 잘 활용했던 것은 내가 환경을 바꾸거나, 내 자신을 던질 수 있었지만, 회사 환경은 그렇지 않았다.
  • 번외로 내 상황은 난국인데 조직의 비전 또한 공감이 되지 않았다.

다시 이직(회고 - 2)

"회고-1"의 이유로 이직한 것도 있지만, 평소에 관심 있던 조직에서 채용이 열린 것도 있다. 

 

만약 이직에 실패했으면 나는 바로 사표 내고 나올 예정이었다. 이미 와이프와 많이 얘기했고, 퇴사하고, 재충전하기로 마음먹었다. IT 이직 시장이 얼어붙었는데도, 그 마음을 먹었다. 

왜 퇴사 결심을 했을까? 심리가 굉장히 불안했다. 우울증 직전까지 간 것 같다(아니 이미 우울증이었을지도..). "저 사람이 나에 대해 안 좋은 생각을 하는 것 같다" 이런 생각과 휴일에 회사 메신저 알림이 오면 항상 놀라거나 집에 오면 유튜브만 쳐보다가 자기 일수였다. 왜 보냐고? 그냥 아무 생각도 하기 싫으니깐. 무력감에 지배됐으니깐. 무력감에 지배되기 때문에 나의 목표는 사라졌다. 아니 잊어버렸다. 그렇게 되니 독서/학습할 이유도 없고, 그냥 시간을 보냈다. 이 무력감은 불안감과 항상 동반됐고, 반강제로 하루 일과가 시작되는 듯한 느낌을 받았다. 심리 상담을 받아도 해결되는 것은 없었다 ㅎㅎ

 

그래도 다행히 이직은 성공했다. 계열 법인 이동은 잘 됐다. 

 

도망친 곳에, 낙원 없다. 필자는 지금도 이 말을 경계하고 있다. 이 꼴이 나지 않으려고 서서히 맨탈을 다시 잡고 있고, 목표도 다시 잘 다듬고 있다. 트라우마는 여전히 남아있어, 제 자신을 다듬기 위해 꽤 많은 시간을 사용하였다. 지금은 많이 좋아졌다. 

회고(회고 - 3)

많이 다쳤지만, 배운 것도 많다. 진짜 일을 하는 법을 배웠다. 왜와 이유를 항상 생각하고, 정말 이 방법이 좋을지? 최적의 판단을 하기 위해 노력하고 있다. 필자의 부족한 점을 인지하고 있기 때문에 이를 기반으로 어떤 목표를 잡아야 할지 갈피도 잡았다. 

아직 많이 부족하다. 지금도 일 하면서 이런 생각을 했겠지?(현재 팀의 일을 잘하는 사람이 있는데, 이 사람이라면 이렇게 생각할 수 있겠네? 혹은 이전 회사에 이 사람이라면 이렇게 업무 했을 때 왜 이렇게 했냐고 한 마디 했겠지?) 생각하며 일을 하고 있다. 

앞으로

앞으로의 목표는 다음과 같다..

다양한 사고가 있는 개발자

  • 다양한 사고가 있고 싶은 이유는 위의 배운 것을 실천하고 싶기 때문이다. 이를 위해서는 경험/기술뿐만 아니라 리더 혹은 기획자 같은 다른 차원/상위자의 시점 필요하다. 당장 생각나는 계획은 조직원 모방과 서적 학습이 있다.
  • 일 잘하는 조직원 모방을 위해서는 조직원의 이슈 코멘트, 행동, 작성 코드 등에 대해 탐구가 필요하다. 어떻게 탐구를 하면 좋을까? 탐구 방법 리스트업 후, 상대의 행적을 기록하고 평가하는 것이 좋을 것 같다. 그전에 나에 대한 객관화 지표도 만들어야 할 것 같다. 일단 모방하고 싶은 조직원은 1~2명 있다.
  • 서적 학습은 기획자 혹은 팀 리더의 사고를 간접적으로 알 수 있는 서적이 좋을 것 같다. 최근 기획 관련 서적을 완독 했는데, 기획의 주된 관점은 문제 정의를 75% 비중을 두고 진짜 문제를 찾기 위해 엄청난 노력을 한다는 것이다. 이와 같이 나의 사고력을 발전할 수 있는 서적을 찾는 것이 중요한 것 같다.
  • 마지막으로 나의 사고를 정리할 수 있는 능력이 필요하다. 내 사고를 구조화하여 적시에 효과적인 표현 및 효율적인 전달이 필요하다. 내 사고력을 어떻게 구조화할 수 있을지? 이는 아직 고민 중이다. 논증에 대한 서적도 보고, 구조적인 사고법을 어떻게 하는지 확인해보고 있다. 논증 서적은 보다 때려치웠는데... 계획을 다시 잡고 어떻게 구조적인 사고를 할지, 논증은 어떻게 업무에 녹일지 고민해 봐야겠다.

상대를 존중할 수 있는 사람

  • 나는 그 사람이 왜 열을 내며 일을 했는지 알고 있다. 그래도 그렇게 주변에 함부로 했으면 안 됐다. 사회는 뿌리는 대로 거두며, 인과 과는 돌고 돈다. 필자는 절대 그렇게 일을 하지 않을 것이다. 그렇게 하지 않아도 일은 진행되기 때문이다. 어떻게든 진행되는 것이 아닌 "좋게 / 잘" 진행될 수 있기 때문이다. 

기회를 줄 수 있는 사람

  • 스스로 의사소통, 의사결정할 수 있도록 기회를 줄 것이다. 모두에게 처음은 있고, 처음은 모두 서툴다. 당연한 것이다. 직접 경험해야지 다음에는 더 좋은 소통과 결정을 할 수 있다. 

갈등 회피

  • 필자는 갈등이 생길 때 절대 회피하는 성향이 아니다. 근데 회사는 달랐다. 다음에 이런 상황이 생기면 어떻게든 발악하고, 부딪칠 것이다. 이런 식으로 물러나는 것은 이번이 마지막이다. 

 

Posted by 동팡

5월에 끝까지 본 기술 서적이 1권이라니... 이것저것 보다가 겨우 하나 다 봤다.. 

독자 정보

  • 5~10년 차 개발자

독서 일자

  • 2022. 05

내용

  • 실제 TDD를 어떻게 하는지 예제와 함께 설명
  • TDD에 대한 기술적인 설명보다 TDD 개념, 더 좋은 TDD 방법 등을 설명 

별점

  • 4.8 이상: 철학이 존재함, 추천++

대상 독자

  • 개발자

선행 도서

  • -

관련 도서(미디어)

  • [서적] 단위 테스트(생산성과 품질을 위한 단위 테스트 원칙과 패턴)
  • [인강] 이규원의 현실 세상의 TDD : 안정감을 주는 코드 설계 방법

느낀 점

 해당 방법론은 1990년 후반 켄트 백의 익스트림 프로그래밍의 일부이다(근데 왜 난 20년이 지나 공부하는가 ㅡㅡ ㅋㅋㅋㅋㅋ). 우리의 프로젝트에 TDD 방법론 적용은 오버 엔지니어링이라고 생각할 수 있지만, 단위 테스트 코드의 작성을 습관화하는 게 좋지 않을까 생각한다. 

 

해당 서적에서도 TDD 인강에서도 TDD는 불안, 두려움을 지루함으로 바꾸는 방법론이라고 다들 얘기한다. 필자 또한 전적으로 동의한다. 서비스 운영 및 배포를 하면 장애가 항상 수반하는데, 배포했을 때 "과연 장애가 없을까..?", "제대로 배포가 됐을까?"와 같은 불안을 최소화 시켜준다. 이와 같은 작업을 반복하면서 안전한 서비스를 만드는 것이다. TDD가 100% 모든 테스트를 대신하는 것이 아니며, 100% 안전한 서비스를 제공하는 수단이 아니지만 많은 비중을 차지하는 것은 서적과 필자의 경험으로 얘기할 수 있다. TDD에 회의감을 가지는 많은 개발자가 있지만 적당선의 타협을 하면 개발 리소스 감축할 수 있는 효과를 볼 수 있다. 

시간에 따른 변경 비용

간략하게 요약하면 기능 변경에 따른 회귀 테스트를 통해 회귀 버그를 최소화할 수 있다. 회귀 버그로 인해 개발 리소스 비용 증가는 모두가 아는 사실이다(저 보라색 비용을 다들 싫어하더라.. 그래프에는 보라색이 작게 표시 되었지만 실제는 더 크다.) 서스테이닝이 없는 단발성 프로젝트는 엄격한 테스트는 굳이 필요 없지만, 서스테이닝 요하는 서비스는 필수라고 생각한다. 현재 프로젝트는 통합 테스트, 기능 테스트만 제대로 적용됐다. 이 두 개의 테스트로도 효과는 많이 보고 있지만 단위 테스트를 "제대로" 적용하면 더할나위 없다고 본다. 몇 개 로직에 단위 테스트를 적용하여 효과를 봤기 때문에 확언할 수 있다. 

 

해당 서적에서 다독 부분은 다음과 같다.

  • 저자의 글
  • 25장 테스트 격리성 설명
  • 27장 테스트 패턴
  • 32장 TDD 마스터(+)

 

Posted by 동팡

독자 정보

  • 5 ~ 10년 차 개발자

 

독서 일자

  • 2022. 06

 

내용

  • 평범한 신입 개발자들의 좌충우돌 성장기 
  • 아직도 성장하는 개발자의 회고록

 

별점

  • 4.5/5.0(많이 배울 수 있음, 추천++)
  • 객관적으로는 3.8이지만 나사 몇개 빠진 필자의 주관에서는 4.5

 

대상 독자

  • 주니어 개발자
  • 미드레벨, 시니어 개발자(개구리, 당신들도 예외는 없습니다.)

 

선행 도서

  • -

 

관련 도서

  • 오늘부터 개발자
  • 오늘도, 우리는 코딩을 합니다

 

느낀 점

보통의 개발자, 자신들의 이야기이다. 그들의 열정과 간절함을 느낄 수 있었다. 비전공자이지만 자신의 특장점을 잘 살려서 해외에서 개발자가 된 친구, 전략적으로 산업체에서 개발자로 일한 친구, 관련 학과지만 많은 고민 끝에 개발자가된 친구 등.. 해당 친구들의 발자취를 간접적으로 볼 수 있어서 영광이었다. 

 

성장하고 싶은 주니어 개발자, 성장하고 있는 주니어 개발자, 성장했던 시니어 개발자, 모두 이 책을 보면 좋겠다. 올챙이는 다른 올챙이를 보고 간접경험을 충분히할 수 있고, 개구리는 자신의 올챙이 시절 치열함과 열정을 다시 불태울 수 있다. 필자는 크고있는 올챙이지만 어린 올챙이 시절의 간절함을 다시 회고할 수 있는 좋은 기회였다.

 

필자는 5년 계획 했던 목표를 이루고 마음에 와 닿지 않는 10년 목표를 위해 1년을 허비했다. 말마따나 목표를 잘못 잡았으니 목표를 위해 1년동안 움직이지도 않았다(솔직히 정신없기는 했지만 핑계 ㅅㄱ링). 이 책을 보면서 필자는 목표를 다시 잡고 세부 계획을 좀 더 정리하고자 한다. 솔직히 고맙다. 몇개 빠진 나사들을 다시 줍는 시간이었다. 

 

 

Posted by 동팡

독자 정보

  • 5~10년 차 개발자

 

독서 일자

  • 2022. 06

 

내용

  • 비전공자 입장에서 개발자가 되기 위해 무엇을 해야하는지 가이드

 

별점

  • 3.8/5.0(가볍게 읽기 좋음, 추천)

 

대상 독자

  • 개발자를 준비하는 비전공자

 

선행 도서

  • 없음

 

관련 도서

  • 나는 주니어 개발자다

 

느낀 점

비전공자가 멘토도 정보도 없는 상태에서 갈피를 잡을 때 읽으면 좋다고 생각한다. 개발자가 되기 위해 수많은 행위들을 추상적으로 잘 설명한다. 추상적? 왜 추상적이라고 표현했을까? 해당 책의 저자는 방향성 까지만 제공하고 있기 때문이다. 최소한의 필요 정보와 방향성만 제공했으면 충분하다. 독자는 책에서 가이드한 정보를 구체화하고 구체화한 것을 토대로 개발자 준비를 하면된다. 막연하게 개발자가 되고 싶다면 해당 서적을 읽어보는 것을 추천한다(개발자의 처절한 현실도 나름 얘기해준다;; ㅋㅋ?).

 

해당 서적은 포트폴리오 강의를 준비하면서 전지적 취준/비전공자 입장을 헤아리기 위해 선택한 수단 중 한개이다(다른 하나는 비전공자 신입, 실무자 인터뷰). 솔직히 많이 도움이 됐다. 비전공자 입장에서는 진짜 아무 갈피가 없고 시야가 정말 좁을 수 밖에 없겠다는 생각을 많이 했다. 비전공자를 폄하하는게 아니라 현실적으로 제한된 정보를 토대로 개발자가 되기 위해 노력을 해야한다는 전제 자체가 쉽지는 않아보였다. 그래도 이러한 서적 하나하나가 독자들한테 많은 힘이 되는 것 같다.

Posted by 동팡

오랜만에 글 쓰니까 어색하네..;;

 

독자 정보

  • 5 ~ 10년 차 개발자

 

독서 일자

  • 2022. 02

 

내용

  • 데이터 모델링의 전반적인 개요/배경 설명
  • 데이터 모델링의 주체/대상/행위 등과 어카운트 개념을 설명 
  • ER 서브타입, 식별/비식별자 기준 설명
  • 확장성 있는 모델링 설명(이 모델링 별로야...)

 

별점

  • 4.0/5.0(개발자 입장에서 몰랐던 모델링 개념과 스킬을 소개, 짜임새와 스토리가 있음, 추천+)

 

대상 독자

  • 주니어 개발자
  • DB 모델링 경험을 최소 한 번 이상 한 개발자

 

선행 도서

  • DB 모델링 관련 서적 또는 관련 경험을 한번씩 해보는 것을 추천

 

관련 도서

  • -

 

느낀 점

개발자 입장에서 간접적으로 모델링을 경험할 수 있었다. "현재 사용하고 있는 제품의 DB 모델링은 충분한가?", "과거에 했던 모델링의 필요 개선점?", "개선 했을 때 어떤 점을 더 고려하면 좋을까"와 같은 고민으로 해당 서적을 읽었다. 추상적으로만 인지하고 있던 다음의 사항을 명시적으로 이해할 수 있는 기회가 있었다.

  • 주체/대상/행위: 사전에 모델링할 때 인터뷰를 하거나 분석하는 행위들을 객관적으로 얘기를 못 했습니다.  필자가 하는 행위는 모델링할 때 업무 시스템의 "주체/대상/행위"를 추출하는 행위였다.
  • ER 서브타입: 보통의 ER 서브타입을 객체 지향의 Sub/Super로 대강 이해했지만 통합, 분리, 혼합이라는 것을 알게 되었다. 이 부분은 더 공부가 필요하다.
  • 어카운트 개념: 마스터 데이터, 행위 데이터를 동일한 성격으로 묶는 행위이다. 모델링에 어카운트가 있으면 모델링의 유연성을 제공할 수 있고 업무에서는 유연한 엔티티로 한층 더 유연하게 문제를 해결할 수 있다. 우리가 데이터 모델링할 때 공통적인 것은 묶고 엔티티 간의 연관관계를 맺는다. 연관관계를 연결할 때 징검다리가 필요할 때가 있다. 이때 어카운트가 징검다리 역할을 해준다.

개발자는 한번쯤 읽어보면 정말 좋은 책이라고 생각한다.

Posted by 동팡

MySQL 정보

  • 버전: 5.7
  • 트랜잭션 격리 수준: Default(repeatable read)

장애 현상

  • A 트랜잭션에서 T1 테이블에 delete 쿼리 진행할 때 B 트랜잭션에서 T1 테이블에 insert 쿼리가 lock wait 발생

원인-1(첫 번째 분석)

  • delete 쿼리의 실행 계획에서 풀 테이블 스캔 발생
  • Where 절이 pk로 구성되어 있어도 옵티마이저는 풀 테이블 스캔이 유리하다고 판단(풀 테이블 스캔은 멀티 블록 스캔이고 인덱스는 싱글 블록 스캔이니 일정 분기점 이상 부터는 인덱스 스캔보다는 풀테이블 스캔이 유리함)
  • MySQL에서 로우에 락이 잡히는 기준은 스캐닝된 인덱스 레코드[1]

위의 분석으로 알 수 있는 사항은 다음과 같다.

  • T1 테이블의 모든 로우는 락이 잡혔으며
  • 락이 잡혀있는 동안 다른 세션(트랜잭션)에서 T1 테이블의 모든 로우는 delete/update 불가능하다.

근데 insert는 왜 안돼??? 격리 수준을 read committed 했을 때는 insert가 잘 된다.

원인-2(두 번째 분석)

  • 현재 MySQL의 격리 수준은 repeatable read이다.
  • delete 쿼리를 진행할 때 Next-Key-Lock이 잡혔으며[2],
  • Repeatable read에서 Next-key-lock으로 인해 positive infinity 레코드 까지 락이 걸렸고,
  • 해당 락으로 인해 insert에 lock wait이 발생한다.
  • 위의 락으로 본의 아니게 팬텀 로우를 방지한다

기타 특이 사항

  • delete할 때 풀 테이블 스캔이 아닌 유니크 스캔을 할 때 insert에 lock wait이 발생하지 않는다.
  • ㄴ유니크 스캔을 하면 lock wait 발생하지 않는게 웃기지 않나?? Repeatable read에서 팬텀 로우를 막아준다는데 안 막아준다. ㅈㄴ 어불성설이다ㅋㅋㅋㅋㅋㅋㅋㅋ(아 근데 이 부분에서 lock wait 발생하면 동시성 ㅈ됨)
  • read committed 격리 수준일 때 되는 이유는 단순하다. gap lock, next-key-lock이 비활성화 되어 있기 때문이다.
  • 반대 상황도 Lock이 발생한다. 1) insert 2) delete 풀 테이블 스캔

기타 주의 사항

  • 인덱스 조건없이 쿼리하는 경우 테이블 락 발생
  • 2개 이상의 세션에서 동일한 인덱스 키를 사용하여 다른 행의 레코드에 엑세스할 때 락 충돌할 수 있다(동일한 스캔 범위가 있는 경우 lock wait 발생)
  • 인덱스 효율이 좋지 않으면 락 범위가 넓어진다.
  • 아무리 PK/유니크 인덱스를 사용하여도 옵티마이저 판단하에 풀 테이블 스캔으로 테이블 락이 발생할 수 있다(지금 상황).

재연

1. 테이블 생성

mysql> create table test_tt(t1 int primary key auto_increment, t2 int, t3 int); 
Query OK, 0 rows affected (0.09 sec)

2. 테스트 데이터 삽입/조회

mysql> insert into test_tt(t2, t3) values (1,2); Query OK, 1 row affected (0.00 sec) 
... 

mysql> select * from test_tt;
+----+------+------+
| t1 | t2   | t3   |
+----+------+------+
|  1 |    1 |    2 |
|  2 |    1 |    2 |
|  4 |    1 |    2 |
| 31 |    1 |    2 |
| 32 |    1 |    2 |
| 33 |    1 |    2 |
| 34 |    1 |    2 |
| 35 |    1 |    2 |
| 36 |    1 |    2 |
| 37 |    1 |    2 |
| 38 |    1 |    2 |
| 39 |    1 |    2 |
| 40 |    1 |    2 |
| 41 |    1 |    2 |
| 42 |    1 |    2 |
| 43 |    1 |    2 |
| 44 |    1 |    2 |
+----+------+------+
17 rows in set (0.00 sec)

3. 삭제 실행(세션 1, 트랜잭션 시작, 삭제실행)

mysql> explain delete from test_tt where t1 in(31,32,33,34);
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | DELETE      | test_tt | NULL       | ALL  | PRIMARY       | NULL | NULL    | NULL |    4 |   100.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set (0.00 sec)

4. 삽입 실행(세션2, 트랜잭션 시작)

mysql> insert into test_tt(t2, t3) values (1,2);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

5. DB 락 현황 조회 결과

mysql> select * from information_schema.innodb_locks;
+--------------+-------------+-----------+-----------+-------------------+------------+------------+-----------+----------+------------------------+
| lock_id      | lock_trx_id | lock_mode | lock_type | lock_table        | lock_index | lock_space | lock_page | lock_rec | lock_data              |
+--------------+-------------+-----------+-----------+-------------------+------------+------------+-----------+----------+------------------------+
| 10586:43:3:1 | 10586       | X         | RECORD    | `mysql`.`test_tt` | PRIMARY    |         43 |         3 |        1 | supremum pseudo-record |
| 10581:43:3:1 | 10581       | X         | RECORD    | `mysql`.`test_tt` | PRIMARY    |         43 |         3 |        1 | supremum pseudo-record |
+--------------+-------------+-----------+-----------+-------------------+------------+------------+-----------+----------+------------------------+
2 rows in set, 1 warning (0.00 sec)
 
mysql> select * from information_schema.innodb_lock_waits;
+-------------------+-------------------+-----------------+------------------+
| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id |
+-------------------+-------------------+-----------------+------------------+
| 10586             | 10586:43:3:1      | 10581           | 10581:43:3:1     |
+-------------------+-------------------+-----------------+------------------+
1 row in set, 1 warning (0.00 sec)

 

참고문헌

Posted by 동팡

간단메모 

 

개요

  • KDF(Key Derivation Function)는 에플리케이션/프로토콜 서브 로직 등에서 많이 활용할 수 있다.
  • 사용자 정의 보안 프로토콜에서 Key/IV/Nonce 등의 Secret 값을 만들기 위해 사용한다.
  • 우리가 사용하는 인증서의 비밀번호는 PBKDF를 사용한다(실질적으로 표현하면 인증서에 상응하는 PrivateKey를 암호화하는 키를 생성하기 위한 비밀번호).
  • PBKDF는 패스워드/Hash 기반으로 키를 유도한다.
  • HKDF는 HMAC을 기반으로 키를 유도한다.
  • HKDF는 "extract-then-expand"의 페러다임(2개의 모듈)을 갖고 있다.
  • extract에서는 일반 입력 값으로(엔트로피가 낮은 값으로) 고정 길이의 PRK(의사난수 키) 값을 추출한다.
  • expand에서는 extract에서 발췌한 PRK를 확장한다.

플로우

  1. HKDF-Extract(salt, IKM) -> PRK(의사난수키)
    • salt: HMAC에서 Key로 사용(공개 값 사용 가능)
    • IKM: HMAC 대상 data
    • salt가 null인 경우 아래와 같음
    • byte[] salt = DatatypeConverter.parseHexBinary("0000000000000000000000000000000000000000000000000000000000000000");
      Mac mac = Mac.getInstance("HmacSHA256");
      mac.init(new SecretKeySpec(salt, "RawBytes")); 
      byte[] extract = mac.doFinal(IKM);
  2. HKDF-Expand(PRK, info, L) -> OKM(최종 결과)
    • PRK: Extract의 결과
    • info: salt와 비슷한 아무 값(생략 가능)
    • L: 결과 값의 길이 
    • /*
      The output OKM is calculated as follows:
        N = ceil(L/HashLen)
        T = T(1) | T(2) | T(3) | ... | T(N)
        OKM = first L bytes of T
      where:
        T(0) = empty string (zero length)
        T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
        T(2) = HMAC-Hash(PRK, T(1) | info | 0x02)
        T(3) = HMAC-Hash(PRK, T(2) | info | 0x03)
        ...
       */
    • 위의 식으로 HMAC 결과 값 만큼 append하여 결과를 출력한다. 
    • 만약 HmacSHA256을 사용하고, 원하는 출력값이 96인 경우 위의 where절을 3번 실행한다.

기타 정보

  • Extract의 salt는 재사용이 가능하며, 없어도 되지만 보안상 추가하는 것이 좋다고 봄.
  • Expand의 "info"는 여러개의 세션 또는 컨텍스트 간에 중복 결과를 방지한다. IKM은 같은 경우가 많으니 info 값을 salt 처럼 활용하는 것 같다.
  • 만약 extarct에서 사용하는 입력 값이 높은 엔트로피를 갖고있으면 extract는 생략할 수 있다.
  • 최종 결과 값 OKM 값이 해시 길이(예:32byte)보다 낮은 경우 PRK를 대신사용할 수 있지만, 권고하지 않음

보안

참고문헌

 

Posted by 동팡

목차

  • 시리즈 소개
  • 개요
  • 라이브러리 소개
  • 데모 - 1
  • 데모 - 2
  • 데모 - 3
  • 데모 - 4
  • 마치며, 다음 시리즈

 

시리즈 소개

본 시리즈는 웹페이지 앞단에서 게시판 페이징을 하는 방법을 소개한다. 즉, JavaScript에서 어떻게 페이징 처리하는지 확인할 수 있다. 피곤하지 않으면 2장 라이브러리 최적화 작업을 진행할 예정이다. 요즘 바빠서 너무 피곤하다... 

  • Pure-JavaSciprt 게시판 페이징 - 1(기본/응용)
  • Pure-JavaSciprt 게시판 페이징 - 2(라이브러리 최적화)

 

개요

[들어가면서...]

웹 페이지에서 제일 많이 사용하는 기능은 단연 게시판이다. 그리고 신입 개발자가 처음에 직면하는 벽이 게시판 페이징 작업이다. 게시판 페이징 작업을 구글링 하여 구현하는 거는 진짜 쉽지 않을 것이다. 게시판 페이징 개발 스타일이 다양해서 이것저것 참고하다가 실패할 것이다. 차라리 책에서 제공하는 게시판 페이징 코드를 활용하는 게 정신 건강에 좋을 것이다. 

 

[게시판 페이징 개발 스타일]

그렇다면 어떻게 개발 스타일이 다를까? 다음과 같다.

  • Java(Spring) / JSP(JSTL) 백단 게시판 페이징 
  • JS 앞단 게시판 페이징

백단 게시판 페이징 스타일은 옛날 스타일이다. 백단에서 게시판 페이징에 필요한 데이터를 가공하여 앞단에 전달, JSP영역에서 JSTL 반복문을 사용하여 게시판 페이징을 구현한다. 단점은 1) 페이지 이동할 때마다 페이지 깜박임, 2) JSP에 종속적인 개발 방법이다. 앞단 게시판 페이징은 REST API가 많이 부각되면서 생기지 않았나 생각한다. 백단 기술 스택에 종속적이지 않고 페이지 깜박이는 현상도 없다. 필자 또한 후자를 소개하고자 한다. 

 

[게시판 페이징 라이브러리]

JS 게시판 페이징 라이브러리는 다양하다. 필자는 JS 개발하면서 2~3개 정도 사용했던 기억이 있다. 웹 페이지 특성상 가시적인 요소가 다분하기 때문에 요구사항이 많다. 이와 같은 요구사항을 모두 충족하는 게시판 페이징 라이브러리는 존재하지 않는다. 비약이 심했지만 진짜 찾다 포기했다. 또한 요구사항 충족을 위한 라이브러리 스터디와 분석이 필요하다. 해당 사항으로 인해 작업 속도가 더 느려질 수 있다. 그래서 결국 필자는 별도의 라이브러리를 개발하여 사용하고 있다. 이유는 단순하다. 외주작업을 혼자 하는데 지랄 같은 요구사항 이행하려면 기능 추가가 가능한 라이브러리가 필요하다. 그리고 실무에서 좀 있다 보면 게시판 페이징 라이브러리를 개발하는 것은 많이 어렵지 않을 것이다. 

 

 

[실무에서 게시판 페이징 디테일]

외주/회사 업무에서 겪은 게시판 페이징 요구사항은 다음과 같다.

  • 체크박스를 이용한 테이블 제어
  • 특정 로우에 이벤트 핸들링
  • 특정 열에 이벤트 핸들링
  • 특정 로우, 열에 이벤트 핸들링
  • 게시판 로우 제어
  • 퍼블리셔와의 템플릿 협업

주로 업무 시스템 개발하는 인원은 이것보다 좀 더 다양한 요구사항을 겪을 것이다. 필자는 다음의 요구사항 때문에 직접 만들기로 결심했다. 실제 개발 결과물이다.

특정 열에 이벤트 핸들링

있을 수 있지만, 각 열에 별개의 이벤트 핸들링을 지원하는 게시판 페이징 라이브러리를 찾지 못했다. 1년 전에 개발한 라이브러리이다.. 기억을 되살리고 테스트하여 시리즈를 연재한다.

 

라이브러리 소개

게시판 페이징을 하기 위한 복잡한 Pure-JS 라이브러리이다. 대단한 기능은 없다. 말마따나 복잡하다. 필자가 봐도 복잡하다. 라이브러리 최적화가 필요하기는 하다.  해당 라이브러리를 사용하기 위한 필수 값이 존재한다. 당연 필수 값은 게시판 페이징에 사용되는 데이터들이다. 데이터들은 백단 API를 이용해서 반환받을 수 있다.

  • total: 게시판 페이징 데이터의 총 로우 수
  • limit: 게시판에 뿌려질 데이터의 개수
  • offset: 게시판 페이지의 위치 
  • datas: 게시판에 뿌려질 데이터 

Oracle 외의 RDBMS를 이용하여 게시판 페이징을 했으면 limit, offset을 알 수 있다. RDBMS에서 limit, offset과 같은 의미고 같은 기능이다. 

 

아 참고로 바빠서 넣지 못한 기능이 페이징 넘버링에 대한 이벤트 바인딩이다. Prev, Next, 페이지 넘버에 대한 이벤트 바인딩은 사용자가 직접 추가해야 한다. 

(라이브러리 최적화 때 이벤트 바인딩 기능을 추가하면 괜찮을 것 같다.) 

 

소개는 짧게 하고 바로 데모를 진행한다. 

 

데모 1: 게시판 페이징 기본

백문이불여일견 JS 피들을 확인한다. 차근차근 진행하기 위해 이벤트 바인딩은 하지 않았다. JS, HTML 영역을 보면 쉽게 이해할 수 있다.

JS 영역

function renderTableList(tableDivEl, pageDivEl, tlbLibOpt) {
    var tblPageEl = new TblPager( tableDivEl, pageDivEl, tlbLibOpt).generateTablePage();
}

HTML 영역

<body>
  <!-- table -->
  <div id="tblArea"></div>
  <!-- //table -->
  <!-- pagination -->
  <div id="pageArea"></div>
  <!-- //pagination -->

</body>

 

설명

  • TEST DATAS는 백단 API에서 데이터를 받았다는 가정이다.
  • div의 id는 꼭 위와 같이 설정한다.
  • tlbLibOpt의 Object Literal은 라이브러리가 지정한 값만 사용해야 한다. 
  • headers를 이용하여 백단 API에서 받은 것을 사용자가 보기 좋게 TH 문구를 바꾼다. header는 tlbLibOpt에 꼭 추가해야 한다. 
  • tlbLibOpt의 변수명을 보면 대강 의미를 이해할 수 있다.

 

데모 2: 게시판 페이징, 이벤트 핸들링 추가

백문이불여일견 JS 피들을 확인한다. 페이지 번호와 Prev, Next에 이벤트 바인딩하였다. 이벤트 바인딩을 사용자가 하기 때문에 중복 코드와 복잡성을 가중한다. JS 피들에서 번호를 누르면 이동되는 것을 확인할 수 있다.

데모 2의 코드 플로우는 다음과 같다(추상화). 

  1. 페이지 DOM 로드 완료 후, 백단 API을 호출한다.
  2. 백단 API에서 받은 데이터를 JS DOM 랜더링 함수에 전달한다.
  3. JS DOM 랜더링 함수는 DOM을 생성/수정한다. 
  4. DOM 랜더링 완료 후 특정 DOM에 이벤트를 추가한다.
  5. 특정 DOM의 이벤트가 발생하면 2번부터 반복한다.

데모 2의 코드 플로우는 다음과 같다(구체화).

  1. 페이지 DOM 로드 완료 후, 게시판 페이징 백단 API을 호출한다.
  2. 백단 API에서 받은 데이터를 게시판 페이징 랜더링 함수에 전달한다.
  3. 랜더링 함수는 게시판 페이징 함수를 호출하여 DOM을 생성/수정한다.
  4. 게시판 항목(DOM) 랜더링 완료 후 페이지 번호, Prev/Next에 이벤트를 추가한다.
  5. 페이지 번호를 누르면 2번부터 반복한다.

 

데모 3: 게시판 페이징, 응용 - 요구사항 진행1

백문이불여일견 JS 피들을 확인한다. 퍼블리셔가 작업한 템플릿에 CSS의 기능을 죽이지 않고 JS 코드를 삽입해야 한다. 또한 고객의 요구사항을 몇 개 이행해야 한다. 이번 데모는 다음과 같은 요구사항을 이행한다.

  • 퍼블리셔가 작업한 템플릿이 적용된 게시판 페이징
  • 특정 로우, 특정 열 데이터 핸들링
  • 특정 열 데이터 핸들링

tlbLibOpt변수에 다음의 사항을 추가하였다.

tlbLibOpt : {
  tableInfo: {
    options: {
      tableClassName: "tableClassName",
      customBeforeThTag: function() { return tableColGroup },
      customThTag: function(headerVal) {
        if ( headerVal === "aaa" ) 
          return { start: "<th><span class='no_arrow'>", end: "</span></th>" }
        else 
           return { start: "<th><span>", end: "</span></th>"}
      },
      customTdBodyTag: function( headerVal, index ) {
        if (index == 2 && headerVal === "bbb") {
          return { start: "<td><span><b>", end: "</td></span></b>" }
        } else {
          return { start: "<td><span>", end: "</td></span>" }
         }
	  },
      customTdBodyValue: function( headerVal, listValue ) {
        if ( headerVal === 'bbb' ) {
          if ( listValue === true) {
            return '성공'
          } else {
            return '실패'
          }
        }

        return listValue
      }
    }
  },
  pageInfo: {
    options: {
      customPrev: {
        start: "<a href='#none'",
        end: "> <<<< </a>",
      },          
      customNext: {
      	start: "<a href='#none'",
        end: "> >>>> </a>",
      },
      customPageNum: {
        totalStart:"<span>",
        start: "<a href='#none'>",
        end: "</a>",
        totalEnd:"</span>"
      }
    }
  }
}

나참 드럽게 복잡하다;;

  • tableClassName: 생성되는 테이블에 class 이름을 추가한다.
  • customBeforeThTag: 테이블의 colgroup을 추가하기 위한 공간이다. <table><colgroup><thead>
  • customThTag: 콜백 함수를 추가했다. headerVal을 활용하여 특정 열에 다른 th 태그를 사용할 수 있다.
  • customTdBodyTag: TD의 특정 열 특정 로우에 특정 태그를 사용할 수 있다.
  • customTdBodyValue: TD의 특정 열 특정 로우에 값을 제어할 수 있다. 
  • customPrev/Next: 뒤로 가기에 특정 태그를 사용할 수 있다(이미지 삽입할 수 있다.).
  • customPageNum: 페이지 넘버링에 특정 태그를 삽입할 수 있다. 

개발자 도구를 활용하여 HTML 태그 랜더링이 어떻게 변했는지 확인할 수 있다. 

 

데모 4: 게시판 페이징, 응용 - 요구사항 진행2

 

백문이불여일견 JS 피들을 확인한다. 데모 3을 베이스로 다음의 추가 요구사항을 이행한다. 

  • 체크 박스 처리
  • 특정 로우, 특정 열 이벤트 바인딩
  • 특정 로우 이벤트 바인딩

 

마치며, 다음 시리즈

인터넷에 돌아다니는 게시판 페이징 테마(CSS)를 사용하여 추가 데모를 시연할 것이다. 또한 데모에서 불편한 사항을 개선할 예정이다. 당장 눈에 보이는 불편한 사항은 다음과 같다.

  • 사용자는 페이징 1~10, Prev, Next DOM의 이벤트 바인딩을 해야한다. 
  • 사용자는 체크 박스의 이벤트 바인딩을 해야한다.
  • 사용자는 테이블 로우 클릭 이벤트 바인딩을 해야한다.
  • 라이브러리에서 제공하는 기타 유틸 함수가 부족하다.

다음 시리즈는 위의 열거한 사항을 기반으로 추가 분석을 실시하여, 라이브러리 최적화 작업을 진행한다. 진행한 결과물에 테마를 입혀 데모를 시연한다. 

 

Posted by 동팡

독자 정보

  • 5 ~ 10년 차 개발자(블로그 3년 차)

 

독서 일자

  • 2021. 07

 

내용

  • 작문 원칙 제공
  • 작문을 위한 상세 시나리오 제공
  • 개발자의 언어를 비개발자(고객/동료)의 언어로 치환하는 과정을 제공 
  • 왜 변수 네이밍 컨벤션을 본문에 실었는지...?(내용은 괜찮으나 책의 주제와 연관관계가 강해보이지 않음)

 

별점

  • 4.3/5.0(체계 있는 본문의 구성, 심도가 있음, 추천+)

 

대상 독자

  • 작문의 질 향상을 원하는 인원(Best)
  • 블로그를 시작하는 주니어 개발자

 

선행 도서

  • 없음

 

관련 도서

  • 개발자를 위한 글쓰기 가이드

 

느낀 점

해당 서적은 오류 문구 정의, 가이드 문서 작성, 장애 보고서 작성 등의 중요 문서 작성 후 검토할 때 많이 참고할 것 같다. 그만큼 본문의 구성은 깊이가 있다. 좋은 문서를 작성할 수 있도록 안내해주는 종합 지침서의 느낌을 받았다. 필자의 표현이 너무 추상적이다. 어떻게 종합 지침을 하였는지 서술하겠다. 해당 서적의 파트 중 하나인 "릴리스 노트 작성법"을 축약하였다. 대강 저자는 아래와 같이 최종 문서를 어떻게 구성하는지 상세하게 설명한다. 

  • 프로젝트의 개선/릴리스 내역 정리
  • 내역의 중요도 분류
  • 내역의 주제별 분류
  • 사용자 관점, 문구 수정
  • 문구 요약 
  • 문서 틀에 맞게 적재적소 문구 삽입

끝으로 개발자와 글쓰기의 연관관계를 정리한다. 전적으로 필자의 생각이다. 좋은 개발자의 요소 중 하나는 테크니컬 라이팅 능력이다. 주요 골자는 소통이다. "페이퍼를 이용한 소통". 개발자는 명세서, 설계서, 분석서 등의 문서들을 활용하여 기술과 프로젝트 정보를 효율적으로 전달해야 한다. 소통이 왜 필요해요? 소통은 문제 해결을 위한 선행 행위다. 그래서 개발자에게 있어, 문서 작성 능력은 선택 사항이 아닌 필수 사항이다. 필자가 중요하게 생각하는 문서 작성 능력은 다음과 같다.

  • 사용자 관점에 맞는 문서 구조화 능력

쉽게 얘기하면 문서는 객체 지향 개발 방법론의 "객체" 처럼 구조적이었으면 좋겠다. 객체처럼 역할, 책임, 상태, 행위가 있고 이를 통해 상호 협력(소통)을 할 수 있으면 비로소 그것은 좋은 문서가 아닐까 생각한다.

 

Posted by 동팡

목차

  • 들어가며
  • Vault Docker 환경 구성
  • 참고문헌

 

들어가며

본 게시물은 Vault 공식 문서의 내용과 필자의 생각을 정리하였다. Vault는 무엇인지, 어디에 사용하는지, 왜 사용하는지, 어떻게 사용하는지 서술한다. Vault를 처음 접하는 인원은 Vault의 흐름과 골격을 이해할 수 있는 시간을 갖는다. 또한 Vault를 실질적으로 사용해보는 시간을 갖는다. Vault는 Dev 서버 모드를 지원한다. Dev 서버 모드는 사전 설정이 되어있는 데모 서버라고 생각하면 좋다. 사용자는 해당 데모 서버에서 Vault를 학습할 수 있다. 시간이 괜찮으면 Vault HA를 구성한다(시간이 있으면...). 

 

본 게시물의 시리즈는 다음과 같다.

 

Vault Docker 환경 구성

[개요]

yum 패키지 설치 기능을 사용하여 Vault 환경을 구성할 수 있다. 이번에는 Docker를 활용하여 Vault 환경을 구성한다. 해당 환경을 구성하기 위해 Docker는 당연히 사용하며, Docker-Compose까지 사용한다. 디렉토리의 구조는 아래와 같다. 환경 구성 후 가동 및 테스트 API만 호출한다.

vault
 |
 -- data  
 |
 -- config
 |    | 
 |    -- config.hcl
 |
 -- docker-compose.yml

 

[Docker 설치 및 기본 설정]

Docker는 별도의 설정을 하지 않을 경우 root 권한으로만 가동할 수 있다. 아래와 같이 설정하면 user 권한에서 Docker를 제어할 수 있다. 

$yum install docker
$yum install docker-compose

$groupadd docker
$usermod -aG docker $username
$sudo systemctl start docker
$sudo chmod 666 /var/run/docker.sock

Docker 명령어 확인 및 Vault 최신 이미지를 갖고온다. 

$docker ps -a

$docker pull vault

 

[Vault - Config]

 

#config.hcl

storage "raft" {
  path = "/vault/file"#vault dir in docker
  node_id = "node1"
}

listener "tcp" {
  address = "0.0.0.0:8200"
  tls_disable = "true"
}

api_addr="http://127.0.0.1:8200"
cluster_addr="https://127.0.0.1:8201"
ui = true

참고로 Listen address를 0.0.0.0을 설정해야 정상 가동할 수 있다.

 

[Vault - docker-comopse.yml]

#docker_compose.yml

version: "2"

services:
  vault:
	image: vault:latest
	container_name: vault
	volumes:
	  - ./vault/config:/vault/config
	  - ./vault/data:/vault/data
	ports:
	  - 8200:8200
	cap_add:
	  - IPC_LOCK
	command: vault server -config=/vault/config/config.hcl

 

[Vault - Docker 구동 및 테스트]

$docker-compose up -d

$curl http://127.0.0.1:8200/v1/sys/init | jq

//응답
{"initialized":false}

위의 응답은 정상적인 반환문이다. 

Vault 서버의 초기화 작업($vault operator init)을 하지 않았기 때문에 반환문의 값은 false이다. 

 

참고문헌

https://blog.exxeta.com/en/2019/12/20/setup-hashicorp-vault-on-docker/
https://stackoverflow.com/questions/50031086/why-does-vault-by-hashicorp-require-the-ipc-lock-capability-to-be-enabled
https://stackoverflow.com/questions/45171564/using-vault-with-docker-compose-file
https://hub.docker.com/_/vault
https://github.com/hashicorp/vault/issues/441

 

Posted by 동팡