EMO Project 보완 후 회고(1)

Moen·2022년 5월 6일
0
post-thumbnail

🚀 다시 시작하게 된 계기

처음 블로그 포스팅을 통해서 직접 참여하여 프로젝트를 진행한 경험이 부족한 것을 알게 되었고 부족한 부분을 해결하기 위해서 새로운 토이 프로젝트를 진행할 예정이었으나, 이전에 진행했던 프로젝트들이 항상 아쉬운 마음으로 마무리했다는 생각이 들면서 다시 한번 github repo를 둘러보았습니다.

그중에 처음 진행한 EMO 프로젝트를 찾게 되었고 부족한 부분이 많은 소스 코드라는 것을 알게 되었고, 새로운 프로젝트를 하는 것도 좋은 방안이지만 부족한 부분을 찾아보고 수정을 통해서 성장을 할 수 있겠다는 생각에 유지 보수를 진행할 결정을 하게 되었습니다.

특히 매력적인 부분은 밑에서 리스트로 정리할 예정이지만 간단하게 언급하면 MPA로 만들어진 소스 코드를 SPA로 만들면 서버와의 네트워크 통신 자원도 줄어들고 EndPoint 또한 명확하게 정해지면서 전역 스코프에 식별자를 생성하지 않을 수 있다는 점이 EMO Project를 선택한 가장 큰 이유입니다.


🫂 팀 프로젝트 정리

기획 자료

부트캠프를 통해서 4명의 팀이 협력을 통해 일주일 동안 기획 + 제작을 진행한 프로젝트입니다.

기획 회의를 통해 아이디어를 공유하고 의견을 모은 결과 많은 사람이 음식에 대한 관심도가 높다는 것을 파악하고 그중에서 1인 가구의 수가 증가하는 점에 대해 중점을 맞추어 다양한 종류와 요리 방법을 쉽게 알려주는 어플을 만들어 보자는 취지에서 EMO(이 재료로 모해 먹지?)가 만들어지게 되었습니다.

📖 기술 스텍

📖 협업을 통해 배운 점

팀원들과 회의를 통해서 기간 내에 마무리 할 수 있는 기능을 추가하기로 결정하고, 기능별로 분배를 통해서 자신이 맞은 업무를 진행하는 것을 목표로 프로젝트를 진행하였습니다.

프로젝트 기간이 짧고 대부분 팀원이 처음 협업을 해보는 상황이라서 우왕좌왕하는 모습도 보였습니다. 그래도 기간 안에 기획한 기능들을 구현하기 위해서 여러 밤을 함께 보내면서 부족한 부분이 많이 보였지만, 원하는 주요 기능들을 모두 완성할 수 있었습니다.

프로젝트를 진행하면서 성장할 수 있었던 계기는 기획 단계와 팀원들이 작성한 코드에 대한 의견을 주고받는 일이었습니다.

기획을 통해서 배운 점은 기획을 준비하면서 서로의 의견을 통합하고 자신의 주장을 펼칠 수 있었고, 다른 사람의 의견을 듣고 서로 다른 점을 마쳐 가면서 넓은 시각과 세세한 부분까지 신경 쓸 수 있다는 장점을 느꼈습니다.

팀원들이 작성한 코드에 대한 의견을 주고 받으면서 자신만이 사용하는 코드 작성 방식을 사용하지 않고 통합된 컨벤션을 사용하여 컨벤션에 위배되는 코드를 쉽게 찾을 수 있었습니다.


📝 문제점 및 보완 리스트

📖 문제점

  1. MPA 사용으로 인한 코드의 흐름을 읽기 어렵고 어플리케이션이 무거워지는 문제 발생
  2. MPA로 제작하여 EndPoint가 따로 존재하지 않고 무분별한 .html, .js 확장자가 존재해서 가독성이 매우 떨어짐
  3. 모듈을 사용하지 않아서 js file이 분리되어 있어도 전역 스코프는 공통으로 사용하여 암묵적 전역 현상이 발생할 수 있다.
  4. 식별자 네이밍이 명확하지 않아서
  5. 중복된 코드로 레거시 코드가 발생
  6. 잘못된 비동기 로직을 사용
  7. Type을 정적으로 컴파일하지 않아서 프로퍼티 접근 시 null, undefind를 대처하지 못하는 경우가 많이 발생하는 코드가 존재한다.

