학습 출처
https://www.youtube.com/watch?v=uMZaeGzbmSM
약 한 달 전 쯤? 부터 알림 설정을 해두고 새로 업로드되는 혼공 자바스크립트 영상을 꾸준히 보고 있다.
아직까진 대부분 아는 내용이긴 한데, 보다 정확히 알게 되거나, 보다 나은 활용방법을 알게 되는 경우가 있다.
그 중에 자바스크립트 함수에서 객체를 파라미터로 받을 때 나이스한 처리방법을 새롭게 알게 되어 요약 정리해본다.
아마 이 내용은 실제 개발이나 실무에서도 많이 사용될 수 있는 좋은 내용이라 생각한다.
예외 처리
박태웅 한빛미디어 의장님은 프로그래밍을 '예외를 처리하는 것' 으로 정의하셨다.
나는 위 정의에 상당히 동의하는데, 그 이유는 개발 결과물의 완성도를 좌우하는 것이 예외 처리라 생각하기 때문이다.
뿐만 아니라 예외 처리는 조금 특별한 영역이라고 생각하기 때문이다.
왜냐하면, 자신이 작성한 코드에서 어떠한 예외가 발생할 수 있는지 그 가능성에 대해 사전에 인지하고
이에 대해 대응할 수 있어야만 보다 완성도 높은 코드를 작성할 수 있기 때문이다.
그러기 위해서는 단순 개발 지식 뿐만 아니라 현장에서의 경험 또한 필요하다고 생각한다.
단순 구현에 그쳐서는 가치를 창출할 수 없다. 제대로 만들어내야만 한다.
그리고 이를 위해서는 반드시 수준 높은 예외 처리가 필요하다.
아무튼 그래서 한 마디로 정리하자면 예외 처리, 상당히 중요하다.
점점 개선되는 파라미터 핸들링!
버전 1이다.
함수 내부에서 네 개의 파라미터가 필요하여, 호출 시 네 개의 변수를 전달하도록 하고 있다.
갯수가 많아지면 호출할때 불편할 뿐만 아니라 휴먼 에러를 발생시킬 가능성이 높아진다.
IDE의 도움 없이 작성된 호출부 코드를 읽기만 한다면 각 파라미터가 어떤 용도로 사용되는지 파악하기 어렵다.
// V1 - 가장 기본적인 형태의 함수.
// 발신인, 수신인, 제목, 내용 각각의 파라미터로 전달받아 이를 로그하는 함수.
const sendMail = (sender, receiver, title, message) => {
console.log(`\nV1 - sendMail is called`);
console.log(`To. ${receiver}`);
console.log(`Title : ${title}`);
console.log(`Message : ${message}`);
console.log(`From. ${sender}`);
console.log(`--------------------------------------`);
}
// 함수 호출에 필요한 파라미터가 많아질수록 호출하는 코드가 길어지고 휴먼 에러 가능성이 높아짐.
// 호출 시점에 각 파라미터가 어떻게 사용되는지 알기 어려움.
sendMail(`발신인`, `수신인`, `제목`, `내용`);
V1 - sendMail is called
To. 수신인
Title : 제목
Message : 내용
From. 발신인
--------------------------------------
[Done] exited with code=0 in 0.119 seconds
버전2이다.
1에서 개선된 내용으로는 먼저 파라미터가 많아져도 호출부가 비교적 간결할 수 있다는 것이다.
객체로 전달받아 해당 객체 내부에 미리 약속된 필드명으로 접근하여 값을 사용한다.
또한 호출부에서도 필드명과 함께 값을 전달하기 때문에 버전1에 비해서는 각 값의 용도를 유추하기 수월하다.
그러나 여전히 호출부를 작성할때, 어떤 필드가 필요한지 파악하기 힘들고 오작동시 원인을 파악하기 어렵다.
// V2 - 여러 개의 파라미터를 객체로 전달받도록 개선한 함수.
// 객체 안에 있는 파라미터를 약속된 필드명으로 접근하여 사용함.
const sendMailByObject = (parameterObject) => {
console.log(`\nV2 - sendMailByObject is called`);
console.log(`To. ${parameterObject.receiver}`);
console.log(`Title : ${parameterObject.title}`);
console.log(`Message : ${parameterObject.message}`);
console.log(`From. ${parameterObject.sender}`);
console.log(`--------------------------------------`);
}
// 함수 호출에 필요한 파라미터가 많아져도 하나의 객체에 담기 때문에 코드가 길어지는 문제는 해결됨.
// 코드를 읽을 때, 각 파라미터가 어떤 필드명으로 전달되는지 파악하기 수월해짐.
sendMailByObject({
sender: `발신인`,
receiver: `수신인`,
title: `안부 드립니다`,
message: `잘 지내시죠?`
});
// 그러나 새로 호출 코드를 작성해야할 때에는 필드명을 오입력하거나 누락하는 오류가 여전히 발생가능함.
sendMailByObject({
sender: `발신인`,
receiever: `수신인`, // To. undefined 발생
title: `안부 드립니다`,
// Message: undefined 발생
});
V2 - sendMailByObject is called
To. 수신인
Title : 안부 드립니다
Message : 잘 지내시죠?
From. 발신인
--------------------------------------
V2 - sendMailByObject is called
To. undefined
Title : 안부 드립니다
Message : undefined
From. 발신인
--------------------------------------
[Done] exited with code=0 in 0.119 seconds
버전3이다.
버전2에서 개선된 내용은 로직을 수행하기 전에 객체 내 파라미터를 검증한다는 점이다.
하여 특정 필드가 필수값인데 전달되지 않았을 경우 예외를 발생시켜 해당 필드를 작성하도록 유도하는 것이다.
기본적인 형태의 예외처리를 했다고 볼 수 있다.
// V3 - 객체로 전달받은 파라미터를 검증하는 로직을 추가한 함수.
// 객체로 전달받은 파라미터 내에 필수 필드가 유효하지 않을 경우 예외를 발생시켜 개발자가 쉽게 인지하게 함.
const isValid = (parameterObject, fieldName) => {
if(parameterObject[fieldName] === undefined) {
throw `${fieldName} is essential.`;
}
}
const sendMailByObjectWithValidation = (parameterObject) => {
const essentialFieldNames = [`sender`, `receiver`, `title`, `message`];
console.log(`\nV3 sendMailByObjectWithValidation is called`);
essentialFieldNames.forEach(essentialFieldName => isValid(parameterObject, essentialFieldName));
console.log(`To. ${parameterObject.receiver}`);
console.log(`Title : ${parameterObject.title}`);
console.log(`Message : ${parameterObject.message}`);
console.log(`From. ${parameterObject.sender}`);
console.log(`--------------------------------------`);
}
// 정상 출력
sendMailByObjectWithValidation({
sender: `발신인`,
receiver: `수신인`,
title: `안부 드립니다`,
message: `잘 지내시죠?`
});
// receiver is essential. throw 후 수행 정지.
// 어느 파라미터 필드에서 문제가 생겼는지 파악할 수 있음.
sendMailByObjectWithValidation({
sender: `발신인`,
reciever: `수신인`, // 필드명 오기.
title: `안부 드립니다`,
});
V3 sendMailByObjectWithValidation is called
To. 수신인
Title : 안부 드립니다
Message : 잘 지내시죠?
From. 발신인
--------------------------------------
V3 sendMailByObjectWithValidation is called
tempCodeRunnerFile.js:5
throw `${fieldName} is essential.`;
^
receiver is essential.
(Use `node --trace-uncaught ...` to show where the exception was thrown)
[Done] exited with code=1 in 0.12 seconds
버전4이다. 최종버전이다.
버전3에서 개선된 내용은 초기값에 대한 사용이다.
필수값인 필드에 대해서는 throw 값을 미리 넣어두고, 전달되지 않을 경우 throw가 발생되는 식이다.
필수값이 아닌 필드에 대해서는 기본값을 넣어둬서, 전달되지 않을 경우 해당 값을 사용하도록 했다.
또한 객체 파라미터 자체가 전달되지 않을 경우를 대비하여 비어있는 객체 초기값도 설정한 모습이다.
마지막으로 각 필드를 명시하여 기본값을 설정하였기 때문에, 버전3과 달리 속성 접근자를 사용하지 않는다.
// V4 가능한 모든 예외처리를 적용한 함수.
// 객체 파라미터 자체가 전달되지 않거나, 객체 파라미터 내 필수 필드가 없는 경우에 모두 대응함.
// 필수값이 아닌 경우, 전달되면 전달된 값을, 전달되지 않으면 기본값을 사용하도록 설정.
const getErrorMessageByFieldName = (fieldName) => {
throw `${fieldName} is required`;
}
// 객체로 전달받은 필드의 초기값을 설정하기 위해 콜론(:)이 아닌 대입연산자(=)를 사용한다.
const sendMailByObjectWithDefaultValues = (
{
sender = getErrorMessageByFieldName(`sender`), // 필수값의 경우 throw 값을 초기값으로 설정하여, 전달되지 않을 경우 예외를 발생시킨다.
receiver = getErrorMessageByFieldName(`receiver`),
title = `untitled`, // 필수적이지 않은 파라미터 필드에 대해서는 단순 문자열 초기값 설정.
message = getErrorMessageByFieldName(`message`)
} = {} // 객체 파라미터 자체가 전달되지 않는 경우에 대응하기 위한 객체 초기값 설정.
) => {
console.log(`\nV4 sendMailByObjectWithDefaultThrows is called`);
console.log(`To. ${receiver}`);
console.log(`Title : ${title}`);
console.log(`Message : ${message}`);
console.log(`From. ${sender}`);
console.log(`--------------------------------------`);
}
// sender is required
// 객체 자체를 전달하지 않아도 정상적으로 유효성 검사가 동작한다.
sendMailByObjectWithDefaultValues()
// Title : untitled
// title 필드를 전달하지 않아도, 기본값인 untitled로 동작한다.
sendMailByObjectWithDefaultValues({
sender: `Rich Sender`,
receiver: `Rich Receiver`,
message: `Here is the message`
})
tempCodeRunnerFile.js:5
throw `${fieldName} is required`;
^
sender is required
(Use `node --trace-uncaught ...` to show where the exception was thrown)
[Done] exited with code=1 in 0.119 seconds
V4 sendMailByObjectWithDefaultThrows is called
To. Rich Receiver
Title : untitled
Message : Here is the message
From. Rich Sender
--------------------------------------
[Done] exited with code=0 in 0.119 seconds
결론
아마 종종 이 포스팅도 다시 들어와서 초기값 설정과 예외 핸들링에 대해 살펴볼지도 모르겠다.
버전4에서 필수값에 대한 throw 초기값 설정, 비 필수값에 대한 기본값 설정, 빈 객체 초기값 설정 모두다
처음 접한 개념이기 때문에 아주 나이스하게 예외 핸들링하는 모습이 인상적이었다.
그리고 함수 내에서 속성접근자를 사용하지 않아도 된다는 점도 맘에 들었다.
생활코딩님이 항상 말씀하시는 필요를 느낀 후 학습하는 것의 효율성을 완전 체감했다.
실무에서 이미 작성된 객체로 여러 필드 파라미터를 전달하는 함수를 봤는데, 항상 어려웠다.
어떤 필드가 필수값인지, 어떻게 사용되는지, 값에 따라 어떻게 분기처리되는지, 어떤 분기선택지가 있는지 등등..
다음에 내가 작성할 일이 생기면 그때는 버전4처럼 나이스하게 예외핸들링을 하고 싶다.
멋진 코드를 작성하면 아주 뿌듯하고 기분이 좋다 ㅋ
'JavaScript' 카테고리의 다른 글
자바스크립트 배열 함수 정리! (0) | 2021.06.04 |
---|---|
TypeScript 첫 발 떼기 (0) | 2021.01.11 |
예약일 선택용 캘린더 구현하기 without 라이브러리 (0) | 2020.11.10 |
RMA : 취업포털에서 공고를 필터링해주는 크롬 확장 프로그램 (10) | 2020.10.24 |
24시간 간격 방문 카운트 구현 : 쿠키, 정규식, navigator.userAgent (0) | 2020.10.04 |