테스트 코드는 왜 필요할까?

로봇 개발과 테스트 코드
아직도 많은 개발자들에게 ‘테스트 코드를 작성한다’라는 개념은 왠지 모르게 부담스럽거나 추가적인 번거로움으로 느껴질 수 있다. 특히 빠른 개발 속도와 결과물을 강조하는 환경일수록, 테스트 코드 작성이 우선순위에서 밀려나는 경우가 흔하다. 그러나 로봇 소프트웨어처럼 하드웨어와 직접 연동되고 동작 안정성이 중요한 도메인에서는 테스트 코드의 중요성을 결코 간과할 수 없다. 이번 글에서는 테스트 코드가 무엇이며, 왜 필요한지, 그리고 어떻게 작성하고 자동화할 수 있는지 살펴본다.
1. 테스트 코드란 무엇인가?
테스트 코드(Test Code)란, 구현한 기능이나 로직이 의도대로 동작하는지 자동으로 검증하기 위한 프로그램 코드를 의미한다. 예를 들어 로봇이 ‘장애물을 피하고 목적지로 이동’하는 기능을 구현했다면, 장애물을 정상적으로 감지하고 회피하는지, 특정 센서 입력값이 비정상일 때도 예외 처리가 적절히 이뤄지는지를 자동으로 검사할 수 있도록 만든 코드가 테스트 코드에 해당한다.
일반적으로 테스트 코드는 규모와 범위에 따라 다양한 단계로 구성된다. 가장 작은 단위(함수, 메서드, 클래스 등)를 대상으로 하는 유닛 테스트(Unit Test)가 있고, 여러 모듈을 연동해 전체 기능을 점검하는 통합 테스트(Integration Test)가 있다. 로봇 소프트웨어에서는 하드웨어 의존성이 크기 때문에, 단순히 유닛 테스트만으로 모든 상황을 검증하기는 어렵다. 따라서 통합 테스트도 함께 고려해 종합적인 시나리오가 의도대로 동작하는지 확인해야 한다. 유닛 테스트와 통합 테스트 이외에도 E2E 테스트, Nightly 테스트와 같은 더 넓은 범위의 테스트들도 있다. 컴파일 옵션에 따라 전체적인 프로세스 시간이 많이 길어지는 경우, 혹은 대용량의 데이터를 기반으로 테스트를 수행해야 하는 경우 특정 시간을 정해서 테스트를 수행하며, 보통 새벽에 많이 수행하기 때문에 Nightly 테스트라고 부르기도 한다.
2. 테스트 코드를 왜 작성해야 하는가?
“굳이 테스트 코드를 작성하지 않아도, 일단 코드를 돌려보면 제대로 작동하는지 확인할 수 있지 않을까?”라고 생각할 수 있다. 그러나 수동 테스트에는 분명한 한계가 존재한다. 특히 로봇 소프트웨어는 물리적인 환경에서 동작하기 때문에, 현장에서 모든 기능을 매번 직접 검증하는 데에는 많은 비용과 시간이 든다. 게다가 사람은 반복되는 테스트 과정에서 실수를 하기도 쉽다.
테스트 코드를 작성하면 다음과 같은 이점을 얻을 수 있다.
안정성 확보
코드가 변경되거나 신규 기능이 추가되었을 때, 기존 기능이 문제없이 동작하는지 빠르게 확인할 수 있다. 본인이 작성한 코드도 몇일이 지나면 기억이 나지 않는다. 심지어 여러사람이 함께 협업을 하는 경우라고 하면 이러한 안정성 확보는 무엇보다 중요하다.
기술 부채 감소
기능이 늘어날수록 “어디선가 예기치 않은 버그가 생기면 어떡하지?”라는 우려가 커진다. 테스트 코드가 있으면 수정 작업 후에도 빠르게 문제 여부를 파악할 수 있어 기술 부채가 쌓이는 속도를 줄일 수 있다.
개발 효율 증가
처음에는 테스트 코드를 작성하는 데 드는 시간이 부담이 될 수 있다. 그러나 장기적으로 보면 문제를 미리 발견·해결하는 과정이 빨라져, 전체 개발 효율이 오히려 높아진다.
협업 효율 상승
팀원이 새 코드를 추가하거나 기존 코드를 수정할 때, 해당 로직이 어떻게 동작해야 하는지 테스트 코드를 통해 빠르게 파악할 수 있다. 즉, 테스트 코드는 그 코드의 사용법에 대한 설명서이다.
코드의 구조화
테스트 코드를 작성하다 보면 자연스럽게 코드의 구조가 개선된다. 특히 유닛테스트는 하나의 함수에 대한 기능을 테스트하는 테스트이기 때문에 하나의 함수에 너무 많은 기능이 들어가게 되면 정확한 유닛 테스트를 작성하기 어려워 진다. 따라서 유닛 테스트 코드를 작성하다 보면 자연스럽게 하나의 함수는 최소한의 기능만 갖도록 구조화가 된다.
코드의 디버깅
테스트 코드를 작성하다 보면 다양한 테스트 케이스를 고민하게 되고, 그 과정에서 다양한 코드의 버그들을 발견하게 된다.
3. Unit Test와 Integration Test
테스트 코드를 구성할 때 자주 등장하는 개념이 바로 ‘유닛 테스트(Unit Test)’와 ‘통합 테스트(Integration Test)’다. 보통 두 테스트는 다음과 같은 차이가 있다.
- 유닛 테스트(Unit Test)
- 함수나 클래스, 혹은 모듈 수준으로 쪼갠 작은 단위를 테스트한다.
- 외부 의존성(네트워크, 하드웨어, 데이터베이스 등)을 가짜 객체(Mock)로 대체해 테스트한다.
- 내부 함수끼리의 의존 관계가 있는 경우 각 함수들의 출력을 Mocking 하여 원하는 시나리오를 테스트한다.
- 각 단위가 제대로 동작하는지 확인하므로 테스트가 빠르게 끝나고, 문제 발생 지점을 정확히 파악하기 쉽다.
- 통합 테스트(Integration Test)
- 여러 모듈이 합쳐졌을 때 전체 기능이 정상적으로 작동하는지를 검증한다.
- 로봇 소프트웨어라면 실제 센서값 수신부터 제어 모듈까지 연결해 시나리오 테스트를 진행하기도 하고, Mocking 센서 테이터를 기반으로 진행하기도 한다.
- 유닛 테스트만으로는 찾지 못하는 모듈 간 연동 문제나 예외 상황을 포착할 수 있다.
로봇 소프트웨어는 하드웨어 연동이 많아 단순 유닛 테스트만으로는 한계가 있다. 따라서 유닛 테스트로 기본 로직을 탄탄하게 검증하고, 통합 테스트를 통해 실제 운영 환경과 유사한 조건에서 시스템을 점검하는 방식이 권장된다. 추가적으로 Nightly 테스트를 관리하기도 하는데, 큰 데이터를 기반으로 한 테스트, 혹은 컴파일 시간이 매우 오래걸리는 테스트 (Memory Sanitizer, Thread Sanitizer 등)는 PR을 생성할 때마다 수행되는 CI 프로세스에서 수행하게 되면 전체적인 개발 프로세스에 지연을 야기 시킨다. 따라서 이런 테스트는 CI 프로세스와는 별개로 일정 시간에 수행되어 리포트를 생성하는 방식으로 테스트 하기도 한다.