📖 보완 리스트

  • MPA로 만들어져 있는 코드를 SPA와 Ajax 네트워크 통신으로 어플리케이션을 가볍게 만들기 (1번 문제)
  • Webpack을 도입해서 모듈 스코프를 사용하고 EndPoint 설정 후 Babel을 사용해서 JS 크로스브라우징 문제 해결하기 (2번, 3번 문제)
  • 깔끔한 코드 작성
    • 명확하게 의미로 작성하지 않은 식별자 수정 및 무분별한 변수 사용 억제, 상수 식별자 대문자 네이밍 규칙을 통해서 가독성 높이기 (4번 문제)
    • 중복된 코드로 레거시 코드가 발생한 부분을 함수 단위로 묶어 명확한 작업 만들기(너무 과도한 작업을 하는 함수는 작은 단위로 분리하기) (5번 문제)
    • aync, await 문법으로 모든 비동기 로직을 통일하여 비동기로 자동하는 코드를 을 동기로 작동하는 코드처럼 만들기 (6번 문제)
  • TypeScript을 도입하여 정적으로 컴파일하여 타입 문제 해결 및 런타임에 발생하던 에러를 컴파일 단계에서 에러를 캐치하여 효율성 높이기 (7번 문제)

문제점 보완에 관련된 Schedule Task 한번에 보기


🤔 난관에 부딪히고, 깨달은 점

📖 코드 분석

EMO 프로젝트를 진행할 시기에는 4명의 팀원이 분업을 통해서 기능을 구현했습니다. 그리고 시간도 많이 흘러서 코드가 어떻게 동작하는지 알 수 없는 때도 있고, 왜 이렇게 작성하였는지에 대한 의문도 생겼습니다. 그래서 모든 코드를 분석하면서 코드가 어떻게 만들어졌는지 알아가는 시간이 가졌습니다.

코드 분석을 하면서 분명 시간이 어느 정도 걸렸지만, 다른 사람 및 과거의 나 자신이 코드를 작성한 의도를 생각해보았고, 코드에 흐름을 알아가면서 프로젝트를 어떤 방향으로 개선 및 코드 컨벤션을 통일할 방법도 구축하였습니다. 이를 통해 문제점 개선이 필요한 코드가 어디에 있는지 알게 되었고, 더 효율적으로 문제점을 개선할 수 있었습니다.

📖 Image upload

위의 사진은 레시피 목록을 보여주는 Page로 작업을 진행할 당시에 레시피 마다 image가 다르지만 모든 이미지를 하나로 통일하여 작업하였습니다. 그 이유로는 Webpack을 사용하는 경우 JS 확장자에서 image 확장자(jpg, png, etc….)를 사용하기 위해서는 import로 사용할 file을 가져와야 합니다. 하지만 저는 Json-server에서 URL 경로만을 알려주는 data를 AJAX 통신을 통해서 받아 왔습니다. 그 결과 JS file에서 명시적으로 image를 지정하지 않아서 경로를 확인할 수 없는 문제가 발생했습니다.

많은 방법을 찾아 보았지만, 해결책이 잘 떠오르지 않고 차선책 한 가지만 가지고 있었습니다. 그래서 어쩔 수 없이 차선책으로 선택한 방법으로는 Entry point file(index.ts)에서 데이터로 사용하는 모든 image를 import 후에 image를 참조만 하는 함수를 만들고 바로 실행하는 방법을 선택했습니다.

물론 차선책이지만 webpack에서 mode를 production으로 설정하면 Tree Shaking을 자동으로 실행되어 사용하지 않는 import 로직을 제거하기 때문에 차선책으로 선택했습니다. (대신 Tree Shaking을 사용하고 싶으면 ESM을 사용해야 합니다) 또한 EMO-V3를 시작하게 된다면 개선점을 찾아볼 예정입니다.

