레거시 코드베이스를 이해하는 방법에 대한 조언은 대부분 코드를 실행할 수 있다는 것을 전제로 합니다. 중단점을 걸고, 한 단계씩 따라가며, 동작을 지켜보라는 식입니다. 하지만 장비 소프트웨어에서는 대개 그럴 수 없습니다. 장비는 공장 현장에 있고, 하드웨어는 늘 가동 중이기 때문입니다. 그래서 접근 방식이 뒤집힙니다. 코드를 읽는 것이 주된 수단이 되고, 디버깅은 심볼 해석과 참조 찾기, 계층 탐색을 중심으로 이루어집니다.
장비는 다른 곳에 있다
제조와 생산 현장을 위한 개발에서는, 코드는 내 PC에 있지만 그 코드가 제어하는 장비는 다른 나라의 공장에 있습니다. 설상가상으로, 지금 맡은 모듈을 처음 작성한 엔지니어는 2년 전에 떠났습니다. 남은 것은 맥락을 알려주는 주석 하나 없는 코드와, 기댈 만한 문서도 없이 “fix” 같은 말만 적혀 있는 오래된 커밋 메시지뿐입니다.
이런 일은 개발자들이 자리를 옮기거나, 최악의 경우 은퇴하면서 꾸준히 반복됩니다. 그리고 문제는 곧바로 드러나지 않습니다. 잘못된 변경은 실패한 단위 테스트로 나타나지 않습니다. 공급 라인 한가운데에서 드러납니다. 폐기된 로트로, 또는 생산 라인에서 예기치 않게 멈춰 선 장비로 나타납니다.
낯선 코드베이스를 이해하는 방법을 찾아보면 언제나 같은 방법이 나옵니다. 빌드하고, 실행하고, 중단점을 걸어라. 대략적인 동작 방식이 파악될 때까지 한 단계씩 따라가라. 프로그램이 눈앞에서 실행되는 환경이라면 훌륭한 조언입니다.
다만 그 전제 조건이 없습니다. 웨이퍼 핸들러를 책상 위에 올려둘 수도 없고, 고객사에서 가동 중인 장비에 디버거를 붙일 수도 없습니다. 코드가 기대하는 카메라와 그 영상 데이터도 내 자리에는 없습니다. SECS/GEM 계층이 연결되는 팹 호스트는 애초에 접근 권한을 받을 수 없는 시스템입니다. 방법 자체는 타당하지만, 한 단계를 쓸 수 없다는 이유로 과정 전체가 무너집니다. 이런 코드베이스가 어떻게 지금의 모습이 되었는지는 반도체 장비 속 C++ 스택에서 따로 다뤘습니다.
가진 것과, 각각이 멈추는 지점
부분적으로 대신할 수 있는 네 가지와, 그 한계입니다.
| 가진 것 | 무엇을 커버하는가 | 어디서 멈추는가 |
|---|---|---|
| 시뮬레이터 / 가상 하드웨어 | 시퀀싱 로직, 상태 전이, 프로토콜 핸드셰이크 | 타이밍, 센서 노이즈, 실제 장비를 쓸 때만 나타나는 실제 장애 |
| HIL(하드웨어 인 더 루프) 장비 | 시간을 확보할 수 있다면 실제에 가장 근접 | 고객사 장비와 동일한 구성인 경우가 드묾 |
| 현장에서 받은 로그 리플레이 | 쫓고 있는 실제 장애를, 실제 계측 데이터와 함께 | 사후 확인. 무슨 일이 있었는지는 보이지만, 코드가 무엇을 판단했는지는 보이지 않음 |
| 해당 모듈을 아는 동료 | 존재한다면 가장 빠른 길 | 대개 없음. 없기 때문에 다른 방법을 찾고 있는 것 |
좋은 시뮬레이터는 외부에서 짐작하는 것보다 훨씬 많은 것을 커버하지만, 그중 어느 것도 실제 장비를 대신하지는 못합니다.
작업 흐름
각자의 환경에 맞게 다듬어 쓸 수 있는 일반적인 접근법입니다. 어떤 IDE나 개발 환경에서도 적용할 수 있습니다.
- 트리의 최상단이 아니라, 지금 맡은 작업과 관련된 진입점에서 시작합니다. 장비 애플리케이션에는 위에서부터 읽어 내려갈 만한 유용한 main이 없습니다. 질문받은 대상을 고르세요. 이상 동작을 보이는 레시피 단계, 알람이 발생하는 지점, 잘못된 응답을 받는 SECS 메시지 같은 것들입니다. 큰 코드베이스를 처음부터 읽는 것은 대개 시간이 너무 많이 들어서 쓸 만한 이해로 이어지지 않습니다.
- 파일이 아니라 심볼을 따라갑니다. 20년 된 코드베이스의 폴더 구조는 팀의 역사와 병합 사고를 기록할 뿐, 설계나 아키텍처를 설명하지 않습니다. 필요한 것이 호출하는 쪽에서 네 폴더쯤 떨어져 있을 수도 있습니다. 트리를 훑는 대신 정의와 참조로 이동하세요.
- 무엇이든 바꾸기 전에 모든 참조를 찾습니다. 반드시 해야 하는 안전 조치입니다. 함수든 멤버든 상수든 건드리기 전에, 그것과 관련된 모든 것의 완전한 목록을 확보하세요. (열다섯 개 호출 지점 중 열두 개만 찾아주는 텍스트 검색으로는 부족합니다.) 장비 코드에서 지우고 싶어지는 그 코드는, 대개 타이밍 문제를 피해 가는 처리이거나 아무도 문서로 남기지 않은 장애에 대한 수정입니다. 참조 목록을 써서 이런 것들을 놓치지 마세요.
- 호출 계층으로 경계를 찾습니다. 자신의 모듈을 벗어날 때까지 위로 거슬러 올라가세요. 내 코드가 끝나고 장비가 시작되는 지점을 찾는 것입니다. 이것이 변경의 영향 범위를 알려줍니다. 범위가 좁으면 빠르게 진행할 수 있고, 그렇지 않더라도 최소한 커밋하기 전에 그 사실을 알게 됩니다.
- 서드파티 SDK의 경계를 파악합니다. 비전, 모션, 호스트 통신은 대개 벤더 라이브러리입니다. 내 코드가 어디서 끝나고 HALCON이나 VisionPro 같은 벤더 라이브러리 또는 모션 컨트롤러의 API가 어디서 시작되는지 알면, 어떤 동작을 바꿀 수 있고 어떤 동작은 우회할 수밖에 없는지 판단할 수 있습니다.
- 조건부 컴파일 변형을 읽습니다. 장비별·고객사별·지역별 구성이 있다는 것은, 화면에 보이는 코드가 지금 디버깅 중인 장비에 실제로 들어가는 코드가 아닐 수도 있다는 뜻입니다. 읽은 내용을 신뢰하기 전에 그 장비에 어떤 변형이 빌드되는지 확인하세요. 애초에 실행되지도 않던 코드를 디버깅하며 몇 시간을 날리는 일을 막아줍니다.
이 접근법의 범용 버전은 대규모 또는 레거시 C++ 코드베이스를 탐색하는 방법에 정리되어 있습니다.
이 코드베이스가 도구와 싸우는 이유
2번, 3번, 4번 단계는 IDE가 정확하게 답해줄 수 있다는 것을 전제로 합니다. 그리고 이 전제는 여기서 혹독하게 시험받습니다.
첫 번째 이유는 규모입니다. 전체 그림을 구성하는 데 실제 연산 비용이 듭니다. 여기에 매크로와 조건부 컴파일이 겹칩니다. 여러 겹으로 쌓여 있고 종종 생성된 코드이며, 단순히 상수를 바꾸는 정도가 아니라 구조 자체를 만들어냅니다. 그다음은 벤더 SDK 헤더입니다. 크고, 깊게 중첩되어 있으며, 우리가 통제할 수 없습니다.
네 번째가 가장 중요합니다. 구성이 이렇게 많다 보니 그중 일부는 특정 개발자의 환경에서 온전히 빌드되지 않는 경우가 잦습니다. 벤더 SDK가 없거나, 보유하지 않은 하드웨어를 대상으로 하는 구성이거나, 빌드 서버에서만 컴파일되는 변형이거나. 이것이 장비 소프트웨어의 일반적인 상태이지, 예외적인 경우가 아닙니다.
그리고 바로 이 지점에서 많은 도구가 조용히 성능을 잃습니다. 대부분의 코드 인텔리전스가 성공적인 컴파일 위에 만들어져 있기 때문입니다. 간단히 말하면 이렇습니다. 어떤 심볼이 어디에서 쓰이는지 알려주기 위해 프로젝트가 먼저 빌드되어야 하는 도구라면, 그 도구는 가장 필요한 순간에 침묵합니다.
Visual Studio 입장도 공정하게 짚자면, Microsoft도 이 문제를 다루고 있습니다. Insiders 빌드의 전체 코드베이스 인덱싱 작업은 대규모 C++ 솔루션을 겨냥하고 있고, 더 빠른 탐색과 컬러라이제이션이 개선점으로 보고되었으며 Find All References도 포함됩니다. 아직 프리뷰이고 점진적으로 배포되는 중입니다.