4. TDD(Test Driven Development)
TDD(Test Driven Development)는 기능 구현보다 테스트 코드를 먼저 작성하는 개발 방법론이다. 보통은 기능을 먼저 구현한 뒤 검증용 테스트 코드를 작성하는데, TDD는 이 순서를 뒤집는다. 일반적인 TDD 흐름은 다음과 같다.
- 테스트 작성: 아직 구현되지 않은 기능에 대해, 원하는 동작과 인터페이스를 정의하는 테스트 코드를 먼저 작성한다.
- 테스트 실행: 당연히 구현되지 않았으므로 테스트가 실패(Fail)한다.
- 기능 구현: 실패한 테스트를 통과시키기 위한 최소한의 코드만 작성한다.
- 리팩터링: 테스트가 통과했다면, 코드를 리팩터링하여 품질과 가독성을 개선한다.
- 테스트 재확인: 리팩터링 후에도 모든 테스트가 통과하는지 다시 확인한다.
이 과정을 반복하면서 기능 요구사항이 더욱 명확해지고, 필요 이상의 코드를 작성하지 않게 된다. 다만 TDD를 적극적으로 적용하려면 팀원들이 테스트 작성에 익숙해져야 하며, 명확한 설계와 테스트 전략이 뒷받침되어야 한다. 로봇 개발 기준으로 데이터의 입력과 출력이 명확한 특정 기능을 갖춘 라이브러리를 작성할때는 이러한 TDD 개발 방식이 적합한 경우가 많다. 반면에 외부 센서 혹은 내부 프로세스들과의 통신이 빈번이 발생하는 인터페이스 프로세스는 개발 초기에 각 함수별로 입력과 출력을 나누기 어려운 경우가 많다. 이런 경우에는 기능을 먼저 개발하고 추후에 테스트 코드를 작성하는 방식으로 하기도 한다.

5. 테스트 코드를 작성하면 개발 속도가 느려질까?
테스트 코드를 작성하면 당장 눈앞의 개발 속도가 느려지는 것처럼 느껴질 수 있다. 특히 빠른 릴리스를 요구하는 환경에서는 “기능 구현만으로도 시간이 모자란데, 테스트 코드까지 작성해야 하느냐”는 불만이 나올 수도 있다.
그러나 장기적인 관점에서 보면, 테스트 코드가 없을 때 발생하는 디버깅과 재배포, 문제 파악에 드는 막대한 비용을 고려해야 한다. 버그가 뒤늦게 발견될수록 고치는 데 더 많은 자원과 시간이 투입된다. 반면 테스트 코드가 잘 마련되어 있으면 수정사항을 적용한 뒤 자동 테스트를 돌려 잠재적인 문제를 빠르게 발견할 수 있다. 이는 “빠른 실패(Fail Fast)”를 가능하게 하며, 전체 프로젝트의 안정성과 생산성을 모두 높이는 결과로 이어진다. 새로운 기능을 빠르게 개발하는 것도 중요하지만, 장기적인 관점에서 개발 속도가 조금은 느릴 수 있지만 안정적인 시스템을 갖추고 테스트 코드를 함께 개발하는 것이 올바른 개발 방법이다. 속도보다 중요한 것은 올바른 방향으로 가는 것이다.
6. 테스트 자동화

