try...catch는 예외처리를 하기 위한 문법이다. 뭐 문법에 대한 설명을 할 것은 아니니, 필요하다면, 아래의 링크를 열어서 문법을 확인 해보도록 하자.
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/try...catch
예외: 일반적 규칙이나 정례에서 벗어나는 일.
예외라는 말은 위에서 나타나는 것처럼 일반적 규칙에서 벗어난 일을 뜻한다. 하지만, 몇몇 개발자들은 예상이 불가능한 상황을 예외라고 생각하는 버릇이 있는 것 같다. 무슨말이냐 하면...
자신이 예상 가능하여 if...else로 처리 가능한 모든 상황은 예외라고 판단을 하지 않는 것 같다는 말이다. 나의 경험으로는 예전에는 try...catch를 해야 하는 상황을 오류로 인식했었다.
try...catch vs if...else
즉 내가 하고자 하는 말은 아래와 같다. 고객의 정보를 불러오는 api가 있고 거기에서 사용자의 이름을 가져오고자 한다. 그때의 코드를 if...else로만 처리한다면...
// 고객 정보 불러오기.
fetch('/api/person/100').then((response) => {
// 해당 호출이 항상 성공 할 수는 없기에 예외
if (response.status === 200) {
// 해당 호출의 결과가 JsonString이 아닐 수 있음.
if (!checkJsonString(response.text())) {
return {
errorCode: `${response.status}0`,
errorMessage: '응답 데이터를 파싱할 수 없음.'
}
} else {
const res = response.json()
// 원하는 데이터는 Object이나 Array이 일 수 있음.
if (Array.isArray(res)) {
return {
errorCode: `${response.status}1`,
errorMessage: '응답 데이터 형태가 배열임.'
}
} else {
// person 객체가 있어야 하나 없는 경우.
if (res.person === undefined || res.person === null) {
return {
errorCode: `${response.status}2`,
errorMessage: '사용자를 찾을 수 없음.'
}
} else {
if (res.person.name === undefined || res.person.name === null) {
return {
errorCode: `${response.status}2`,
errorMessage: 'person is not found'
}
} else {
return res.person.name
}
}
}
}
} else {
return {
errorCode: response.status,
errorMessage: '해당 api를 사용 할 수 없음.'
}
}
}).then(res => {
if (res && res.errorCode) {
console.error(res.errorMessage)
} else {
return res
}
})
바로 위와 같게 코드를 짤 수 있을 것이다. 물론 내가 상상하지 못한 예외가 있을 수 있지만, 그 정도는 문학적 허용으로 치자.
try...catch만으로 위의 코드를 다시 짜본다면 아래와 같게 된다.
try {
await fetch('/api/person/100').then(response => response.json().person.name)
} catch (e) {
console.error(e)
}
사실 위의 에러들을 단지 console.error로만 작성하고 말 것이라면 이 코드도 좋은 상태이다. 당신이 상상한 모든 예외를 if...else로 제어하는 것은 그다지 좋은 선택이 아니다. 뭐 물론 name이 null, undefined인 경우 처리는 되어있지 않지만, 그건 해당 api호출 내에서 적절히 처리하면 된다.
try...catch 대치하지 말것.
위의 섹션에서 말하고나 하는 것은 if...else를 모두 대치하라는 것은 아니다. 예를 들어. 자식 정보를 추가해주는 함수를 아래와 같이 만들지 말라는 것이다.
function addChildren (person, child) {
try {
person.children.push(child)
} catch (e) {
person.children = [child]
}
}
이럴 때는 아래의 형태가 낫다.
function addChildren (person, child) {
if(person.children) {
person.children.push(child)
} else {
person.children = [child]
}
}
이는 한 문장으로 말하면. 프로그램 로직을 try...catch로 대체하지 말라. 이 정도로 말할 수 있을 것 같다. 뭐 물론 children이 있지만 배열이 아닐 수 있다. 그건 저 person객체를 만든 코드에서 처리할 문제이다.
무조건 적인 대치는 코드가 불안정해지며, 다른 개발자로 하여금 어디까지 허용하는 함수인지 파악이 불가능 하다.
댓글
댓글 쓰기