The normal state of a machine-software checkout is partly unbuildable. What a tool does at that moment is the whole difference.
지금의 작업 방식이 실제로 치르는 비용
25년 된 장비 코드베이스를 유지보수해 온 팀에게는, 그 불편을 알아채지 않을 25년이 있었던 셈입니다. 어떤 심볼이 어디에서 쓰이는지 찾는 데 얼마나 걸리는지 재는 사람은 없습니다. 비효율처럼 느껴지지 않습니다. 원래 그렇게 해온 일이기 때문입니다.
그래도 한번 재보시길 권합니다. 우리 숫자가 아니라 여러분의 숫자로요. 하루 동안 다음을 기록해 보세요.
- 무언가가 어디에서 쓰이는지 찾아 나선 횟수와, 매번 걸린 시간
- 그중 포기하고 우회한 횟수. 방어적인 검사를 넣거나, 기존 코드를 그대로 두는 식으로요
- 가장 최근에 다룬 낯선 모듈에서, 파일을 연 시점부터 확신을 갖고 변경한 시점까지 걸린 시간
여기에 팀 인원수와 분기의 주 수를 곱해 보세요. 이 항목에 대해서는 저희가 의도적으로 수치를 제시하지 않습니다. 사내에서 누군가를 설득할 수 있는 유일한 숫자는 여러분의 코드베이스에서 나온 숫자이기 때문입니다.
그리고 더 큰 비용은 느린 탐색만이 아닙니다. 불완전한 정보 위에서 커밋된 변경도 포함됩니다. 이 위험은 코드베이스가 오래될수록, 그리고 그것을 작성한 사람과 멀어질수록 커집니다.
이 환경에서 코드 인텔리전스가 갖춰야 할 것
그렇다면 도구가 단지 설치되어 있는 수준을 넘어 실제로 쓸모 있으려면 무엇이 필요할까요?
온전히 빌드되지 않는 코드에서도 심볼을 해석할 수 있어야 합니다. 그것이 이 체크아웃의 일반적인 상태이기 때문입니다. 이해를 처음부터 다시 구성하는 비용이 큰 규모에서도 반응성을 유지해야 합니다. 그리고 같은 질문에 같은 답을 내놓아야 합니다. 실행할 때마다 달라지는 결과 위에서는 변경을 판단할 수 없기 때문입니다.
모든 것이 재현성을 중심으로 조직된 산업에서, 결정론적 동작은 타협 대상이 아닙니다.
Visual Assist는 자체 파서를 중심으로 만들어진 Visual Studio용 C++ 확장 프로그램이며, 이 파서는 컴파일이 아니라 코드 인텔리전스를 위해 설계되었습니다. 프로젝트를 빌드할 필요 없이 이해하기만 하면 되기 때문에, 컴파일되지 않는 코드에서도 심볼과 참조, 정의를 계속 해석합니다. 그리고 파서는 모델이 아니라 알고리즘이므로, 같은 코드는 언제나 같은 답을 냅니다.
리더를 위한 정리: 적응 기간과 지식 편중 위험
이것이 신경 쓸 만한 문제인지 판단하는 중이라면, 근거는 적응 기간과 지식의 편중입니다.
Google 연구진이 자사의 온보딩을 연구해 IEEE Software에 발표한 결과에 따르면, 적응을 가장 크게 지연시키는 세 가지는 새로운 기술을 익히는 것, 부실하거나 없는 문서, 그리고 전문성을 가진 사람을 찾는 것이었습니다. 수십 년 된 제어 코드베이스는 이 세 가지를 모두 제공합니다. 약 400개 기업을 대상으로 한 DX의 벤치마크에서는 신규 엔지니어가 열 번째 풀 리퀘스트에 도달하기까지 2026년 4월 기준 평균 33일이 걸리는 것으로 나타났습니다. 출하 중인 장비의 레시피 시퀀싱을 맡길 만한 수준과는 아직 거리가 멉니다.
장비 소프트웨어에서 “그 모듈을 이해하던 개발자가 떠났다”는 것은 인사 통계가 아닙니다. 아직 출하 중인 제품에 대한 운영 리스크입니다. Roger Swann이 인수받은 센서 테스트 시스템이 저희가 공개한 사례입니다. 원 개발자에게 연락이 닿지 않아 어떻게 동작하는지 물어볼 기회조차 없었고, 그런데도 시스템은 크게 바뀌어야 했습니다.
앞서 말한 거리를 다른 방식으로 잰 것이기도 합니다. 장비는 다른 곳에 있고, 결국 그 코드가 왜 그렇게 생겼는지 알던 사람도 다른 곳에 있습니다. 남는 것은 코드이고, 그 코드를 얼마나 잘 읽어낼 수 있는가입니다.
레거시 C++ 코드베이스를 인수한 첫 90일. 이 글의 범용 버전입니다. 직접 작성하지 않은 코드베이스를 파악하고, 탐색하고, 기여하고, 마침내 익숙해지기까지의 4단계 방법을 담았습니다. 무료 가이드 받기
자주 묻는 질문
장비 제어 코드베이스에서 IntelliSense가 힘을 못 쓰는 이유는 무엇인가요?
네 가지가 겹칩니다. 번역 단위의 수, 여러 겹으로 쌓이고 종종 생성되는 매크로 사용, 크고 깊게 중첩된 벤더 SDK 헤더, 그리고 특정 개발자의 환경에서 온전히 빌드되지 않는 구성입니다. 성공적인 컴파일 위에 만들어진 코드 인텔리전스는 마지막 조건이 충족되지 않을 때 성능을 잃습니다.
레거시 C++ 제어 시스템에 적응하는 데는 얼마나 걸려야 하나요?
대부분의 관리자가 예상하는 것보다 깁니다. DX는 400개 대규모 조직을 표본으로, 신규 엔지니어가 열 번째 풀 리퀘스트에 도달하기까지 2026년 4월 기준 평균 33일이 걸린다고 밝혔습니다. 열 번째 풀 리퀘스트는 출하 중인 장비의 레시피 시퀀싱을 맡길 만한 수준과는 아직 거리가 멀고, 수십 년 된 제어 코드베이스는 그 거리를 좁히기보다 늘립니다. Google의 연구는 부실한 문서와 전문가 찾기를 적응을 지연시키는 상위 세 가지 요인에 포함시켰습니다.
C++ 생산성 확장 프로그램이 Copilot이나 저희 비전 SDK와 충돌하지는 않나요?
Visual Assist와 GitHub Copilot Chat은 인라인 채팅 입력 충돌이 수정된 Build 2024.2 이후로 함께 사용할 수 있습니다. 한 가지 알아둘 점은, Visual Assist의 입력 제안 팝업과 Copilot의 탭 자동완성이 같은 키를 사용한다는 것입니다. 그래서 둘 다 쓰는 사람들은 대개 한쪽을 끄고, 나머지는 탐색과 리팩터링 용도로 사용합니다. 비전과 모션 SDK는 IDE 확장 프로그램 입장에서는 평범한 C++ 라이브러리이므로, 일반적인 헤더 파싱 외에는 상호작용이 없습니다.
개발 도구 예산을 경영진에게 어떻게 설득하나요?
적응 기간과 변경에 대한 확신을 근거로 설득하세요. 설득력 있는 숫자는 여러분의 팀에서 나옵니다. 신규 엔지니어가 확신을 갖고 변경하기까지 얼마나 걸리는지, 그리고 무엇을 건드리는지 온전히 파악하지 못한 채 변경이 나가는 일이 얼마나 잦은지입니다. 둘 다 일주일만 기록해도 측정할 수 있습니다.
Visual Assist 사용해보기 30일 무료 체험 · 신용카드 불필요