테스트 코드의 가치를 극대화하기 위해서는, 작성된 테스트를 자동으로 돌려주는 환경(CI, Continuous Integration)을 구축하는 것이 중요하다. 대표적인 CI 툴로는 GitHub Actions, GitLab CI/CD, Jenkins 등이 있으며, 대체로 Pull Request가 올라오면 빌드와 테스트를 실행하고 결과를 알려준다.
특히 로봇 소프트웨어는 하드웨어 시뮬레이션 환경이 필요할 때가 많다. 이를 위해 Docker를 이용하거나 시뮬레이션 툴(ROS 시뮬레이터 등)과 연동해 자동 테스트를 구성한다. 이렇게 하면 실제 로봇 없이도 비교적 빠르게 코드가 의도대로 동작하는지 검증할 수 있다.
TIM Robotics의 CI 프로세스에서는 일반적으로 새로운 PR이 생성될 때마다 다음의 항목들을 CI 과정을 통해 자동으로 테스트 한다. (위 그림은 PR 생성 시 모든 테스트가 통과한 모습)
- Linter: 각 언어 (c++, python, shell script, xml) 에 대해 정해진 포멧을 지키고 있는지 확인.
- Code compile 및 테스트 : 정상적으로 컴파일이 수행되는지 확인하고, 테스트 코드가 모두 성공하는지 확인. 로봇 내부에서 동작하는 코드의 경우에는 X86 시스템 뿐만 아니라 ARM Architecture CI 서버에서도 함께 테스트 진행.
- 테스트 커버리지 확인 : 유닛 테스트 수행 완료 후 테스트 코드의 커버리지를 확인하고 수정된 파일에 대한 커버리지를 리포트 해준다. 커버리지가 특정 값 (일반적으로 80%)를 넘지 못하는 경우 CI가 실패하여 Merge를 수행할 수 없다.
- File consistency 체크 : 로봇의 경우 여러개의 Repository를 관리하는 경우가 많기 때문에 동일한 역할을 하는 파일들이 각 Repository에 분산되어 있는 경우가 많다. 각 Repository에 있는 파일들이 master file과 동일하게 유지되고 있는지 확인
사람은 누구나 실수를 할 수 있기 때문에 최대한의 자동화를 통해 이러한 휴먼 에러를 최소화 해야 한다.
7. 테스트 커버리지 체크
테스트 코드가 있다고 해도, 실제로 얼마나 많은 부분을 테스트하는지는 또 다른 문제다. 이때 도움이 되는 지표가 테스트 커버리지다. 테스트 커버리지 분석 툴(gcov, lcov, cobertura 등)을 사용하면 특정 파일 혹은 함수가 테스트에서 얼마나 커버되었는지 확인할 수 있다. 일반적으로 다음과 같은 항목을 살펴본다.
- 라인 커버리지(Line Coverage): 전체 코드 라인 중 테스트를 통해 실행된 라인의 비율
- 함수 커버리지(Function Coverage): 전체 함수 중 테스트를 통해 실행된 함수의 비율
- 분기 커버리지(Branch Coverage): 조건문(if/else 등)의 각 분기가 실제 테스트 과정에서 모두 실행되었는지를 측정한 비율
테스트 커버리지가 높다고 해서 모든 오류를 자동으로 검출할 수 있는 것은 아니다. 그러나 커버리지를 확인하면 테스트되지 않은 부분을 명확히 파악할 수 있어, 테스트의 사각지대를 줄이는 데 큰 도움이 된다. 테스트 커버리지를 확인하는 주된 목적은 각 유닛 테스트가 함수 내부의 로직을 다양하게 검증했는지를 평가하는 데 있다. 단 하나의 테스트 케이스만 존재하더라도 해당 함수가 실행되었다면 커버리지 리포트에는 포함되므로, 커버리지 수치만으로 테스트 코드의 질적 수준(즉, 얼마나 다양한 케이스를 검증했는지)을 평가하는 것은 어렵다. 따라서 유닛 테스트의 품질은 테스트를 작성하는 개발자의 역량에 크게 의존하며, 이를 위해 개발 문화가 중요한 역할을 한다. 테스트 코드를 작성할 때 중요한 점은 유닛 테스트와 통합 테스트를 분리하는 것이다. 통합 테스트가 커버리지 체크 프로세스에 포함되면 어떤 문제가 발생할까? 통합 테스트는 여러 함수가 연결된 상태에서 실행되므로, 특정 함수를 테스트하는 과정에서 해당 함수가 호출하는 모든 함수들까지 커버리지에 포함된다. 이로 인해 유닛 테스트에서 개별적으로 검증되지 않은 함수가 무엇인지 명확히 파악하기 어려워진다. 따라서 통합 테스트는 커버리지 확인 프로세스에서 제외하는 것이 바람직하다고 생각한다.

TIM Robotics에서는 테스트 작성 시 유닛 테스트와 통합 테스트를 명확히 분리하며, CI를 구성할 때 유닛 테스트의 실행 결과만 커버리지 리포트에 포함되도록 설정하였다. 이를 통해 생성된 커버리지 리포트는 PR 생성자가 확인할 수 있도록 자동으로 업로드되며, 커버리지가 사전에 설정한 기준에 미달할 경우 CI가 실패하도록 구성되어 있다. 또한, 상세 리포트를 다운로드하여 코드 라인별로 커버리지 미충족 부분을 확인할 수 있도록 하여, 어떤 코드에 대한 유닛 테스트가 부족한지 쉽게 파악할 수 있는 시스템을 구축하였다.


