All Articles

2023년 과제형 코딩 테스트 후기 (2)

연재 안내

들어가며

이 게시글은 최근 치렀던 코딩 테스트를 회고하는 게시글입니다.

이 게시글에선 무엇으로 인해 코딩 테스트에서 탈락이라는 고배를 마셨는지, 그 원인을 스스로 반추해보는 내용이 주가 될 것입니다.

목차

왜 떨어졌을까?

완성하지 못한 소프트웨어에, 외부 공부의 모자람, 그리고 막상 파이썬을 사랑한다고는 하지만 정말 그렇지 않음이 복합적으로 적용된 것이라고 복기할 수 있겠습니다.

완성된 소프트웨어가 기본이다

앞서 말했듯 많은 것을 배웠으나, 가장 중요한 결과 달성에 실패했습니다. 이것이 가장 큰 원인이지 않았을까 합니다.

완성되지 않은 소프트웨어는 내부적으로 아무리 깔끔하고 좋다고 한들 아무런 가치를 창출하지 않습니다. 과제의 본 목적을 벗어나 기술을 탐미하는 것은 엔지니어로서의 자세라고 할 수 없습니다. 신기술이어서, 뜻대로 돌아가는게 신기해서, 뭔가 블록맞추기가 완성되는 즐거움에 취해서 본질을 생각하지 않는 것은 경계해야 할 자세입니다.

아키텍처 학습 부족

DDD나 클린 아키텍처, 헥사고널 아키텍처를 단기간에 올바른 방안으로 쓰기는 쉽지 않습니다. 이견없는 주제를 향해 많은 사람이 머리를 맞대는 현업과 달리, 이 자리는 제 역량을 점검받는 자리였기 때문입니다. 따라서 평소에 얼마나 이런 설계 방법이나 외부 사항들을 학습했는지, 토이프로젝트를 수행해본 적은 있는지를 평가받는 자리입니다. 매력적인 지원자가 되고 싶었다면 평소에 미리미리 했어야 했습니다.

‘망치를 들면 모든 것이 못으로 보인다’라는 격언이 있습니다. (발언의 의도와 다르게) 여러 망치를 가진 기술자는 선택의 폭이 그만큼 넓어지죠. 어느 도메인에 속하더라도 사용할 수 있는 여러가지 접근 방법을 학습해야 하지 않을까요? 이 점을 사무치게 반성했습니다.

파이썬 deep-dive, 진짜 하고있나?

주력 언어를 파이썬으로 두고, 이를 잘 쓰고자 하는 노력이 부족했지 않았나 하는 생각을 하게 되었습니다. 아래에서 설명하겠습니다.

random 라이브러리는 seed 기반임을 알고있었나?

random이란 파이썬 기본 라이브러리는 객체 생성 시의 seed 값을 기반으로 연산을 하는 유사-난수 생성로직 입니다. random 라이브러리의 시드는 기본값으로 현재 시각을 시드로 사용하고, 랜덤난수가 주어진다면 이를 사용합니다(관련 설명). 특정 시드를 누군가가 예측한다 면, 어떤 값이 리턴됨을 “예측”할 수 있을 것입니다. 설령 MT19937 로 난수를 훌륭하게 예측했다 하더라도요. 또한 현재 제가 사용한 로직은 이 CTF 문제의 write-up을 보아도 충분히 깨질 수 있는 가능성이 열려있음을 알 수 있습니다.

참고) random은 cryptographically secure 하지 않습니다.
그러한 목적이라면 secure 같은 라이브러리를 사용하기를 권장합니다.

논외로, 매 호출 시 새로운 시드값을 계속 생성하여 사용하는 것도 좋은 방법은 아닌 듯 합니다. 뾰족한 대안이 생각나지 않고 빠르게 구현해야 했다면, 차라리 이런 최소한의 조치라도 했다면 어땠을까 합니다.

  1. 로직 설계
    1. 확신이 서지 않는 로직이므로, 비록 공식 라이브러리라 할지라도 이른바 “경계” 소프트웨어로 간주한다.
    2. 얼마든지 교체할 수 있도록 ‘랜덤 값 제공 라이브러리’를 wrapping 하여 객체간의 상호작용으로 사용한다.
  2. 로직구현
    1. “랜덤”한 시간에 한번씩 시드값을 외부 in-memory service에 기록한다. 시드값은 예측하기 어려운 값을 사용한다(현재시각값에 salt를 추가한 해시 등).
    2. “랜덤”한 값이 필요하다면, in-memory service에서 가지고와서 사용한다.
    3. “랜덤”한 시간 후 시드값을 새로운 값으로 갱신한다.

사용하는 라이브러리에 대한 deep-dive가 모자라지 않았나?

