안녕하세요. 지난 글에 이어 지적 덕후생활 공동체(지덕체)개발기를 연재하고 있는 ryukim입니다.
지난 글에서는 저의 첫 번째 리팩토링 과정과 그 피드백에 대해 글을 써 봤는데요.
오늘은 두 번째 리팩토링 과정과 시행착오, 그리고 피드백에 대해 말씀드리겠습니다.

어김없이 찾아온 이렇게 하는게 맞나?

OOP를 찾아 나서는 길

비전공자인데다 해본 언어라고는 C언어 밖에 없었던 저는 OOP에 대한 개념이 부족했습니다.
동료들의 추천을 받아 ‘객체지향의 사실과 오해’라는 책도 사서 읽어보고, 유튜브에서 강의도 찾아봤지만 추상적이고 어려운 내용들이었습니다.
하지만 저는 깊은 이론보다는 지금 당장 서비스를 완성해 운영해보고 더 나아가 창업까지 하는 것이 목표였기 때문에 많은 시간을 투자할 수 없다고 판단했고, ‘구멍있는 지팡이에 원소석을 갈아끼워 마법 지팡이를 만든다’는 저에게 가장 와닿는 예시를 바탕으로 코드를 짜기 시작했습니다.
그런 접근으로 가장 먼저 한 작업은 구조를 생각해보는 것이었습니다.
첫 리팩토링 때는 나름대로 가장 가독성이 좋다는 판단하에 기능(CRUD)별로 라이브러리를 나눴다면, 이번에는 멘토님의 조언에 맞게 어떤 기능이 추가될 때 하나의 파일만 보면 CRUD를 모두 수정할 수 있도록 모델 별로 라이브러리를 나눴습니다.
그리고 각 라이브러리마다 중복되는 mongoose ODM내의 메소드 블럭을 한 줄로 바꿀 수 있도록 CRUD에 맞게 DAO(Data Access Object)파일로 나눴습니다.
여기서 가장 고민이 되었던 것은 DAO로 파일을 나눌 때 매번 다른 모델 객체를 가져와 처리해야하는데 이것을 어떻게 매개변수로 넘겨주는냐 하는 것이었습니다.
그렇게 처음 생각한 방법은 바로 if ~ else문을 이용해 타입을 문자열로 넘겨주는 것이었습니다.

(그렇게 만들어진 지옥에서 온 코드 – 사실 이 전에는 else문으로 연결되어 더욱 심각했습니다.) 하지만 아무리 생각해도 이 코드는 아닌 것 같다는 생각에 멘토님께 이런 방식이 맞는지 여쭤보러 갔습니다.

if ~ return문과 if ~ else문의 차이

멘토님은 저의 if ~ else 지옥을 보시고는 웃으시며 if ~ return문과 if ~ else문의 차이를 알아보고 어떤게 더 나은 선택인지에 대해 생각해보라고 하셨습니다.
도서관에서 빌린 책도 찾아보고 인터넷에도 검색해봤지만 아무리 찾아보고 생각해봐도 성능적인 차이는 없고 그저 보기 좋다 정도가 있는 것 같았습니다.
멘토님께 다시 찾아가 저의 생각을 말씀드렸더니 저의 생각이 정답이라고 하셨습니다. 가독성이 가장 큰 이유라고 하셨죠. 하지만 그럼에도 여전히 if문 투성이인 코드는 방법이 아니라고 하셨고 클래스를 매개변수로 처리하는 방법이 있을 거라고 하셨습니다.

자스에도 길은 있었다.

이번에도 동료에게 찾아가 질문했지만 해답을 얻을 수 없었고, 결국 직접 해보기로 했습니다.
무작정 매개변수로 클래스를 넣었더니, 이럴 수가! 정상적으로 작동됐습니다. 그런데 왜 되지…?
일단 된다는 것을 알았으니 이유를 찾기 시작했고 곧 다음과 같은 결론을 얻었습니다.
자바스크립트에는 기본적으로 클래스라는 개념이 없었고(지금은 생겼다고 합니다.) 대신 생성자 함수라는 것을 이용합니다. 자바스크립트에서 함수는 일급객체로 매개변수로 전달할 수 있기 때문에 저의 코드에서 모델 클래스를 매개변수로 전달할 수 있었던 것이었습니다. 그렇게 저는 6줄의 코드(어쩌면 모델이 생길 때마다 수정해야했을)를 한 줄로 줄일 수 있었습니다.

공부는 코드를 아름답게 한다

Promise, async/await 적용하기

다음으로 저는 계속 공부를 미뤄오고 있던 Promise와 async/await를 공부하기 시작했습니다.
그 이유는 promise와 async/await가 나온 이유와 동일한데요. 바로 콜백지옥을 벗어나기 위해서 다른 말로는 depth가 너무 깊어 가독성이 떨어지는 코드를 보기좋게 바꾸기 위해서였습니다. 저는 특히 https://joshua1988.github.io/web-development/javascript/promise-for-beginners/ 이 블로그가 정말 많이 도움되었으니 자바스크립트의 Promise와 async/await에 관심있는 분들은 참고하시면 좋을 것 같습니다.

before & after

Promise, async/await를 적용하고 저의 코드가 어떻게 달라졌는지 구경해보시죠.

before

코드의 depth가 상당히 깊고 반복되는 코드도 많습니다.

after

이 코드도 사실 여전히 async/await에 대한 이해가 부족한 코드입니다.
이후 남세현 멘토님께 멘토링을 받으며 더 간결하게 변화하였는데 그 이야기는 추후 쓰도록 하겠습니다.
before만 놓고 비교했을 때는 훨씬 간결하고 depth가 줄어든 것을 보실 수 있습니다.

피드백

리팩토링은 이제 끝

이렇게 코드를 수정해서 멘토님께 가져갔고 또 한 번 코드리뷰를 진행했습니다. 호준 멘토님과 수보 멘토님께 수정 전과 후를 보여드렸고 칭찬 받으며 통과(?)할 수 있었습니다.

지금부터는 기능 추가 미션

멘토님께서 이제 리팩토링은 충분히 이뤄졌으니 본격적으로 기능에 대해 피드백을 해주셨습니다.
그 첫번째는 바로 ‘파일을 검증할 수 있는 클래스가 있는가?’였는데요.

저의 초기버전 지덕체는 보시는 것처럼 사진 크기가 모두 달라 보기 좋지 않았습니다.
멘토님은 이런 문제를 해결하고 더 나아가 서버에 대한 부담을 줄이기 위해, 이미지의 크기, 용량, 확장자 등을 검증할 수 있는 클래스를 만들어보라는 과제를 주셨습니다.
또한 지금은 용량이 작은 이미지이지만 다루는 파일이 더 커졌을 때 클라이언트와 통신에서 어떻게 대응할지에 대해 고민해보는 과제와, 코드 곳곳에 직접 선언되어있는 중복 값들과 중요한 값들(서버 주소, DB주소, DB 설정 값 등)을 config 파일로 분리해오는 과제를 내주셨습니다.
config 파일로 환경변수를 따로 관리하지 않았을 때 어떤 문제가 발생할 수 있는지 현업에서 있었던 예시도 알려주셨습니다.
멘토링 도중 알려주시는 이런 현업에서의 일화들이 이해에 정말 큰 도움이 되는 것 같습니다.

다음 글에서는 위에서 말씀드린 (기능개선)1주차 과제를 어떻게 해결했는지 써보도록 하겠습니다.
긴 글 읽어주셔서 정말 감사합니다!