마치며
테스트 코드 작성은 코드 품질을 개선하는 도구를 넘어, 지속 가능한 개발 문화를 위한 필수 요소라고 할 수 있다. 특히 로봇 소프트웨어처럼 하드웨어와 맞물려 안전성과 신뢰도가 중요한 분야에서는 더욱 강조될 수밖에 없다.
처음에는 테스트 코드를 작성하는 데 드는 시간이 부담스러울 수 있다. 그러나 테스트가 존재함으로써 얻게 되는 조기 오류 발견, 협업 효율성 향상, 기술 부채 감소 등은 장기적인 관점에서 절대적인 가치를 지닌다. 또한 코드 리뷰, 스타일 가이드, CI/CD 파이프라인과 결합하면 그 효과가 배가된다.
결국 테스트 코드는 “필요하면 추가로 작성하는 옵션 사항”이 아니라, 프로젝트의 토대를 견고하게 만드는 핵심적인 도구다. 로봇 소프트웨어 개발에서도 테스트 코드 작성 문화를 정착시키고, 이를 자동화와 결합해 장기적으로 안정된 개발 환경을 구축하기를 권장한다. 테스트 코드가 제공하는 안정성과 예측 가능성은, 하드웨어와 깊이 연동되는 로봇 소프트웨어 개발에서 더욱 빛을 발하게 된다.
로봇 소프트웨어 개발 문화를 어떻게 만들어야 할까?
로봇 소프트웨어 개발 문화

로봇 소프트웨어 개발 문화를 어떻게 만들어야 할까?
로봇 소프트웨어 개발은 단순한 소프트웨어 개발과는 차이가 있다. 로봇은 물리적인 환경에서 동작하며, 하드웨어와의 긴밀한 연계가 필요하기 때문에 코드의 신뢰성과 유지보수가 특히 중요하다. 하지만 아무리 뛰어난 기술을 보유하고 있어도, 좋은 개발 문화가 정착되지 않으면 장기적으로 효율적인 개발이 어려워지며, 어느순간 부터는 기술 부채가 쌓여 되돌릴 수 없는 상태에 이르게 된다. 또한 개발 처음부터 재대로된 개발 문화와 시스템을 구축하지 않고 중간에 레거시 시스템을 고친다는 것은 매우 머리아픈 일이다. 이번 포스팅에서는 두번째 스타트업에서 개발문화를 구축하면서 생각하고 있는 로봇 소프트웨어 개발 문화의 중요성과 이를 구축하는 방법에 대해 이야기해 보겠다.
개발 문화의 중요성
좋은 개발 문화는 단순히 “잘 짜인 코드”를 만드는 것 이상의 가치를 제공한다. 조직 내 개발 문화가 건강하면 다음과 같은 장점이 있다.
- 협업이 원활해진다: 코드 스타일과 리뷰 방식이 일관되면, 팀원들이 더 쉽게 서로의 코드를 이해할 수 있다.
- 버그와 기술 부채를 줄일 수 있다: 체계적인 코드 리뷰와 테스트 문화가 자리 잡으면, 문제를 조기에 발견하고 해결할 수 있다.
- 신규 개발자 온보딩이 쉬워진다: 문서화와 코드 컨벤션이 정립되어 있다면, 새로운 팀원이 빠르게 적응할 수 있다.
- 개발 속도가 꾸준히 유지된다: 단기적인 속도보다 장기적인 생산성을 고려한 개발 문화가 정착되면, 프로젝트의 유지보수가 쉬워지고 확장성도 높아진다.
로봇 소프트웨어 개발은 하드웨어와 직접 연결되므로, 잘못된 코드 하나가 물리적인 사고를 초래할 수 있다. 따라서 체계적인 개발 문화가 더욱 필수적이다. 아쉬운 부분은 한국의 많은 로봇 회사들이 이런 개발문화에 대한 중요성을 모르고 있는 경우가 매우 많다. 일반적인 B2C 소프트웨어를 개발하는 풀스택의 경우 컴퓨터공학을 기반으로 개발 문화가 형성되어 이런 개발문화의 중요성, 에자일 개발 등 개발 문화에 대해 신경을 쓰는 경우가 많다. 하지만 로봇 개발 회사의 경우 (특히 한국 로봇회사의 경우) 학교 출신의 로봇 관련 연구를 했었던 석사/박사 출신이 개발 문화를 만드는 경우가 많다 보니 이런 개발 문화에 대한 중요성, 그리고 필요성에 대해 인지하지 못하는 경우가 많은 것 같다. 심지어 형상관리 툴을 사용하지만 모든 개발자가 master 브랜치에서 코드 작업을 하고 바로 master로 commit을 넣는 경우도 심심치 않게 보았다. 이런 개발 문화에서는 코드의 퀄리티가 유지될 수 없을 뿐만 아니라 코드의 버전 관리도 불가능하다. 따라서 무엇보다도 로봇 소프트웨어 개발에서 개발문화는 가장 중요한 요소이다.