imageAllUplad 함수를 실행하면 데이터에 있는 모든 image를 참조하게 만들었습니다.

📖 JavaScript ▶︎▶︎ TypeScript

EMO Project를 시작하면서 TypeScript를 Project에 적용해서 부족한 TypeScript의 실력도 같이 올리고 싶다는 욕심이 생겼습니다. 그래서 Project를 directory에 옮기자마자 npm i -D typescript로 TypeScript를 Project에 적용했습니다.

난관에 봉착한 부분으로는 무시무시하다는 Setting 부분이었습니다. 특히 JavaScript에서 TypeScript로 마이그레이션을 하는 상황이라서 js Extention으로 작성한 logic 들이 많은 Error를 던졌습니다. 저는 마이그레이션을 하면서 tsconfig.json 설정에 allowJs 속성을 지정하지 않는 선택을 했습니다. 그래서 처음 Js로 만든 Project는 완전히 망가져 버렸습니다. 시간이 더 많이 걸리지만, 이런 작업 선택을 하게 된 이유로는 SPA로 Project를 수정하면서 순서를 지키고 싶다는 생각이 크게 들었습니다. 예시로 들면 일단 login page => ingredient page => cuisine page로 Project의 흐름을 잡고 싶다고 생각하면 일단 login page에 대한 js extention을 ts extention으로 바꾸면서 type에 대해 정의를 하고 Route를 설정하고 그다음 순서로 가는 페이지의 작업을 반복하는 방식을 통해서 획일적인 작업 방식을 통해 작업을 통일하고 싶다는 생각을 가지게 되었고 그 결과 모든 작업을 위의 방식으로 작업을 마무리할 수 있었습니다.

협업을 하지 않고 혼자서 모든 작업을 수행해야 했던 저는, 획일적으로 모든 작업 방식을 통일하지 않았다면 뒤죽박죽이 된 작업 방식으로 가독성 저하 및 통일되지 않은 코드 스타일로 더욱 많은 시간을 소비해야 할 수 있었다고 생각합니다.


🔑 결과물

github 주소
작동이 궁금하면 github repo로 가서 git clone을 통해서 실행 할 수 있습니다.


🖌 작업하며 배우고 느낀 것

📖 라우터를 통해 SPA 구현

History 기본으로 Router API를 구현했습니다.

Router가 동작하는 원리를 설명하면 router 변수에 URL의 address를 문자열로 미리 지정하여 화면이 변경될 때마다 history.pushState function을 호출하여 URL의 address를 변경하고 변경 후에 root dom에 접근하여 innerHTML을 사용하여 이전 화면을 바뀐 화면으로 새롭게 교체하는 방식을 사용했습니다.

그렇다면 innerHTML function을 호출할 때 마다 리렌더링이 발생하는 문제가 있는데 왜 굳이 사용했는가 하는 의문이 들 수 있습니다. 저도 처음에 createElement와 DocumentFragment를 사용하여 최소한의 리렌더를 발생하면 되지 않을까 하는 생각을 했지만, 코드를 분석하고 보니 화면을 바꿀 때는 고정적으로 변하지 않는 화면을 제외하고는 모든 부분이 바뀌어야 한다는 것을 알게 되었고, createElement와 DocumentFragment를 사용하면 가독성이 떨어지고 막노동 같은 코드가 많이 생길 수 있다는 생각을 가지게 되었고 innerHTML의 문제점을 정확히 인지하고 사용하면 유용하게 사용할 수 있겠다는 생각에 innerHTML을 사용하여 DOM 업데이트를 진행했습니다.

위의 image의 코드에서는 Router를 사용하기 위해 중요한 두 가지 function으로 구축되어 있습니다.

첫 function은 initialRoutes를()의 동작은 처음 화면을 렌더링하기 위해서 만든 function으로 entry point(index.ts)에서 initialRoutes를 호출하면 Login page를 보여주는 기능입니다.

