• 2022 카카오 공채 코딩테스트 감독을 하면서.. 그리고 TDD
    DEV 2023. 12. 2. 09:23

    test

    21년 9월 카카오 신입 공채 2차 온라인 코딩 테스트 감독을 진행하였습니다. 좀 늦었지만, 이 글은 당시 코딩테스트 감독을 진행하며 느꼈던 점들을 공유하기 위해 작성하였습니다.

     

    코로나19로 인해 온라인 환경에서 비대면으로 테스트가 진행되었습니다. 참가자들은 코딩 테스트 플랫폼에서 문제를 풀고, 감독관은 참가자들의 모니터 화면을 지켜보며 여느 시험 감독관들처럼 부정행위를 파악하거나 시험 중 질문을 받았습니다. 저는 총 8명의 참가자를 감독하였습니다. 문제를 푸는 참가자들의 공유된 모니터를 한자리에서 볼 수 있는 것도 재미있는 경험이었습니다. 각자 다른 방식, 순서로 문제에 접근하기도 하고, 또는 비슷한 방식으로 문제를 해결하지만 사용하는 언어에 따라서도 코드의 구조가 달라지는 것을 보는 것도 흥미로웠습니다.

     

    코딩테스트 문제와 문제해설은 이곳에 공유되어 있습니다. 문제를 간단히 요약하면 게임의 매칭 시스템을 만드는 것입니다. 문제 접근 방식은 게임 매칭 시 매칭시간을 길게 잡으면 비슷한 실력의 유저를 찾을 확률이 높아서 정확성은 높아지지만 효율성이 떨어지고, 반대로 매칭 시간을 줄이면 효율성은 좋아지지만 정확성은 떨어지기 때문에 둘 사이의 trade-off를 잘 고려하는 것입니다.

     

    또한 작성한 프로그램을 테스트하기 위해 테스트 API를 호출하여 유저의 실력 순위를 계산해 제출하면 리더보드에 자신이 제출한 매칭시스템의 점수, 순위가 공개되어, 코딩테스트가 끝날 때까지 높은 점수를 얻기 위해 자신의 매칭 시스템의 알고리즘을 튜닝해 가야 합니다.

     

    제가 주목했던 부분은 테스트 시 여러 번의 API통신이 발생하고 매칭을 기다리는 시간도 있기 때문에 한번 테스트를 하려면 2~3분 정도의 시간이 걸린다는 점이었습니다. 제가 감독했던 모든 참가자들은 테스트를 돌리고 문제나 작성한 코드를 다시 살펴보거나, 화장실을 다녀오거나, 웹서핑을 하기도 했습니다. 

    비슷한 행동패턴

    시간이 지나면서 참가자들의 비슷한 행동패턴이 보였습니다.

    1. 코드수정 -> 테스트 (2~3분) -> 성공 -> 순위 확인 -> 코드수정
    2. 코드수정 -> 테스트 (x~3분) -> 실패 -> 코드수정

    위 작업의 반복을 지켜보며 느낀 점은 에러로 인한 테스트 실패가 반복되거나, 테스트 시간이 길어지거나, 시스템을 튜닝해 가며 프로그램이 조금씩 커질수록 코드수정(리펙토링)에 점점 소극적이 되어간다는 것이었습니다. 시간이 갈수록 간단한 변숫값들을 수정해 가면서 테스트를 반복하는 모습을 볼 수 있었습니다. 결국 대부분 처음 완성한 모듈의 구조는 거의 변하지 않았습니다. 코드 수정 후 테스트 비용이 너무 크기 때문에 참가자들이 코드 변경의 불안함을 느끼고 더욱 신중해진 것처럼 느껴졌습니다. 

     

    물론 코드의 구조 개선이 반드시 성능의 향상을 의미하는 것은 아니지만, 참가자들이 리펙토링에 소극적이 되는 모습에 대해 이야기하고 싶었습니다. 그리고 그 원인은 코드 변경의 불안함에서 오는 것처럼 느껴졌습니다. 그리고 아마도 이것은 비단 코딩테스트에만 해당하는 이슈는 아닐 겁니다.

     

    불안

    불안함 없이 리펙토링 하려면?

    In mathematics, factorization or factoring consists of writing a number or another mathematical object as a product of several factors, usually smaller or simpler objects of the same kind. For example, 3 × 5 is a factorization of the integer 15, and (x – 2)(x + 2) is a factorization of the polynomial x2 – 4. - Wikipedia

     

    수학에서의 펙토링(인수분해)은 하나의 숫자를 더 작거나 단순한 여러 개의 요소로 작성하는 것이라고 위키피디아에서 설명하고 있습니다. 예를 들어 15 = 3 x 5로 표현하듯이. 비슷한 의미로 프로그래밍에서의 리펙토링이란 의미를 유지하며 코드베이스를 정리하는 것이라 할 수 있습니다.

     

    그렇다면 어떻게 의미 유지를 확인할 수 있을까요? 답은 테스트 케이스에 있습니다. 

    • 일반적인 개발 순서: 개발 -> 리펙토링 -> 테스트
    • TDD의 개발 순서: 테스트 -> 개발 -> 리펙토링

    TDD를 통해 개발한다면 테스트 케이스를 우선 추가하고 테스트를 통과할 정도의 코드만 개발하기 때문에 오버 엔지니어링도 줄일 수 있고, 미리 작성된 테스트 케이스를 통해 리펙토링 시 내가 방금 수정한 코드가 기존코드의 의미를 변경하진 않았는지를 매우 적은 비용으로 확인할 수 있습니다. 

     

    참가자들의 시간 사용 비율을 대략적으로 나누어 볼 때 총 5시간 중, 개발에 2~3시간, 리펙토링 1시간, 테스트 1시간 정도를 사용하였습니다. 코드 수정 후 2~3분가량 걸리는 테스트를 돌리기 전에 미리 작성한 단위 테스트 통과 여부로 에러 발생 유무를 미리 확인한다면 테스트 시간을 줄일 수 있고, 실패 시 빠른 피드백을 받을 수 있기 때문에 조금 더 적극적이고 자신감 있는 리펙토링이 가능하지 않았을까? 하는 생각이 들었습니다.(물론 TDD에 익숙하다는 전제이지만..)

    그럼 실제 코딩테스트에 TDD를 사용할 것인가?

    TDD, 비용, 시간

    위 그림을 보았을 때 TDD를 통한 효과를 얻기까지는 꽤 오랜 시간(t2)이 걸릴 수 있기 때문에 적용여부에 대해서는 많은 고민이 필요해 보입니다. 운영하는 서비스의 운영기간이 t2보다 짧다면 효과를 볼 수 없기 때문입니다. 운영기간이 단 하루인 코딩테스트의 경우에 TDD를 적용하는 것은 별로 의미가 없어 보입니다. 다만 위 문제와 같이 지속적인 리펙토링이 필요한 테스트의 경우 TDD에 익숙하다면 시도해 볼 수도 있지 않을까? 싶네요.😅

    728x90

    'DEV' 카테고리의 다른 글

    K8S, DNS 간헐적 5~15초 지연  (0) 2023.12.02
    Test Double  (1) 2023.12.02
    Dependency Mechanism  (1) 2023.12.02
    slf4j, facade, TDD  (1) 2023.12.02
    Elasticsearch Shard & 성능  (1) 2023.12.02
go.