코드 리뷰의 중요성
코드 리뷰는 개발자의 실수를 줄이고 코드 품질을 향상시키는 중요한 과정이다. 단순히 “버그를 잡는 과정”이 아니라, 팀이 공유하는 개발 원칙과 철학을 유지하는 역할도 한다.
코드 리뷰가 필요한 이유
- 버그 예방: 코드 리뷰를 통해 동료 개발자가 실수를 발견하고 수정할 수 있다.
- 지식 공유: 리뷰 과정에서 코드에 대한 이해도를 높이고, 팀 전체의 개발 역량을 향상시킬 수 있다.
- 일관성 유지: 코드 스타일과 아키텍처가 팀의 기준에 맞게 유지될 수 있다.
- 기술 부채 감소: 불필요한 복잡성이나 잘못된 설계를 초기에 바로잡을 수 있다.
로봇 소프트웨어의 경우, 코드 한 줄이 실제 로봇의 동작에 영향을 미칠 수 있기 때문에 코드 리뷰는 더욱 철저히 진행해야 한다. 단순히 “문제가 없어 보인다”는 식의 리뷰가 아니라, 코드가 실제 환경에서 어떻게 동작할지 고려하며 리뷰해야 한다. 또한 코드에 버그가 있는 상태로 Master로 머지가 된다면 그에 대한 책임 또한 리뷰어에게도 있다는 사실을 항상 인지해야 한다. 리뷰 과정은 단순히 다른 동료의 코드를 훑어보는 과정이 아닌 개발의 일 부분임을 잊어서는 안된다.
효율적인 코드 리뷰 프로세스
효율적인 코드 리뷰 프로세스를 구축하기 위해서는 몇 가지 원칙을 따라야 한다.
1. 리뷰를 위한 명확한 기준 설정
코드 리뷰를 시작하기 전에 팀 내에서 명확한 기준을 세워야 한다. 예를 들어, 다음과 같은 항목을 정할 수 있다.
- 코드 스타일 가이드라인 (ex: Google C++ Style Guide)
- PR(Pull Request) 크기 제한 (너무 큰 PR은 리뷰하기 어렵다)
- 테스트 코드 포함 여부
이러한 기준이 없다면 리뷰어마다 다르게 판단할 가능성이 높아지고, 리뷰 과정이 비효율적으로 변할 수 있다.
2. 코드 스타일 가이드 설정
개발자마다 함수명, 변수명, namespace 이름을 만드는 규칙, 포멧이 다르다면 코드는 금방 엉망이 될 것이며, 리뷰를 어렵게 만드는 요소가 된다. 공통으로 사용할 코드 스타일 가이드를 설정하는 것은 개발 문화의 가장 기본적인 요소이다. TIM Robotics의 경우에는 모든 언어가 Google Style Guide 따르고 있다. (링크) 일반적으로 Style Guide에는 코드 작성을 위한 함수명, 변수명, namespace명 등 모든 요소들에 대한 규칙을 포함한다. 예를 들어 Google Style Guide 기준으로 Class의 맴버 변수는 _
라는 suffix 를 사용하며, const variable인 경우에는 k
의 prefix를 사용한다. 모든 개발자가 이렇게 동일한 규칙을 사용함으로써 코드의 Readability가 높아지고, 리뷰하는데 시간이 감소하게 된다. 추가적으로 TIM Robotics는 좌표계의 변환 관계를 표현하는 방법, Time을 포함한 변수 표현 방법 등 다양한 스타일 가이드를 추가적으로 만들어 공유하고 있다. 내부 스타일 가이드는 개발을 하면서 부족한 부분을 발견하면 함께 논의하여 만들어 가는 과정이 매우 중요하며, 이 과정에서는 모든 개발자가 참여해야 한다.
3. Test 코드 작성하기
테스트 코드 작성은 하나의 추가 업무가 아닌 당연한 개발의 일부이다. 테스트 코드가 없는 코드는 개발 단계에서 검증 단계를 거치지 않았으며, 추가 수정이 있을때마다 버그가 발생할 수 있는 코드이다. 따라서 개발되는 모든 코드는 테스트 코드가 포함되어야 하며 PR에 항상 함꼐 포함되어 있어야 한다. CI 프로세스에서는 해당 PR에 테스트 코드가 포함되었는지, 커버리지가 일정 이상 인지 확인하여 Merge 가능 여부를 자동으로 판단하도록 시스템을 구성해야 한다.
4. PR(Pull Request) 크기 조절하기

