ECMAScript | TypeScript

FE개발자로서 못해준 이야기 1 - 프로젝트

partner_jun 2022. 1. 13. 16:34

이직하기 전에 말해줬어야 하는 내 개인적인 의견에 대해 정리해봤다.

쓰다보면 별거 없을 거 같아서 다 쓰고 공유해줄지 고민해봐야 할 것 같다.

내가 대단한 사람도 아니고 흔한 개발자 중 하나에 불과하니 이 사람은 이렇게 생각하는구나 정도로 봐 줬으면 한다.

 

FE 프로젝트에 대해

우리는 서비스를 유지보수한다. 개발은 쉽지만 유지보수는 어렵다. 왜 그럴까? 대부분의 경우 유지보수에 대한 생각 없이 개발하기 때문이다. 최근 몇 년 사이 급격하게 생태가 변했고(심지어 채용관련해서도), 상대적으로 룰이 정립되지 않은 프론트엔드에서 그 문제는 더욱 크게 다가온다. 만든지 몇 년, 아니 몇 달만 지나도 단순한 변경에 큰 리소스가 소모되기 시작한다. 나 역시 그리 많은 경험이 있다고 자신할 수는 없지만, 여러 프로젝트의 유지보수 업무를 수행하고 마이그레이션했던 경험을 통해 중요하다고 생각되는 점들을 공유해본다.

 

 

FE프레임워크를 맹신하지 말자

개발이 편하다고 FE 프레임워크를 당연스레 사용하는 경향이 있다. 심한 경우 FE 프레임워크를 사용하고는 바닐라-혹은 JQuery를 사용한 웹 페이지처럼 작동되게 만든다. 이런 경우, 프레임워크를 사용하지 않는 것보다 성능은 떨어지고 관리는 어려워진다. 나는 신규 프로젝트를 진행하기 전 아래 두가지를 먼저 고민한다.

1. SEO

FE프레임워크로 개발된 페이지를 lighthouse(=audit) 혹은 pagespeed에서 테스트 해 본 적이 있는가? 쓸만한 서비스를 개발한 직후라면 20점 언저리의 점수를 받게 될 것이다.

꽤 유명한 상업 사이트도 점수는 별볼일 없다

대부분의 SEO 분석 사이트에 따르면 (구글이 아니니 정확하진 않다) 점수가 낮은 경우 구글 검색 결과 첫 페이지에 랭크되지 못한다고 한다. 사람들이 찾아서 들어오는, 이미 유명해진 사이트라면 상관없겠지만 그렇지 않다면 이건 아주 심각한 문제다. 계속 하위 랭크(2페이지 이상)로 노출된다면 PV 상승이 어렵고, 결국 사이트가 망하게 될 것이다. 그렇다면 이 점수는 어떻게 올릴 수 있을까? 답은 단순하다. 페이지를 가볍게 만들면 된다. 첨부된 에셋, 응답 속도. 무조건 가볍고 빠르게 만들면 점수는 올라간다. FE 프레임워크를 사용했다면? 한계는 아주 명확하다. SSR을 해도 마찬가지다. 캐싱과 하이드레이션을 고려한다고 하더라도 많은 부분에서 감점이 될 수 밖에 없다.

2. 호환성

광고컨텐츠나 AMP 페이지와 같이 특정 페이지에 삽입될 수 있는 경우 호환성이 매우 떨어진다. 물론 확장될 가능성도 생각할 수 있지만 프로젝트 담당자가 이직하거나 개발 후 너무 오랜 시간이 지난 경우엔 어차피 다시 만들게 될 것이다. 그렇다고 그 상황까지 고려해서 미리 만드는 것은 더욱 바보같은 짓일 뿐이다. 서버 템플릿과 JS파일 몇개를 이용해 간단하게 구현할 수 있는 프로젝트를 FE 에코시스템에 태운다는 것은 도구를 잘못 선택하는 명백한 실수라고 본다.

 

나 역시 때론 귀찮아서, 시간적 한계로 생각 없이 FE프레임워크를 사용했던 경험이 있다. 하지만 그런 프로젝트들은 결국 시간이 지난 후 더 큰 고민을 하게 하고, 각종 수정에 시간을 더 소모하게 만들었다. 생각 없이 '우리 팀은 항상 이걸 쓴다' 따위의 멍청한 짓은 지양해야 한다.

 

 

