예제문
- 예외가 발생해서 catch 문으로 이동 후, 다시 에러가 발생하기 전으로 돌아가는 것이라고 생각하고 짯던 코드.
- 근데 그게 아니고, 코드는 위에서 아래로 흐름.
- try 문에서 에러나면 catch문으로 이동하고, catch문에서 예외처리 한 후 아래로 이동하여 try-catch 문 바깥의 코드를 실행함
- 따라서 이건 의도대로 예외처리 된 것이 아님.
const dispensing = async (): Promise<void> => { resetLoggerState(); logRelease('디스펜싱 호출 안되냐!'); let isForCheck = false; try { await dispensingTest(isForCheck, true); isForCheck = true; await dispensingTest(isForCheck); } catch (error) { if (error instanceof Error) { switch (error.message) { case 'checksumError': case 'dataIntegrityError': logRelease(`[에러발생] : ${error.message}`); logWebHook(`[에러발생] : ${error.message}`); await dispensingTest(isForCheck); break; default: handleError( '영양성분 조합에 실패하였습니다.', '잠시 후 다시 시도해주세요.', ); return; } } } setIsSuccess(true); };
예제문 1차 개선 코드
try-catch문 통째로 새로 호출하도록 재귀 호출을 통해 기존 문제를 해결하였음.
일부러 3회까지 에러가 발생되도록 처리하였음.
- test1() 함수가 3회까지 데이터 무결성 실패 처리됨
- test1() 함수가 3~6회 까지는 체크섬 에러가 발생한 후에 성공처리됨
- test2() 함수가 3회까지는 체크섬 에러가 발생한 후에 성공처리됨
- 실제 토출 진행됨
- 완료 처리
const dispensing = async (): Promise<void> => { resetLoggerState(); logRelease('디스펜싱 호출 안되냐!'); let isForCheck = false; let count = 0; const test1 = async (): Promise<void> => { const goError = count !== 3; const goChecksumError = count > 3 && count <= 6; count += 1; try { await dispensingTest(isForCheck, goError, goChecksumError); } catch (error) { if (error instanceof Error) { switch (error.message) { case 'checksumError': case 'dataIntegrityError': logRelease(`[에러발생] : ${error.message}`); logWebHook(`[에러발생] : ${error.message}`); await test1(); break; default: handleError( '영양성분 조합에 실패하였습니다.', '잠시 후 다시 시도해주세요.', ); } } } }; await test1(); count = 0; const test2 = async (): Promise<void> => { const goError = count !== 3; count += 1; try { isForCheck = true; await dispensingTest(isForCheck, false, goError); } catch (error) { if (error instanceof Error) { switch (error.message) { case 'checksumError': logRelease(`[에러발생] : ${error.message}`); logWebHook(`[에러발생] : ${error.message}`); await test2(); break; default: handleError( '영양성분 조합에 실패하였습니다.', '잠시 후 다시 시도해주세요.', ); } } } }; await test2(); setIsSuccess(true); };
예외처리 중복코드 제거, 리팩토링 결과
- 공통된 부분이 많으므로, 코드를 줄일 수 있음.
const dispensingTest = async ( isForCheck: boolean = false, integrityTest: boolean = false, checksumError: boolean = false, ): Promise<void> => { const dispensingResult1 = await hardwareController.setDispensingAmountAndStart( dispensingAmount, isForCheck, checksumError, ); // 체크섬이 잘못됐을 때 재전송 if (dispensingResult1[4] === 0x2) { throw new Error('checksumError'); } if (isForCheck === false) { const data1 = getDataFromPayload(dispensingResult1); const dispensingAmountPayload = hardwareController.getDispensingAmountAndStartPayload( dispensingAmount, ); const isDataEqual = data1.every( (byteFromData1, index) => byteFromData1 === dispensingAmountPayload[index], ); if (isDataEqual === false || integrityTest) { throw new Error('dataIntegrityError'); } } };
const dispensing = async (): Promise<void> => { resetLoggerState(); logRelease('디스펜싱 호출 안되냐!'); let isForCheck = false; let count = 0; const test1 = async (): Promise<void> => { const goError = count < 3; const goChecksumError = count >= 3 && count < 6; count += 1; try { await dispensingTest(isForCheck, goError, goChecksumError); } catch (error) { if (error instanceof Error) { switch (error.message) { case 'checksumError': case 'dataIntegrityError': logRelease(`[에러발생] : ${error.message}`); logWebHook(`[에러발생] : ${error.message}`); await test1(); break; default: handleError( '영양성분 조합에 실패하였습니다.', '잠시 후 다시 시도해주세요.', ); } } } }; await test1(); count = 4; isForCheck = true; await test1(); setIsSuccess(true); };
LOG [전송 메세지] : A08110010800000501000502000503000504000505000506000507000519DA LOG [수신 데이터] : 160,129,16,1,8,0,0,5,1,0,5,2,0,5,3,0,5,4,0,5,5,0,5,6,0,5,7,0,5,25,218 LOG [에러발생] : dataIntegrityError LOG [전송 메세지] : A08110010800000501000502000503000504000505000506000507000519DA LOG [수신 데이터] : 160,129,16,1,8,0,0,5,1,0,5,2,0,5,3,0,5,4,0,5,5,0,5,6,0,5,7,0,5,25,218 LOG [에러발생] : dataIntegrityError LOG [전송 메세지] : A08110010800000501000502000503000504000505000506000507000519DA LOG [수신 데이터] : 160,129,16,1,8,0,0,5,1,0,5,2,0,5,3,0,5,4,0,5,5,0,5,6,0,5,7,0,5,25,218 LOG [에러발생] : dataIntegrityError LOG [전송 메세지] : A0811001080000050100050200050300050400050500050600050700051ADA LOG [수신 데이터] : 160,129,16,4,2,22,218 LOG [에러발생] : checksumError LOG [전송 메세지] : A0811001080000050100050200050300050400050500050600050700051ADA LOG [수신 데이터] : 160,129,16,4,2,22,218 LOG [에러발생] : checksumError LOG [전송 메세지] : A0811001080000050100050200050300050400050500050600050700051ADA LOG [수신 데이터] : 160,129,16,4,2,22,218 LOG [에러발생] : checksumError LOG [전송 메세지] : A08110010800000501000502000503000504000505000506000507000519DA LOG [수신 데이터] : 160,129,16,1,8,0,0,5,1,0,5,2,0,5,3,0,5,4,0,5,5,0,5,6,0,5,7,0,5,25,218 LOG [전송 메세지] : A0811003080000050100050200050300050400050500050600050700051CDA LOG [수신 데이터] : 160,129,16,4,2,22,218 LOG [에러발생] : checksumError LOG [전송 메세지] : A0811003080000050100050200050300050400050500050600050700051CDA LOG [수신 데이터] : 160,129,16,4,2,22,218 LOG [에러발생] : checksumError LOG [전송 메세지] : A0811003080000050100050200050300050400050500050600050700051BDA LOG [수신 데이터] : 160,129,16,4,1,21,218 LOG [수신 데이터] : 160,129,16,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,16,218
일부러 에러 발생시키던 코드 제거 + 2차 리팩토링 결과(최종)
const startDispensing = async (): Promise<void> => { const dispensing = async (isForCheck: boolean = false): Promise<void> => { try { const dispensingResult = await hardwareController.setDispensingAmountAndStart( dispensingAmount, isForCheck, ); // 체크섬이 잘못됐을 때 재전송 if (dispensingResult[4] === 0x2) { throw new Error('checksumError'); } if (isForCheck === false) { const data = getDataFromPayload(dispensingResult); const dispensingAmountPayload = hardwareController.getDispensingAmountAndStartPayload( dispensingAmount, ); const isDataEqual = data.every( (byte, index) => byte === dispensingAmountPayload[index], ); if (isDataEqual === false) { throw new Error('dataIntegrityError'); } } } catch (error) { if (error instanceof Error) { switch (error.message) { case 'checksumError': case 'dataIntegrityError': // 데이터가 변조된 경우, 동일한 명령어를 한번 더 내려보낸다. await dispensing(isForCheck); break; default: handleError( '영양성분 조합에 실패하였습니다.', '잠시 후 다시 시도해주세요.', ); } } } }; // 토출명령을 내려보낸다. await dispensing(); // 토출명령 데이터 검증을 위해 commandType을 0x03(Check)으로 바꿔서 한번 더 보낸다. await dispensing(true); // 토출 완료 후 상태값을 갱신한다. setIsSuccess(true); };
LOG [전송 메세지] : A08110010800000501000502000503000504000505000506000507000519DA LOG [수신 데이터] : 160,129,16,1,8,0,0,5,1,0,5,2,0,5,3,0,5,4,0,5,5,0,5,6,0,5,7,0,5,25,218 LOG [전송 메세지] : A0811003080000050100050200050300050400050500050600050700051BDA LOG [수신 데이터] : 160,129,16,4,1,21,218 LOG [수신 데이터] : 160,129,16,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,16,218