PR은 Pull Request의 약자로 수정된 코드를 다른 사람에게 리뷰받는 프로세스를 의미한다. PR을 작성할 때 리뷰어에게 도움을 주기 위해 어떤 내용에 대한 수정사항인지 자세히 PR에 정리해서 PR을 생성하는 것이 기본 프로세스이다. PR을 작성 시 PR이 너무 크면 리뷰어가 모든 내용을 꼼꼼히 살펴보기가 어렵다. 10줄의 코드를 리뷰 요청하면 10개의 comment가 달리는데, 500줄의 코드 리뷰를 요청하면 한개의 리뷰도 돌아오지 않는다 라는 농담이 있다. 하나의 브랜치에서 여러 작업을 동시에 수행하여 수정사항이 너무 많으면 리뷰어는 수정사항에 대해서 이해하는데 시간이 오래걸려 포기해버리고 LGTM (Looks good to me) 리뷰를 던지는 경우가 발생한다. 따라서 일반적으로 한 번의 PR에서 너무 많은 기능을 추가하기보다는, 작은 단위로 쪼개어 올리는 것이 좋다. 작은 PR은 리뷰 시간이 단축되고, 변경 사항을 명확히 이해하는 데 도움이 된다.
5. 자동화 도구 활용하기
개발 프로세스에서 자동화 툴을 사용하여 자동화 할 수 있는 부분은 최대한 적용하는 것이 효과적이다.
- 코드 스타일 검사: Clang-Format, Prettier, Clang-tidy 등을 활용하여 스타일을 자동으로 맞춘다.
- 정적 분석 도구: SonarQube, cppcheck 등을 이용해 잠재적인 버그를 찾는다.
- CI/CD 파이프라인: 코드 리뷰 전에 자동으로 빌드, 테스트를 실행해 코드의 안정성을 확인한다.
개발자들끼리 특정 스타일 가이드를 따르기로 약속했다고 하더라도 개발과정에서 누구라도 실수를 할 수 있다. 이러한 실수들은 자동화 툴을 사용해서 자동으로 감지되도록 시스템을 구성해야 한다. TIM Robotics는 clang-format과 clang-tidy를 함께 사용하고 있다. clang-format은 코드 전반적인 format에 대하여 자동으로 감지하고 수정해준다. clang-tidy는 코드 스타일 검사와 정적 분석이 모두 포함되 있으며, 특히 함수, 변수명들이 정의한 스타일과 다르게 작성된 부분을 자동 검출하는데 유용하며, 잠재적인 버그들도 함께 검출할 수 있다. 이러한 툴들은 개발 과정에서 개발자들이 활용하는 것 뿐만 아니라 CI 과정에서 다시 한번 수정 사항에 대하여 테스트를 하고, 문제가 발견했을 때 오류를 발생시켜 수정된 코드가 Master 브랜치로 Merge되는 것을 방지한다. 이런 자동화 도구를 적극적으로 활용함으로써 리뷰어는 코드 스타일이나 간단한 실수를 지적 하는 대신, 전체적인 코드의 구성, 아키텍처, 그리고 로직에 집중하여 리뷰를 할 수 있다.
6. 건설적인 피드백 제공하기
코드 리뷰는 팀원 간의 협업 과정이므로, 피드백을 줄 때는 긍정적인 방식으로 접근하는 것이 중요하다.
- “이 부분은 잘 구현하셨네요! 하지만 여기서는 이런 방식이 더 좋을 것 같습니다.”
- “이 로직이 잘 동작하긴 하지만, 성능 최적화를 위해 이런 접근도 고려해볼 수 있을 것 같아요.”
단순한 비판이 아니라, 대안을 제시하는 피드백이 더 효과적이다. 때로는 리뷰만으로는 의도한 내용을 정확히 전달하기 어려울 때 코드를 수정하여 제안하는 것도 방법이다.
7. 리뷰 시간을 정기적으로 확보하기
코드 리뷰는 “남는 시간에 하는 것”이 아니라, 개발 프로세스의 핵심 단계다. 따라서 리뷰를 위한 시간을 정기적으로 확보하는 것이 중요하다. 예를 들어, 매일 오전 10~11시는 코드 리뷰 시간으로 지정하는 등의 방식이 있다. 이런 방식이 재대로 동작하기 위해서는 PR을 작은 단위로 자주 작성하여 리뷰 요청을 해야 한다.
신규 개발자 온보딩 및 문서화
새로운 개발자가 팀에 합류했을 때 빠르게 적응할 수 있도록 돕는 것도 좋은 개발 문화의 일부다. 이를 위해 다음과 같은 요소를 준비하는 것이 좋다.
1. 개발 환경 설정 가이드 제공
- 개발 환경을 빠르게 구축할 수 있도록, Docker 같은 자동화된 환경 설정 방법을 제공한다.
- “개발 환경 설정 가이드” 문서를 준비해 놓는다.
2. 코드베이스 문서화
- 프로젝트의 전체 구조를 설명하는 아키텍처 다이어그램을 제공한다.
- 주요 모듈과 라이브러리의 역할을 정리한 문서를 만든다.
3. 온보딩 미션 제공
- 신규 개발자가 코드베이스를 이해할 수 있도록, 작은 기능을 직접 추가해보는 미션을 제공한다.
- 테스트 코드 작성이나 작은 버그 수정부터 시작하도록 유도한다.
결론
좋은 개발 문화를 만드는 것은 하루아침에 이루어지는 일이 아니다. 하지만 코드 리뷰 프로세스를 정립하고, 자동화 도구를 활용하며, 명확한 문서화와 온보딩 시스템을 갖춘다면, 지속 가능한 로봇 소프트웨어 개발 환경을 만들 수 있다.
개발 문화는 단순한 규칙이 아니라, 팀 전체가 함께 만들어가는 과정이다. 한국의 로봇 산업이 더 고도화 되기 위해서는 모든 로봇 회사들이 이러한 개발 문화를 갖춰야 한다고 생각한다.
예문을 포함한 Ceres tutorial PPT & github code
Ceres Solver
Ceres solver는 비선형 최적화 문제를 풀기위한 오픈소스 기반의 c++ 라이브러리이다. 우리가 풀어야 하는 대부분의 문제들은 비선형 문제이다. Ceres solver는 다른 최적화 라이브러리에 비해 확장성이 좋으며, SLAM을 위한 다양한 예제도 제공해주고 있다. SLAM을 연구 및 개발하는 사람이라면 기본적으로 Ceres Solver 는 다룰 수 있어야 한다.
Ceres Solver Tutorial
해당 발표 자료 및 tutorial code는 2023년 인하대학생들에게 제공하기 위해 작성한 자료들이다.
Ceres Tutorial 발표자료
Ceres Tutorial Code
혼자서도 스타트업 - 조현영 대표