빌드 툴을 고민하고 선택하자

Vue.js의 기본 빌드 툴은 Vue-CLI다. CLI는 웹팩 기반이지만 플러그인과 설정들로 순수한 웹팩과는 다르다. 필요한 경우에는 아직 순수한 웹팩을 사용할 수 있다. Vue.js 개발팀은 최근 Vite를 밀고 있다. 하지만 Vite는 개발환경에서 IE를 지원하지 않고, SSR 플러그인 개발이 완료되지 않은 것으로 보인다(현재 renderToHtml이 지원되지 않음). 이러한 상황에서 어떤 툴을 선택할 것인가? 그냥 vue create 명령어를 칠 것인가? 이 역시 이전 말했던 FE 프레임워크 선택과 같은 내용이다. 그냥 단순히 많이 써봐서, 유명해서 고른다는 것은 최악의 선택이 될 수 있다.

 

적절한 빌드 툴 선택시 프로젝트 유지보수 이전, 개발 단계에서도 생산성 향상에 아주 큰 도움을 줄 수 있다. 한가지 예로 FE 개발자의 숙명과도 같은 관리자 프로젝트의 경우 SSR과 IE를 고려할 필요가 없으며, 다양한 라이브러리 사용으로 청크의 크기가 비교적 커질 확률이 높다. 이런 경우 ES 모듈을 사용하는 Vite를 빌드 툴로 선택하면 개발 단계에서 기동 속도와 업데이트 속도에 아주 긍정적인 효과를 볼 수 있다. 결과적으로 개발 시간이 단축되는 결과를 얻게 될 것이다.

Vite를 사용한다면 ESM 모듈을 사용하여 기동/빌드 시간 차이가 꽤나 크다

 

또, 단순한 유지보수가 아닌, 인수 인계 단계에서도 아주 큰 이점을 얻을 수 있다. 예를 들어, React 진영의 Next.js의 경우 프록시 처리로 API서버의 역할을 위해 래핑된 것이므로 만약 프로젝트에 GraphQL, Redis Session 등 백엔드측 라이브러리를 추가하게 된다면 점점 더 복잡해지고 원형에서 멀어진다. api 디렉토리 밑에 middleware니 model이니 하는 디렉토리가 많은 것 자체가 이미 커스터마이징이 되어 버린 것이다. 이렇게 원형에서 멀어지게 되면 그 빌드 툴을 선택한 의미도 없어지고, 유지보수를 위해 프로젝트를 다시 학습해야 한다. 이렇게 된 프로젝트를 팀원 누구나(신규 입사자가) 곧바로 수정할 수 있다고 자신할 수 있겠는가? 모듈과 히스토리에 관해 하나하나 다시 설명해야 할 것이다. 심지어 신입의 코드 변경에 의해 전혀 예상치 못한 사이드 이펙트로 장애가 발생할 수도 있을 것이다.

 

 

로직을 분리해라

취업을 준비할 때, 혹은 교육받을 때 누구나 듣고 공부한 내용이지만 현업에서 생각보다 지켜지지 않고 있다. 특히 프론트엔드의 경우 이벤트 핸들링과 화면을 구성하기 위해 사용되는 로직은 명백하게 분리가 가능하다. Vue3의 compostion api와 같이 거창한 방법론을 말하는 것이 아니다. 단순히 함수를 쪼개고, 다른 파일로 분리하여 데이터 처리를 위한 로직을 어디에 둘지 룰을 정해두라는 것이다.

 

대부분의 경우 프로젝트를 생성했을 때 만든 디렉토리는 프로젝트가 종료될 때까지 삭제되지 않는다. 반대로 말하자면 프로젝트가 종료될 때까지 처음 만든 디렉토리 구조 그대로 사용한다는 뜻이다. 때문에 프로젝트의 초기 구조는 아주 중요하다. 방금 만든 디렉토리에 앞으로 10년간 수많은 사람들이 무엇인가를 넣는다고 생각해보자. 자랑스러운가? 끔찍한가? 끔찍하다면 조금 더 생각해보자.

 
로직 분리에 대한 간단한 예를 들자면, 나는 주로 MVC 패턴에 기본을 두고 데이터를 fetching하는 것은 서비스, 서비스를 로드하고 요청하는 것은 페이지 컴포넌트, 그리고 데이터를 연산하여 넣는 것은 스토어를 기본으로 잡고 정리하기 시작한다. 또, 데이터 포맷 변환를 위한 함수는 Mixin에서 작성한다. 이와 같이 프로젝트에 명확히 룰을 정해두면 유지보수가 편해질뿐 아니라 리팩토링의 목적도 명확해진다. 나는 이 형태를 레이어라고 부르는데, 이 레이어에 관해서는 다른 글에서 이어간다.

 

 

