디버깅 가능한 시스템을 구축하기 위해서는 두 가지 필수적인 역량이 시스템에 내장되어야 합니다. 첫째는 유용하고 설명적인 오류 메시지입니다. 오류 메시지는 정보가 너무 많아 혼란스럽거나, 반대로 너무 부족하여 무용지물이 되는 양극단의 문제를 피해야 합니다. 이상적인 오류 메시지는 고유하며, 사용자가 문제에 대한 더 상세한 정보를 참조할 수 있도록 안내해야 합니다. 예를 들어, Shopify의 ruby-lsp가 정의를 찾지 못할 때 단순히 ‘No Location Found’라고 표시하는 것은 문제의 원인, 추가 조사 방법, 메시지 발생 주체, 수행하려던 작업 등 핵심 정보가 누락되어 매우 비효율적입니다. ‘Could not find definition of ‘FooComponent’, ruby-lsp returned empty array’와 같이 발생한 작업, 특정 입력, 종속 시스템의 동작, 추가 정보 획득 옵션, 요청 관련 메타데이터를 포함하는 메시지가 훨씬 유용합니다. 또한, 메시지에 시스템 및 하위 시스템의 이름을 명시하여 출처를 명확히 하는 것이 중요합니다.
둘째는 디버그 또는 진단 모드입니다. 문제 해결에 필요한 정보의 양은 방대할 수 있으며, 이를 항상 제공하는 것은 비용이 많이 들 수 있습니다. 따라서 시스템은 필요할 때 상세한 진단 정보를 생성할 수 있는 모드를 갖추어야 합니다. 진단 모드는 입력, 출력뿐만 아니라 출력을 생성하는 데 관련된 중간 값까지 제공해야 합니다. 예를 들어, ruby-lsp가 클래스 정의를 찾지 못했을 때, 검색된 파일 목록이나 폴더 목록과 같은 중간 정보는 문제 해결에 큰 도움이 됩니다. 이러한 방대한 정보는 고유 ID와 함께 로그 파일에 기록하고, 요청 시에만 --diagnostic
또는 --debug
플래그를 통해 제공하는 방식이 효율적입니다. 이러한 진단 코드 구현에는 추가적인 노력이 필요하며, 진단 코드 자체도 실패할 수 있음을 인지해야 합니다. Ruby의 Logger
블록이나 SemanticLogger
와 같은 도구를 활용하여 필요한 경우에만 상세 로깅을 수행하거나 런타임에 로깅 레벨을 동적으로 변경하는 방법을 통해 효율적인 진단 정보 생성을 지원할 수 있습니다.