오늘은 Bare Minimal 따라가기도 힘든 날이었다. 비동기에 대한 내용 자체도 난이도가 있었지만 테스트를 통과하기 위해서 테스트 파일을 검사
하는 안타까운 일이 또 다시 생겼다. 이번 파트에서 고생한 사람들이 많을거다. 트러블 슈팅 하면서 분노가 쌓이고 그 과정 속에서 비동기 개념을 확실하게 깨닫게 됐다.
비동기에 대한 내용은 아주 좋았다. 프로그래밍에서 비동기를 구현한 적은 없었던 것 같아서 이렇게 구현되는 구조 자체가 흥미로웠고 좋았다. 비동기로 실행하면 작업 흐름을 구성해야 된다는 생소한 경험 때문에 진행 내내 재밌었다. 지금까지 경험해본 적이 없는 새로운 모습의 코딩을 경험했다.
역대급으로 불친절한 테스트였다. 또 다시 테스트 파일을 까볼줄이야.
첫번째 에러 처리에서 메시지는 에러가 발생할 경우, callback 첫번째 인자에 에러 객체가 전달되어야 합니다.
라고만 되어있다. 두 번째 data에 null을 넣으라는 표기
가 없다. 그렇다면 그렇다고 말을 해주지 어디에도 null을 넣으라는 표기가 없는건 너무 심하지 않았나? toBeNull
확인 때문에 한참을 해맸다. 코드스테이츠 진행하면서 이정도로 빡!😡쳤던 적은 없었다. 아니... 한마디 써 줄수는 있었잖아요. 형님들... 다 끝나고 나서야 null을 넣는 의미를 알게 됐다.
내용을 불러오지 못해서 data 내용이 undefined 일 경우 callback 함수가 정상적으로 동작하지 않을 수 있다. 의도적으로 null 처리를 해서 비워져 있다고 명시하는게 더 좋다.
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
callback(err, null);
} else {
callback(err, data);
}
-----
test('에러가 발생할 경우, callback 첫번째 인자에 에러 객체가 전달되어야 합니다', (done) => {
getDataFromFile('nonexist', (err, data) => {
expect(err.code).toBe('ENOENT');
expect(data).toBeNull()
두 번째 에러 처리는 catch 구문으로 빠질 수 있는지를 확인한다. 여기서도 한참을 해맸다. 코드 안에 catch 구문을 넣으려고 했기 때문이다. reject 실행까지 잡아주고 끝내는게 정답이었다. reject로 끝내면 가장 가까운 catch 구문으로 보내주고 테스트 구문에서 catch 구문이 구현되어 있다.
근데 이거도요 형님들.. catch 블록을 통하여
라고 써놓으면 마치 catch 블록을 구현해야 될 것 같잖아요..?
이 내용에 대한 반박은 getDataFromFilePromise
이라는 함수명에서 Promise 부분만 구현하면 된다는 내용을 내포하고 있다... 아... 😇
const getDataFromFilePromise = filePath => {
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) return reject(err)
else return resolve(data)
})
})
// TODO: Promise 및 fs.readFile을 이용해 작성합니다.
};
-----
it('에러가 발생할 경우, catch 블록을 통하여 에러 객체가 전달되어야 합니다', (done) => {
return getDataFromFilePromise('nonexist').catch((err) => {
expect(err.code).toBe('ENOENT');
done();
이게 제일 심각하다. 우선 채점 기준을 보자.
getDataFromFilePromise
을 두 번 사용했는지 확인하기 위해서 funcBody 라는 정규 표현식을 참조한다.
test('fs module을 직접 사용하지 말고, getDataFromFilePromise을 두 번 사용해야 합니다', () => {
let matched = funcBody.match(/getDataFromFilePromise\(.+\)/g) || [];
expect(matched.length).toBe(2);
matched =
funcBody.match(
/fs\.readFile(Sync)?|fs\[(\'|\")readFile(Sync)?(\'|\")\]/g
) || [];
expect(matched.length).toBe(0);
});
---
const funcBody = readAllUsersChaining.toString().replace(COMMENT, '');
const COMMENT = new RegExp(
`${MULTI_LINES_COMMENT.source}|${ONE_LINE_COMMENT.source}`,
'g'
);
그리고 코드를 본다. 이 코드는 문제가 없다.
const readAllUsersChaining = () => {
let result = [];
// TODO: 여러개의 Promise를 then으로 연결하여 작성합니다
return getDataFromFilePromise(user1Path).then(data => pushResult(data)).then(() => {
return getDataFromFilePromise(user2Path)}).then(data => pushResult(data)).then((data) => {
return result;
})
function pushResult (arg) {
result.push(JSON.parse(arg))
//return result
}
}
하지만 아래 코드는 테스트가 실패한다.
.then(() => getDataFromFilePromise(user2Path))
Promise를 한 번 더 받을 때 return 구문을 썼는지의 차이다. 화살표 함수는 자체적으로 return 구문을 포함하고 있기 때문에 당연히 될 줄 알았는데 return 문으로 했는지 안했는지에 따라서 테스트 결과가 달라진다. 정규 표현식이 찾지 못했을 것이다.
const readAllUsersChaining = () => {
let result = [];
// TODO: 여러개의 Promise를 then으로 연결하여 작성합니다
return getDataFromFilePromise(user1Path).then(data => pushResult(data))
.then(() => getDataFromFilePromise(user2Path)).then(data => pushResult(data)).then((data) => {
return result;
})
function pushResult (arg) {
result.push(JSON.parse(arg))
//return result
}
}
와... 이건 정말이지... 너무한다. 테스트를 분석해서 역으로 통과한다는 과정은 찝찝한 경험을 남긴다. 이걸 트러블슈팅 하면서 비동기에 대한 개념을 잘 익혔지만 그다지 좋은 기분은 아니었다. 오늘 과제는 고생하지 않은 페어가 없을 것이다.
그래도 잘 배우긴 했다... 그만큼 너무 피곤하다. 어깨가 결리기 시작했다. 오늘은 여기까지.
바로 며칠 전이지만 뭔가.. 이젠 추억이 되어버린 ..