다음 개발자를 배려해라

당신은 이직할 것이다. 당신의 후임으로 들어온 개발자도 이직할 것이다. 하지만 프로젝트는 계속해서 서비스될 것이다. 나는 항상 다음 개발자를 위해 개발하려고 노력한다. 이유는 단순하다. 프리랜서 업무를 하던 시절 봐온, 많은 '망한' 프로젝트를 보았기 때문이다. 개발에 문제가 있어서 망하는 것이 아니다. 많은 개발자의 손을 거쳐간 코드들이 더 이상 파악하기 어려워졌을 때 나는 프로젝트가 망했다고 본다. 서비스는 유지해야 하지만 손 댈수가 없기 때문이다. 아무리 많이 공부했더라도, 성능 측면에서 아무리 더 나은 방법이 있더라도 '회사'에서의 프로젝트는 재미없게, 단순하게 만드는 것이 좋다고 생각한다. 누구나, 곧바로, 코드를 보자마자 이해할 수 있도록 해야 한다.

 

예를 들어 JS 진영에서 함수형인 '척'을 하기 위해 사용하는 라이브러리 중 rambda라는 것이 있다. 이름부터 느낌이 오겠지만 함수형 프로그래밍에서 자주 사용되는 함수를 미리 구현한 lodash같은 유틸리티성 라이브러리다.

rambda의 path 함수

자. 위 함수를 보자. 아래 예시 코드를 보자마자 바로 이해할 수 있었는가? rambda를 즐겨 사용했던 개발자가 아니라면 곧바로 이해할 수는 없었을 것이다. 사실 아주 단순하다. 배열로 받은 파라미터로 객체 그래프를 탐색하고 결과를 반환하는 함수다. 특정 상황에서 아주 유용하지만 코드로 처음 접한 사람은 아주 곤란할 것이다. 왜냐하면 대부분 FE 개발자에게 path는 Node의 path 모듈일테니까!

 

어떤 사람들은 '다음' 개발자의 공부가 부족해서 모르는 것이라고 생각한다. 하지만 나는 장담한다. 그런 생각을 하는 본인도 분명히 같은 일을 겪게 될 것이다. 그럼 그 때 말하겠지. "코드가 너무 쓰레기같다. 어떤 새끼가 이렇게 만들었지?"

 

 

주석을 남겨라

주석은 정보를 담은 문서다. 정보는 없는 것보다 있는 것이 유용하다. 개인적으로는 TODO나 FIXME같은 주석은 아주 싫어하지만(영원히 구현되지 않을 내용이니까) '~해서 이렇게 작성해 두었다'는 식의 히스토리성 주석은 아주 중요하다고 생각한다. 이는 다음 개발자에게 힌트가 되고, 만약 그 부분에 대한 수정이 필요하다면 '왜' 이렇게 개발하였는지를 이해하게 한다. 

나는 이런 형태의 주석을 작성한다.

어떤 사람들은 주석이 길다고 싫어한다. 하지만 해외의 유명한 오픈소스 프로젝트는 모두 주석이 길다. 그런 사람들은 본인이 해외의 유명 개발자들보다 더 뛰어난 개발자일테니 주석이 필요 없겠지만, 대부분의 평범한 개발자에게는 주석은 큰 도움이 된다. 이미 알고 있는 내용이라면 다시 확인하여 안심할 수 있고, 모르는 내용이라면 헛수고를 덜게 될 테니까.

 

 

패턴을 고민해라