2022년 중반부터 올라가기 시작한 금리에 따라 전반적인 시장이 얼어붙고, 그에 따라 투자 시장도 급격히 얼어붙음에 따라 많은 스타트업들이 어려워지고 있다. 내가 몸담고 있는 스타트업도 100억이 넘는 투자금을 받았지만 현재 많은 어려움을 겪고 있다. 작년까지만 해도 투자금은 회사의 비전을 제시할 수 있다면 언제든지 받아올수 있다고 생각할 만큼 현금이 넘쳐나는 시기였다. 하지만 지금과 같은 시기가 되니 투자자들은 더욱 보수적으로 스타트업을 평가하고 그에 따라 회사의 가치도 급격히 떨어지고 있다. 이런 시기가 올 것이라고 조금이라도 미리 예측하고 보수적으로 투자금을 사용했더라면 지금과 같은 어려움을 겪지 않지 않았을까 하는 생각을 계속 하는 시기이다. 이런 시기에 우연히 유튜브를 통해 하이퍼로컬의 조현영 대표님의 인터뷰를 보고 이 책을 읽게 되었다.
첫 서비스는 망한다
조현영 대표님이 스타트업을 시작하기로 결심을 하고 카카오를 떠나면서 들었던 이야기가 “첫 서비스는 망한다” 였다고 한다. 시간이 지나고 나서 그 말이 현실이 되었음을 알게 되었다고 하신다. 그만큼 스타트업에서는 서비스를 만들어봤던 경험이 중요하고, 그 경험이 쌓이면서 더욱 경쟁력 있는 제품을 만들수 있다는 뜻이기도 한것 같다. 그리고 스타트업은 언제든지 방향이 잘못되었다고 판단이 되면 Pivot을 할 준비가되어 있어야 한다. 언제든지 열린 생각을 가지고 시장의 흐름을 읽고, 트랜드를 계속 파악해 나가야 한다.
공동 창업자에 대하여
공동창업자와 열정의 크기가 다르고 생각하는 것이 다르다면 공동창업을 하지 않는 것이 더 좋다. 특히 본 직업을 갖고 있으면서 주말 혹은 업무시간 이후에 스타트업에 도전하려는 생각을 갖는 사람과의 공동 창업은 추천하지 않는다.
회사의 직원에 대하여
현재 조현영 대표님은 “그루밍족” 과 “해주세요” 라는 두개의 서비스를 운영하고 계시며, 정직원 없이 혼자 회사를 운영하고 계신다. 기술 조직을 이끌어온 나로써 다시 생각해 보아도 지금의 조직을 혼자 이끌수는 없다고 생각한다. 왜냐하면 하드웨어 개발 및 소프트웨어 개발은 알아야 되는 분야가 너무 세분화 되어 있고 내가 그 지식을 다 갖추지 못했기 때문에다. 하지만 반대로 생각해보면 조현영 대표님도 개발자가 아니다. 개발자가 아니지만 서비스 기획부터 개발, 홍보, CS까지 혼자 계획하고 외주 개발자를 통해 어플을 만들어 지금까지 성장시켜왔다는것은 정말 쉬운일이 아닐 것이다. 물론 하드웨어 개발과 어플 개발의 기술적 난이도는 다를 것이다. 그럼에도 많은 스타트업들은 더 빠른 성장을 위해 값비싼 인건비에 능력있는 개발자들을 모시기위해 노력하고 있고, 그러한 인건비에 의해 적자를 벗어나지 못하고 있는 스타트업들이 많다.
나 또한 회사가 시리즈 A 투자를 받고 나서 어느정도 자금의 여유가 생김에 따라서 내가 그동안 재대로 커버하지 못했던 부분을 매우기 위해 채용에 속도를 냈었었다. 그 당시에는 나름대로 채용에 대한 시스템도 만들어 가면서 정말 좋은 분들을 모시기 위해 노력했었고 채용 자체는 실패하지 않았다고 생각한다. 하지만 지금 돌이켜 생각해보면 지금의 제품을 만들기 위해 지금까지 채용했던 모든 인원들이 반드시 필요하지는 않았을 것 같다. 그 당시에는 CTO로써 나의 업무가 너무 많아서 능력있는 직원을 빨리 뽑아서 나의 역할을 분배해주고 싶었던 마음이 컸었다. 그러다보니 점점 직원은 많아지고, 조금씩 잉여인력이 늘어났던것 같다.
조현영 대표님은 대표가 모든 부분에 대해서 챙기고 이해를 하고 있어야만 회사 운영이 재대로 이뤄질수 있고, 직원이 변경되었을 때도 그 업무를 커버할 수 있다고 하신다. 물론 50명이 넘어가는 큰 회사에서도 동일하게 적용되기는 어려운 방법일 수 있다. 하지만 일반적인 스타트업은 수익이 나기까지 시간이 걸리고, 그 수익도 크지 않기 때문에 최대한 인건비를 줄이면서 성장해 나가는 것이 가장 좋은 방법임에는 공감한다.
지금까지 제품 개발을 하면서 한 두번의 외주를 진행했었고 그다지 성공적이지 못했던 프로젝트였다. 그 당시에는 내가 전혀 알지 못하거나 부족하게 아는 부분에 대해 개발을 해야 했고 (Linux Kernel, 회로 개발), 나름대로 가이드는 작성하였지만 디테일이 부족했던 것 같다. 내가 그 분야에 대해 외주 개발자만큼 지식을 갖고 있었다면 더욱 성공적은 프로젝트였을 것 같다. 조현영 대표님 말처럼 대표가 모든 일을 할 수 는 없기에 프리랜서를 최대한 활용해야 한다. 하지만 프리랜서를 최대한 활용하기 위해서는 적어도 대표 스스로가 그 부분에 대한 지식을 충분히 갖춰야 한다.
투자에 대하여
지금까지의 나 또한 스타트업을 하게 되면 투자가 반드시 필요하다고 생각을 했다. 투자를 해야만 회사의 벨류가 측정이 되고, 나의 지분의 가치가 올라간다고 생각했다. 물론 일부는 맞는말이다. 하지만 반드시 투자가 회사에 긍정적인 영향을 미치는 것만은 아니다. 우리 회사만 보더라도 한명의 미국 투자자에 의해서 회사의 CEO가 바뀌고 회사의 문화가 완전히 망가졌다. 많은 투자자들이 회사의 성장을 바라기 때문에 물심양면으로 회사를 성장시키기 위해 함께 노력해 나가고 있고, 다양한 도움을 주고 있다. 히지만 그 투자자들도 결국에는 회사의 성장에 의해 이익을 위해 움직이는 사람이고, 누구보다도 똑똑한 사람이다.
조현영 대표님의 말씀처럼 투자를 받는것은 필수가 아니다. 회사의 제품을 개발하는 초기에 대표는 고객을 바라보고, 고객의 문제를 해결하기 위해 집중을 해야한다. 하지만 대부분의 대표들은 투자자들을 만나서 어떻게 투자자들을 설득시킬지를 고민한다. 어떻게 현재 개발하고 있는 제품이 미래지향적으로 보일지, 어떻게 돈이 되는 스토리를 만들지를 고민한다. 이것 또한 스타트업의 대표로써 잘 해야만 하는 일이지만, 회사의 제품이 어느정도 성숙해 지기 까지는 조금 더 고객의 Pain Point를 해결하는 것에 조금 더 집중하는 것이 맞다고 생각된다. 어느정도 회사의 성장 속도에 가속화를 내기 위해서는 당연히 어느정도의 투자는 필수적이다. 하지만 투자를 받는 것이 스타트업을 운영하는 첫번째 목표가 되어서는 안된다.
유의미한 데이터에 집중하라
현재 내가 만들고 있는 서비스가 의미있는 결과를 만들어 내고 있는지를 보기 위해서는 주기적으로 유의미한 데이터에 집중을 해야 한다. 어플기반의 서비스라면 DAU (Daily Active User), MAU (Monthly Active User)와 같은 지표가 될 것이다. 두개의 지표중에서는 DAU가 조금 더 의미있는 지표이다. 왜냐하면 MAU는 주기적인 광고 혹은 이벤트를 통해 채울수 있는 지표이기에 매일 접속하는 유저의 수를 의미하는 DAU가 더욱 의미있는 지표이다.
내가 지금 개발하고 있는 제품은 B2B 제품이다. 제품을 구매하는 사람은 한 회사의 관리자 혹은 Inovation (혁신) 팀이고, 실제 사용자는 물류센터내의 작업자이다. 그러다 보니 제품의 실제 구매자와 사용자가 제품을 바라보는 관점이 다르다. 지금까지 B2B 제품이기에 실제 사용자에 대한 지표를 중요하게 분석해볼 생각을 많이 해보지 못했다. 하지만 해당 사용자가 어떤 기능에 만족해 하는지, 어떤 부분에 불편해 하는지 등 이러한 피드백에 계속 귀를 귀울여야 하고, 이러한 데이터를 자동으루 수집할 수 있는 시스템을 구축하여 고객의 데이터를 만들어 나가야 할 것 같다.
고객의 목소리 (고객의 응대는 대표가 하라)
CS (Customer Service)는 가장 감정 노동이 되는 업무이기에 회사를 운영하면서 가장 하기 싫은 부분이고, 직원에가 가장 먼저 넘기는 부분이 아닐까 한다. 나 또한 현재 제품을 개발하면서 고객을 직접 만나는 경우는 많지 않다. 주로 고객의 목소리는 필드 엔지니어, 혹은 세일즈 팀을 통해 듣고, 그 고객의 목소리를 다음 제품 기획에 반영하고 있다. 하지만 그렇다 보니 중간 메세지 전달역할을 하는 필드엔지니어나 세일즈팀의 제품 이해도에 따라 고객의 목소리가 외곡되어 전달되는 경우가 심심치 않게 있어왔다. 조현영 대표님은 대표가 직접 고객을 응대하고 고객의 니즈를 계속 제품에 반영해 나가야 한다고 강조하고 있다. 이러한 방법이 가장 직접적으로 고객의 피드백을 받아 제품 기획에 반영하고, 개발까지 이어질 수 있는 가장 빠른 방법이기도 하기 때문이다.
물론 이 방법 또한 큰 조직에서 유지되기는 힘든 방법일수는 있겠지만, 대표가 고객의 목소리에 계속 집중해야 한다는 메세지는 꼭 기억해야 할 것 같다.
총평
이 책은 사업을 할 때 계속해서 마음속에 담아둬야 하는 포인트들을 잘 담고 있는 책인것 같다. 새로운 사업을 시작하게 된다면 이 책은 다시 돌아와서 읽어볼 예정이다.
Check stdout of running process
top
로 확인 가능한 process의 terminal output를 확인하기 위한 명령어
# std out
cat /proc/{pid of process}/fd/1
# std err
cat /proc/{pid of process}/fd/2
Pagination