pytest의 미숙함이 너무나 아쉬웠습니다. 테스트의 중요성은 이미 알고있음에도, 정작 필요한 부분을 테스트해보지 못하였습니다. 그리고 pytest의 사용법이 미숙하여 적재적소에 이를 활용하지 못했습니다.

애플리케이션 테스트는 왜 못했나?

서비스 레이어에서, Mocking 을 통해 얼마든지 객체를 갈아끼워서 테스트할 수 있음을 꾀했습니다만 이를 많이 다뤄보지 못했기 때문에 시간이 지체되었습니다. 따라서, 로직만을 검증하자는 케이스를 작성할 때도 쓸데없이 시간이 많이 소요되어 결국 틀만 짜고 테스트를 마무리하지 못했습니다.

e2e test는 왜 못했나?

FastAPI에서 제공하는 TestClient는 이벤트 루프 관리를 제대로 못해주는 것으로 파악되었습니다. 따라서 차라리 늦더라도 httpxAsyncClient를 어떻게든 학습하여 풀어내는 것이 필요했습니다. 또한 테스트코드 구동 시 DB관련 이슈도 mark.anyio로 했더니 trio 쪽에서 이벤트 루프 문제가 생깁니다. 이 또한 이벤트 루프를 asyncio 로 지정해서 풀어냈어야 했습니다. 이런 유스케이스는 일일이 학습하지 않으면 절대 알 수 없는 것들입니다. 공식 문서를 봤음에도 배우지 못함에 반성합니다.

평소 중시하는 ‘동료에 대한 배려’를 해두었나?

마지막까지 섬세함을 보일 수 있는 부분 또한 채우지 못해 매우 아쉬웠습니다.

API Docs 제공은 왜 하지 못했나?

FastAPI는 OAS 3.0 표준에 의거한 문서 뿐 아니라 ReDoc과 Swagger 페이지를 함께 제공해줍니다. 이는 FastAPI의 강점 중 하나이지요. 원래라면, 스펙 공유를 위해 OAS 3.0 YAML 파일을 작성하는 수고를 들일 필요가 있습니다. 그렇지만 로직에 코드로 작성하여 이러한 문제를 최소한으로 하는 방안은 외부에 너무나도 쉽게 잘 정리되어 있습니다. 1 그렇지만 다른 부분에 시간을 너무 투자하여 이러한 디테일을 더한 채로 서비스하지 못한 것이 너무 아쉽습니다.

진행사항 공유를 위한 문서화 제공은?

진행사항 공유는 전체 구성원들에게 정말 중요한 일입니다. 특히나 애자일함을 중시하는 조직이라면 더더욱 그렇지요. DDD에서 말하는 유비쿼터스 언어를 잘 정의한 문서라도 하나 만들었다면, 이를 토대로 의사소통할 수 있는 방안을 제공할 수 있지 않았나 싶습니다. 이런 부분들에 대해 제 스스로만 ‘알고있고’ 공유하려는 시그널을 보여주지 못한 것이 아쉽습니다.

마무리

이번 테스트를 통해 아래 사항을 얻을 수 있었습니다.

  1. 무엇이 모자랐는지 돌아볼 수 있었습니다.
    1. 완성을 못했습니다. 사실 이것만 해도 할 말이 없습니다.
    2. 기술적으로는 아래 면면들을 돌이켜볼 수 있었습니다.
      1. 아키텍처에 대해 스스로 공부해야 할 필요가 있겠습니다.
      2. 사용하는 라이브러리나 기술에 대해 스스로 공부해야 할 필요가 있겠습니다.
  2. 함께 일 할 구성원을 배려하지 못한 사항에 대해 돌이켜 볼 수 있었습니다.
    1. API 문서화의 부재가 아쉬웠습니다.
    2. 작업사항 공유의 부재가 아쉬웠습니다.

마지막으로…

토이 프로젝트를 하거나, 현업에서 일을 하거나 할 때 이런 부분들을 보이지는 않는지 반성하고 보다 나은 프로그래머가 되도록 노력해야겠습니다.

떨어지면 씁쓸하죠. 하지만 과정을 복기해보니 감사할 수 있었습니다. 더 달라져봅시다. 끊임없이 배우고 익혀서 두번 다시 이런 아쉬움을 남기지 않도록 합시다.

긴 글 읽어주셔서 감사합니다.


Ignis aurum probat, miseria fortes viros.

Seneca, De Providentia 1.5.10.


  1. 이러한 사용례를 현업에서 사용한 바 있으나, 자주 보지않아 놓치게 되곤 합니다. 앞으로는 이런 사항을 토이프로젝트로 미리 구현해놓아야 하겠습니다.

Published Feb 20, 2023

Non scholæ sed vitæ discimus.

his/him