줌 인터넷에서 근무할 때, 비디오 플레이어를 개발할 일이 있었다. 기획 단계부터 내가 계속해서 주장했던 내용이 있다. '비디오 플레이어는 일종의 상태 머신이니 State machine 패턴을 사용해야 한다. 그래야 앞으로 유지보수가 가능하다.' 하지만 담당하던 개발자는 단순한 함수 뭉치로 개발하였고 어느 정도 유지보수를 진행하던 중 퇴사해버렸다. 퇴사한 이유를 내가 알 수는 없지만, 유지보수 작업에 어려움이 있었으리라는 것은 충분히 예측할 수 있다. 왜냐하면 기획 단계에 없던 영상 중간 광고가 추가되었기 때문이다.

 

상태 기계 패턴은 사실 게임 업계에서 주로 사용한다

 

개발자와 디자인 패턴의 관계는 참 이상하다는 생각이 든다. 신입 티를 벗어가는 개발자(2~3년 언저리?)는 디자인 패턴에 목숨을 걸기 시작한다. 듣도 보도 못한 패턴부터 유명한 패턴까지 모두 섭렵하여 여기저기 적용하기 시작한다. 악마의 서적인 토비의 스프링 때문인지, 아니면 선배들의 저주가 그들을 그렇게 만드는 것인지는 모르겠지만, 그렇게 패턴을 발라대기 시작하던 개발자는 금새 퇴사한다. 그리고 그 프로젝트를 이어받은 개발자들은 유지보수에 어려움을 겪고 고통스러워한다. 고통스러운 경험을 한 개발자와 디자인 패턴을 마구 발라 프로젝트를 망쳐본 개발자는 디자인 패턴을 아주 혐오하기 시작한다. 패턴의 p만 붙어 있어도 화를 내며 모두 지워버린다.

 

나는 디자인 패턴은 소화기라고 생각한다. 디자인 패턴은 대부분의 경우 쓸모가 없다. 서비스는 대부분 그렇게 복잡하지 않고(사실 CRUD뿐이다) 위 구문에서 적은 '다음 개발자를 배려'하지 않는 코드가 될 확률이 높기 때문이다. 하지만 위에서 든 예시처럼 어려운 문제를 정말 쉽게 해결할 수 있는 경우가 한번쯤 올 것이다. 그런 상황을 준비만 해 두자. 불이 났을 때 사용할 소화기처럼.

 

 

보수적으로 타입스크립트를 사용하라

타입스크립트는 자바스크립트의 슈퍼셋이다. 슈퍼셋이지 상위 언어가 아니다. 심지어 다시 자바스크립트로 컴파일해야 실행할 수 있다. Deno가 자리잡지 않은 현재, 타입스크립트로 모든 코드를 작성하는 것은 매우 비효율적이다. 나는 그 이유로 크게 두가지를 든다. 첫번째, 타입스크립트는 느리다. 당연한 것이다. 이전 스칼라를 공부할 때도 느낀 것이지만, 타입 추론이라는 것은 아주, 끔찍하게, 굉장히 무거운 작업이다. 아무리 CPU의 성능이 좋아졌다고 하더라도 상대적으로 무거운 작업인 이상 느려지는 것을 피할 수는 없다. 이렇게 느려진 속도는 개발 생산성에 영향을 줄 것이다. 두번째, 자바스크립트의 자유로움을 해친다. 자바스크립트는 자유롭다. 자유라는 것은(늘 그렇듯) 본인의 책임이 필요한 것이다. 책임을 질 수 없다고 아예 막는 것은... 이 곳에 어울리지 않는 방식이다. 하지만 사내에서, 팀내에서 타입스크립트를 사용하면 딱딱한 형식, '책임'을 강요할 수 밖에 없다. '타입'이라는 특성이 그렇기 때문인데, 그래서 나는 앞서 말한 MVC를 기반으로 한 아키텍처 레이어 중 '서비스' 레이어에만 타입스크립트를 사용하는 것을 권장하는 편이다. 'API부터 데이터를 가져온다'는 작업 특성상 명확하게 타입을 지정할 수 있고, IDE는 타입스크립트 파일에서 정의된 타입도 그대로 추적해주기 때문에 자바스크립트 파일에서도 해당 형식을 참조할 수 있다. 타입스크립트를 어떻게 사용할지는 프로젝트의 특성에 따라도 달라진다. 하지만 타입스크립트는 '무조건' 사용하는 것이 아니라, '어떻게' 사용할 것인지에 대해 고민해야 한다고 본다.