기술에 감성을 더한 소프트웨어로 창의적이고 혁신적인 문화를 만들어가는
소프트박스의 진솔한 이야기를 전합니다.
프론트엔드 개발을 진행하다 보면 예기치 못한 에러가 자주 발생합니다. 특히 주니어 개발자라면 에러 메시지를 접했을 때, 당황스럽고 어디서부터 손을 대야 할지 막막할 수 있죠.
하지만 걱정할 필요는 없습니다. 경험이 쌓여 시니어 개발자가 되면, 에러 메시지는 오히려 문제를 사전에 방지할 수 있는 중요한 신호로 여겨집니다. 에러 없이 릴리즈된 소프트웨어가 나중에 더 큰 문제를 야기할 수 있기 때문이죠. 시니어 개발자는 수많은 에러를 겪어보았기에, 새로운 에러가 나타나더라도 다양한 해결 방법을 찾아낼 수 있습니다.
실제로 프로그램 개발 과정에서 에러 조사와 수정에 드는 시간은 전체 업무 시간의 약 40%에 달한다고 알려져 있습니다. 따라서 에러를 효과적으로 처리하는 능력은 개발자에게 필수적인 역량입니다. 아무리 많은 경험을 쌓더라도 모든 종류의 에러를 직접 경험할 수는 없으므로, 에러 발생 시 이를 신속하게 분석하고 해결할 수 있는 능력을 키우는 것이 중요하죠. 이번 글에서는 프론트엔드 개발자가 자주 만나는 에러의 유형과 해결 방법 등을 살펴보겠습니다.
에러가 발생하면 대부분의 개발 환경은 “에러가 발생했어요”라고 친절하게 알려줍니다. 에러를 효과적으로 해결하려면, 먼저 에러 메시지가 어떻게 구성되어 있는지 이해하는 것이 중요합니다. 에러 메시지는 문제의 원인을 파악할 수 있는 핵심 정보를 제공하며, 이를 분석하는 것이 에러를 다루는 첫걸음입니다.
대부분의 프로그래밍 언어에서 에러 메시지는 다음과 같은 요소로 구성됩니다.
예를 들어, 다음과 같은 에러 메시지를 살펴봅시다.
TypeError: Cannot read properties of undefined (reading `name`) at Object.getUserName (app.js:10) at fetchUserData (app.js:25) at main (app.js:40)
위 메시지는 TypeError가 발생했으며, undefined인 객체에서 name 속성을 읽으려 했을 때 문제가 발생했음을 의미합니다. 또한 app.js 파일의 10번째 줄에서 getUserName 함수가 호출될 때 에러가 발생했고, 그 호출이 fetchUserData 함수(25번째 줄)와 main 함수(40번째 줄)에서 이루어졌음을 알 수 있습니다. 무슨 말인지 모르겠나요? 각 요소에 대해 좀 더 알아볼게요.
프론트엔드 개발에서 발생하는 대표적인 에러 유형은 다음과 같습니다.
이처럼 에러 메시지에 나오는 유형에 대한 이해만 있어도, 에러가 왜 발생했는지 알 수 있습니다. 이를 통해 우리가 만든 프로그램에서 어떤 부분에 집중해야 하는지 판단할 수 있게 됩니다.
에러 유형을 보고 어디에 집중해야 하는지 알았다면, 이제 정확히 우리 코드 어디에서 에러가 발생했는지를 추적해야 합니다. 이때 필요한 것이 바로 스택 트레이스입니다.
스택 트레이스는 보통 다음과 같은 형식으로 표시됩니다.
TypeError: Cannot read properties of undefined (reading `name`)
at Object.getUserName (app.js:10)
at fetchUserData (app.js:25)
at main (app.js:40)
위의 예시를 보면, main 함수에서 fetchUserData를 호출했고, 그 내부에서 getUserName을 호출하다가 에러가 발생했음을 알 수 있습니다. 이러한 구조를 활용하면 어떤 함수가 에러의 원인인지 추적할 수 있습니다.
app.js:10
에서 문제가 발생했다면 해당 파일의 10번째 줄을 확인하여 어떤 코드가 문제를 일으키는지 살펴보세요.console.log()
를 사용하여 특정 변수가 예상한 값을 가졌는지 점검합니다.
이때 스택 트레이스의 전체를 볼 필요는 없습니다. 가장 마지막 추적만으로도 에러가 발생한 위치를 쉽게 찾을 수 있기 때문이죠. 그러나 간혹 여러 에러 상황에서 좀 더 추적을 따라가야만 하는 에러도 있습니다. 예를 들어, 실제 에러가 getUserName
에서 발생한 것이 아니라, fetchUserData
가 getUserName
을 호출하지 않아야 했는데 호출한 경우일 수도 있습니다. 이 경우 우리가 코드에서 수정해야 할 부분은 마지막 추적인 getUserName
이 아닌 fetchUserData
입니다.
이제 우리는 어떤 유형의 에러가 어디에서 발생했는지를 알게 되었습니다. 이제 이 에러를 해결해 봅시다. 에러를 해결하기 위해서는 작성한 코드의 논리를 순차적으로 따라가면서, 우리가 생각했던 논리대로 프로그램의 동작이 일치하는지 분석해야 합니다. 이 과정을 “디버깅”이라고 합니다. 이 디버깅은 다양한 도구를 이용하면 더욱 효과적입니다.
프론트엔드 개발에서 가장 강력한 디버깅 도구는 ‘브라우저 개발자 도구(DevTools)’입니다. Chrome, Firefox, Edge 등의 브라우저에서 제공하는 개발자 도구를 활용하면, 보다 효과적으로 에러를 분석할 수 있습니다.
1. 콘솔(Console) 활용
console.log()
, console.warn()
, console.error()
를 사용하여 실행 중인 코드의 상태를 확인할 수 있습니다.
2. 네트워크 패널(Network Tab) 활용
3. 요소 검사(Elements Tab)
4. 소스 패널(Sources Tab)에서 브레이크포인트 설정
5. 브라우저 디버거 활용
다음으로 Visual Studio Code(VSCode)의 디버깅 기능을 활용하면, 프론트엔드 개발에서 발생하는 문제를 더욱 효과적으로 해결할 수 있습니다.
이렇게 디버깅을 통해 논리의 실패가 확인되었다면, 코드를 수정하여 에러를 해결할 수 있습니다. 그렇다면 에러를 해결하고 나면 끝일까요? 이제 에러를 해결하는 데서 그치지 않고, 같은 에러가 재발하지 않도록 예방해야 합니다. 에러를 수정한 후에는 수정한 코드가 의도한 대로 작동하는지 확인하는 과정이 필수적인데요. 단순히 에러 메시지가 사라졌다고 해서, 문제가 완전히 해결되었다고 판단해서는 안 됩니다.
수정된 코드와 관련된 기능이 제대로 작동하는지 확인하기 위해 테스트 코드를 작성하고 시행해야 합니다. 수정한 부분만이 아니라 회귀 테스트를 통해 수정한 부분이 기존 기능에 부정적인 영향을 미치지 않았는지 확인합니다. 회귀 테스트는 에러 수정 후 전체 애플리케이션의 안정성을 확보하는 데 중요한 역할을 합니다.
에러는 결국 개발자가 발생시킨 것이기 때문에, 같은 에러가 반복될 수 있습니다. 따라서 같은 에러 발생 시 효과적인 해결을 위해 발생한 에러와 해결 과정을 기록해야 합니다. 유사한 에러가 재발생할 때 문제를 빠르게 해결할 수 있도록 도와줍니다.
프로그래밍에서 에러는 피할 수 없는 요소이며, 이를 통해 배우고 성장할 기회로 삼는 것이 중요합니다. 에러가 발생했을 때 에러 메시지와 스택 트레이스를 분석하면, 미처 놓친 부분이나 개선할 수 있는 점을 찾는 과정에서 문제 해결 능력이 향상됩니다. 때론 에러가 좌절감을 줄 수도 있지만, 경험이 쌓이면서 이러한 문제가 곧 개발 실력 향상의 발판이 됩니다. 여러분이 아는 훌륭한 개발자들도 비슷한 어려움을 겪었고요.
그리고 개발 과정에서 발생하는 에러는 단순한 문제 상황이 아니라, 더 나은 코드를 만들기 위한 중요한 신호입니다. 에러 메시지를 통해 문제의 원인을 파악하고, 스택 트레이스를 활용해 디버깅을 진행하며, 철저한 테스트를 통해 문제를 해결할 수 있습니다.
또한 에러 로그를 기록하고 팀 내에서 지식을 공유함으로써, 비슷한 문제에 빠르게 대응할 수 있는 체계를 마련해 팀의 성장도 이끌어 낼 수 있죠. 에러는 개발자로서 성장하는 과정의 일부이며, 이를 효과적으로 관리하는 능력은 훌륭한 개발자가 되기 위한 필수 역량입니다. 그러니 에러를 두려워하지 말고, 오히려 개선과 학습의 기회로 삼아 보면 어떨까요?