두 번째 function은 Router를 구축하는 가장 중요한 기능으로 pushRouter()입니다. pushRouter()는 첫 화면을 제외하고 모든 router가 이동하기 위해 거쳐야 하는 과정으로 pushRouter(pathName: string, qureyId?: string, backPageType?: cuisine|recommend)의 매개변수를 넣어서 호출하면 새로운 화면을 보여주는 역할입니다.

위의 예시 Image는 ingredient page의 일부 logic으로 다음으로 이동할 URL의 address pathName을 DOM에서 추출하여 pushRouter(url address pathName) 호출로 동작을 구현할 수 있습니다.

Router 작업을 통해 어떻게 SPA가 동작하는지 알게 되었습니다. 처음에는 History API만을 사용하여 모든 Router 작업을 수행하려고 생각했지만, 검색을 통해 Location API 같은 쉽게 URL에 접근할 수 있는 여러 가지 Web API에 대해서도 알게 되었습니다.

📖 DRY(Don't Repeat Yourself) 원칙 적용

처음 코드를 분석하면서 중복되는 코드가 많다는 생각을 가지게 되었습니다. 그래서 EMO/src/utils dir 경로에 중복되는 utils function들은 재사용할 수 있게 만들었습니다.

대표적인 중복 function으로 찜하기를 눌렀을 경우 전체 화면의 배경 화면의 opacity를 투명하게 만들고 modal을 2초 정도 띄워주는 UI를 만들었습니다. 하지만 찜하기 기능은 cuisine page, recipe page, recommed page에서 모두 사용했고 중복된 Logic을 찾아서 timeModel()으로 공통 Logic을 옮기고 과정을 거쳐서 어디서나 재사용할 수 있게 만들었습니다.

timeModel()의 UI 모습

DRY 원칙을 적용하여 획일적인 코드 스타일을 가지게 되었고, Refactoring을 하면서 아무 생각 없이 Logic을 작성하면 이렇게 중복되는 코드가 많을 수 있다는 경험을 하게 되었습니다. 중복 Logic을 제거 후 재사용할 수 있는 function을 만드는 경험을 통해 다음 Project에서는 기능 구현만을 생각하기보다 재사용할 수 있으며, 가독성 있는 Logic을 목표로 세우고 Project를 진행하겠습니다.

📖 상수에 대한 명시적인 코드 작성

EMO Project 보완을 진행할 때는 혼자서 모든 Logic에 대해서 작업을 진행하여 획일적인 코드 스타일을 쉽게 가질 수 있었습니다. 물론 위에서 설명한 DRY 원칙도 많은 도움이 되었습니다. 그러나 모든 Project에 대해서 혼자서 코드 작성을 할 수 있는 게 아니며, 언젠가는 협업을 진행해야 한다는 생각을 가지게 되었습니다. 그래서 혼자서 지킬 수 있는 협업 규칙을 정하게 되었고 명시적인 코드를 상수로 작성하는 규칙을 EMO Project에 적용하게 되었습니다.

Server 통신을 위해 사용되는 URL은 많은 Logic에서 중복되어 사용되는 점을 생각하여 따로 file을 분리하여 중복 Logic을 제거하고 수정하는 경우에는 하나의 Logic만을 수정하면 의존성을 통해 사용된 부분도 쉽게 수정할 수 있었고(DRY 원칙 적용) JavaScript의 문법 const 변수 선언으로 상수로 URL 변수를 지정하여 상수로 만들었습니다. 상수로 변수를 선언할 때 가장 중요하게 생각했던 점으로는 변수 네이밍으로 의미를 정확하게 알려 주어 다른 사람이 Logic의 흐름을 읽지 않고 변수 네이밍만으로 의미를 알 수 있게 만들었습니다.

위의 Logic은 Cuisine Page로 Number Type을 사용해야 하는 경우가 있었습니다. 처음에는 addToCartElement.style.opacity = "1"; 같이 Number를 바로 삽입하는 방식을 사용했지만, Number의 의미가 정확하지 않다고 생각하여 Object의 Property로 지정하였습니다. 그러나 문제가 되는 부분으로는 객체 리터럴의 Property는 불변이 아니면서 Private 지정도 안 된다는 문제가 있어 어디서나 쉽게 접근하여 변경할 수 있었습니다. 해결 방안을 고민하였고 TypeScript의 readonly 문법을 통해 읽기 전용으로 변경할 수 있어서 상수의 의미를 가진 Property로 만들 수 있었습니다.


🛠 보완해야 할 부분

📖 Test Logic 작성하기

2022.04.26일 기준으로 아직 저는 정확히 Test의 중요성을 완벽하게 인지하지 못하고 있습니다. 이론적으로 Unit Test, E2E Test 등의 여러 가지 Test 이론에 대해서 읽어보았고 필요성을 알게 되었고 실무에서 직접 사용을 통해 Test의 중요성을 이론적인 부분뿐만 아리나 실무적인 부분까지 느끼고 싶다는 생각에 보완할 부분에 추가하기로 선택하게 되었습니다.

특히 EMO Project에서 보완해야 할 첫 번째 순서로 Test를 선택할 생각입니다. 그 이유로는 EMO Project 보완 후 회고(2)를 시작하게 되면 새롭게 Refactoring 해야 하는 부분의 Logic을 수정하기 전에 Test를 미리 작성해 두면 더욱 쉽게 Error를 잡고, 어디에서 문제가 발생하는지를 쉽게 파악할 수 있으며, Test Logic을 작성하지 않은 경우보다 Test Logic을 작성할 때 시간적인 이점도 많이 챙길 수 있다고 생각해서 첫 번째로 보완할 점으로 선택하게 되었습니다.

물론 Test를 진행하게 되면 초기 투자 시간이 많이 들어간다고 생각하지만, 이 경험 또한 저한테 많은 도움이 될 것으로 예상하고 TypeScript에 대해서 이론만 풍부하게 알고 있던 저에게 EMO Project에 직접 적용하면서 실무적으로도 많은 도움을 받은 좋은 경험이 있으므로 꼭 처음 보완할 부분으로 선택하고 싶습니다.

📖 Json-Server ▶︎▶︎ 실제 Server로 변경하기

Json-Sever를 처음 팀원들과 Project에 도입한 이유로는 쉬운 HTTP API 사용 방법과 간단하게 DB를 구축할 수 있는 이점이 있어서였습니다. (물론 그 당시에는 BackEnd를 구축할 방법도 모르게 했습니다….) 하지만 쉽게 사용할 수 있는 이점에도 불구하고 다시 Project를 진행하면서 제한된 사용 범위로 Ajax 통신에서 비용을 많이 차지하는 방법을 차선책으로 선택하는 경우가 많았고 보안 측면인 문제도 큰 문제로 떠올랐습니다.

위의 코드 예제를 보면 Login 관련 Logic으로 Id, Password를 확인할 때마다 Server 통신을 해야 하는 문제도 발생하고, Password처럼 보안을 철저하게 신경 써야 하는 부분에는 bcrypt library 등의 hash 알고리즘으로 암호화를 하는 방식도 사용할 수 없는 문제가 발생했습니다.

이러한 여러 문제를 해결하기 위해 Node.js(Express) + Mysql(sequelize)를 사용해서 Server를 구축할 예정으로 EMO Project 보완 후 회고(2)를 통해서 수정할 예정입니다.

📖 Webpack production 환경 만들기

처음에는 위의 두 가지(Server, Test 구축) 경우만 보완하면 더 좋은 Web Application으로 만들 수 있다고 생각했습니다. 그러는 도중 Server를 구축하면 직접 Server를 배포하지 않으면 포트폴리오에서 실제 Service를 보여 줄 수 없다는 생각이 떠올리게 되었습니다.

Server 배포를 생각하다 문득 현재 Webpack의 Mode 설정이 development로 설정했다는 것을 알게 되었고, 그 결과 Webpack의 Mode가 Production일 경우에 Webpack에서 자동으로 성능 향상(최적화)을 도와주는 기능들의 도움을 받지 못하고 있다는 생각을 가지게 되었습니다.

간단하게 Production mode를 사용할 경우의 이점을 설명하면 Tree Shaking(ESM을 사용할 경우만 해당)을 자동으로 지원하며, Optimization을 모드에 따라 조건을 정하여 production mode일때 최적화를 진행할 수 있습니다. 그 외에 Plugin을 통해 production에서 불필요한 console.log() 로직을 complie 단계에서 모두 지우는 방법도 지원합니다.

위의 설명처럼 많은 혜택을 EMO Project에서는 누리지 못하고 있다는 생각을 가지게 되었고, 직접 Server와 DB를 구축하게 되면 server 배포뿐만 아니라 Front 또한 Webpack의 설정을 production에 맞춰서 Front 배포를 통해 실제 사이트를 포트폴리오로 사용할 생각입니다.

수정 예정 일자는 6월로 생각하고 예상하고 있습니다.


💻 후기

EMO-v2 Project를 2주 동안 작업을 하면서 많은 부분을 배우게 되었습니다. 특히 Vanilla JS로 모든 작업을 진행하여 JS Library, Framework에서 내부적으로 작동되는 부분에 대해서 깊이 있게 알게 되었습니다. 물론 아쉬운 점도 많이 있었습니다. 특히 가장 아쉽게 생각했던 부분으로는 Vanilla JS로 모든 작업을 진행하여서 Library와 Framework을 사용할 때보다 더 많은 자유도로 작업을 진행할 수 있어서 구조에 관한 생각 및 상태 관리에 대해서 생각할 수 있었는데 그 부분을 신경 쓰지 못했던 게 가장 아쉽게 생각이 들었습니다. 그래서 다음 Project에서는 MVC 패턴을 사용하여 상태 관리 및 객체 지향 프로그래밍을 중점을 두고 작업을 진행하고 싶다는 생각을 가지게 되었습니다.

다음 Project 또한 Vanilla JS로 작업을 진행할 예정이며 React 또는 Vue와 같이 JS Library를 사용하지 않는 의문이 들 수 있어서 간단하게 설명하면 Vanilla JS를 사용하는 것보다 JS Library를 사용하면 쉽게 자유도 또한 많이 줄어들며 다른 사람이 만든 UI Library 등을 사용하여 쉽게 UI를 만들 수 있어서 매우 편해서 빠르게 작업을 진행할 수 있으며 어느 정도의 퀄리티 보장받을 수 있다는 장점이 있어서 수익을 창출하고 빠르게 기능을 구현하는 곳에서 사용하는 게 적합하다는 생각을 가지게 되었습니다.

하지만 많은 내부 동작을 Library가 마법을 부리는 것처럼 보이는 부분에 대해서 library 사용자들은 알기가 쉽지 않습니다. 저는 Library가 마법을 부리는 부분에 대해서 많은 궁금증을 가지게 되었고 Library의 내부 코드에 대해서 찾아보니 모든 부분이 Vanilla JS로 만들어졌다는 것을 알게 되었습니다. 그래서 Vanilla JS의 중요성을 더 크게 느끼게 되었고 EMO-v2 Project를 Vanilla JS로 진행하였습니다.

EMO-v2 Project를 끝내고 나서는 Webpack의 동작 원리, React에서 SPA 동작 원리, TypeScript의 사용 방법 및 컴파일 방법, Reflow, Repaint 고려한 Logic 작성, 획일적인 코드 스타일 적용 방법과 같은 많은 부분에 대해서 알게 되었고 이러한 경험에서 배운 것에만 만족하지 않고 더 많은 부분에 호기심을 가지게 되었고 내가 아직 많이 부족하다는 것을 알게 되었고 여기서 멈춰서 뒤처지지 말고 계속해서 앞으로 나아가야 한다는 것을 깨닫는 계기가 되었습니다.

profile
게시글에 잘못된 부분이 있으면 댓글로 알려주시면 빠르게 수정 및 수용도 하겠습니다. 🥲

0개의 댓글