Css 대통합/리팩토링 대작전, 작전명 : 갈아엎기 (회사경험담-)
스파게티 코드라고들 하시죠? 저는 비빔밥 코드를 마주 했습니다. 재료 하나하나 분리해봤어요.

이 집, 비빔밥 맛(없)집이에요.
회사에 들어와 코드를 들여다 보니 상당히 어질어질한 상태였다. 템플릿을 활용해 그를 바탕으로 개발된 탓인지 프로젝트 전반적으로 활용되지 않는 코드들이 많았고, 특히나 CSS 코드들이 글로벌에만 7만줄에 육박하는 등 상당히 많은 리소스를 잡아먹고 있었고 이는 대부분이 부트스트랩 Utility CSS 혹은 부트스트랩 컴포넌트를 위한 것들이었다.
그래서 이를 과감히 쳐내는 작업을 하고자 생각하였는데, 그렇다면 이런 생각을 다들 할 것 같다.
굳이 멀쩡히 잘 만들어져 있는 부트스트랩을 제거해야하는거야? 그건 비효율적인 거 아닐까?
이 부분에 대해서는 적극적으로 동의한다. 굳이 잘 활용되고 있는 코드를 꽤 큰 비용을 들여가며 리팩토링/마이그레이션해야 할 이유는 없다고 생각한다. 하지만 활용되고 있는 코드보다 활용되지 않는 코드가 훨씬 더 많았다.
앞서 언급한 것처럼 70,000줄이 넘는 CSS코드가 글로벌 위에 올라가 있었고, 부트스트랩 컴포넌트, 부트스트랩 유틸리티 CSS 뿐만이 아닌, SCSS, styled-components, CSS, styled-jsx, MUI 등 수많은 스타일링 도구들이 혼재해 있었다. 이는 성능에도 지독한 영향을 줄 수 밖에 없어 UX적으로 좋지 못했고 그 부분을 넘기더라도 추후 유지보수를 하거나 새로운 기능들을 추가할 때 효율적인 개발이 불가능할 것으로 보였다.
부트스트랩 컴포넌트를 활용하면서 발생한 심각한 네스팅과 utility CSS의 사용으로 인한 클래스네임 복잡도 등이 기본적인 레이아웃을 파악하는 것 조차 어렵게 만들었다. 아래와 같은 상태의 코드들이 수십, 수백개의 파일에 나뉘어져 있다니 기초적인 레이아웃을 파악하는 것도 쉽지가 않았다.

그런 이유로 CSS 대통합 및 코드 리팩토링을 중심으로 작업하기 시작했다. 이른바 작전명 불도저(…맞나?).
결과적으로는 추가적으로 페이지를 작업하고, 기능들을 개발하면서 만 두달의 시간을 소요해서 어느정도 윤곽이 보이는 정도로 까지는 작업을 했다. (일단 모든 CSS를 SCSS으로 통합 완료했다.)
그 작업들을 하면서 느꼈던 것들, 경험했던 것들을 작성해보고자 한다.
애증의 부트스트랩
처음 회사에 면접을 갔을 때, 템플릿을 기반으로 작업 중이라는 얘기를 들었다. 그 때까지만 해도 템플릿의 개념이 디자인 템플릿을 활용하여 가이드를 잡고 개발을 하는 것인 줄 알았으나, 실제 직면해보니 디자인 템플릿이 아닌 붙트스트랩 템플릿 코드를 수정해서 작업을 하고 있다는 의미였다. 결코 나쁜 선택은 아니라고 생각한다. 회사에 프론트엔드 개발자가 없다면 템플릿을 활용하는 것이 효율적일 수 밖에 없고 촉박한 개발일정을 맞출 수 있는 길이니까.
지금의 프로젝트도 아마 처음에는 촉박한 MVP 생산을 위해서 템플릿을 기반으로 만들어졌을 것이 뻔하다. 하지만 이게 외려 추후의 유지보수를 고려하면 독이 되지 않을까 생각이 들었다. 부트스트랩을 활용해본 적이 없었고, 부트스트랩을 접한 게 지금이라 그런 지는 모르겠으나 위의 네스팅 코드만 보고도 아 이건 리팩토링을 우선적으로 잡고 작업해야겠구나 하는 생각이 들었다.
부트스트랩 걷어내기 1단계 : 컴포넌트 분리
추상화된 컴포넌트를 활용하는 선언형 프로그래밍의 최대 장점은 코드를 읽기 편하다는 점과 재사용하기 편하다는 점이라고 생각한다. 하지만 기존의 코드는 재사용성이 전혀 고려되지 않고 컴포넌트를 추출하지 않는 등 한 파일의 코드 줄이 400-500줄 이상의 혼잡한 상태였다. 거기에 네스팅마저 깊어지니 어디를 손봐야할 지가 어려웠다. 그래서 컴포넌트를 먼저 추출하기로 했다.
당장 기능 또는 UI를 추가해 작업해야하는 페이지를 중심으로 먼저 리팩토링을 시작했는데, 메인페이지를 기준으로 11개의 컴포넌트만 존재하던 것을 40-50개의 컴포넌트로 분리하며 공용으로 사용할 것과 한정된 부분에서 사용할 것으로 나누었다.

부트스트랩 걷어내기 2단계 : 분리한 컴포넌트의 부트스트랩을 제거하기
분리한 컴포넌트의 부트스트랩 컴포넌트를 모두 html 태그로 변경하고 class로 붙은 유틸리티들을 모두 제거했다. 중첩된 과 , 등으로 복잡도가 높지 않은 컴포넌트 임에도 10단계 중첩을 보여주던 어질어질한 현기증 코드가 깔끔하디 깔끔한 날 것 그대로의 CSS로 변모하는 모습에도 왜인지 마음이 편안해졌다.
그 뒤로는 별 것 없이 컴포넌트 단위로 스타일링을 기존과 <동일하게> 해주었다. 다행이도 컴포넌트 분리를 하면서 구조적으로 어느 정도 파악을 해둔 상태여서 그런 지 크게 어려움 없이 스타일링이 가능했는데, 문제라면 대체 어디가 부모컴포넌트인 지 모를 깊은 뎁스의 향연때문에 파악이 어려워 레이아웃이 어긋나는 상황이 발생했다. 이를 해결하기 위해서 컴포넌트 최상단(페이지)에 기본적인 레이아웃을 잡아주기 위한 컴포넌트를 추가를 해줬다.
아무래도 기존에는 페이지 단위로 스타일링이 추가로 되어있어 관리가 어려웠던 CSS를 컴포넌트 단위로 관리를 해주니 유지보수에 이점이 있을 뿐만이 아니라 이전 배포된 UI를 동일하게 잡아내는 것이 확실히 용이했다.
사실 이까지만 해줘도 충분히 제 역할을 다 하는 코드들이라고 생각했지만, 성능상의 이슈도 그렇고 어디선가 잡히지 않는 CSS디버깅을 위해서 한가지 단계가 추가되어야 했다.

부트스트랩 걷어내기 3단계 : global에 선언된 CSS 모두 날리기
CSS 코드가 77000줄 가량 존재하는 global은 다양한 !important를 내포하며 개발자가 의도한 대로 UI를 그릴 수 없게 만들었다. 물론 그 위에서 부터 작업을 한다면 그러려니 하고 계속 개발해나가면 되겠지만 또 다른 문제가 있었다. 바로 성능 최적화에 대한 이슈였다.
아무래도 사용되지 않는 CSS코드들이 같이 빌드되다보니, 또 그 코드양만 해도 77000줄에 육박하다보니 라이트하우스를 기준으로도 그렇고 굉장히 성능적으로 느리게 느껴지는 모습을 보였다.
77000줄이 된 이유는 템플릿의 모든 CSS import들을 끌어안은 채 빌드가 되어서였는데, 사실상 99퍼센트의 임포트는 필요없는 것이기 때문에 정리해주고 리셋 CSS 정도만을 설정해주었다.
이걸 날려주니 역시나 레이아웃이 망가지는 일들이 벌어졌는데, 앞서 선행된 작업을 통해 대부분은 영향을 받지 않았기 때문에 영향 받은 부분만 골라서 간단히 수정가능했다.
근데 그러면 처음부터 다시 작업하는 게 더 빨랐던 거 아니야?
맞다. 사실 그게 맞을 거 같다. 하지만 추가로 기능을 구현하는 상황에서 아예 다 날리고 시작하면 그 사이에 공백은 어떻게 할 것인가 ㅠ. 개인 사이드 프로젝트였으면 (애초에 이렇게 안했겠지만) 이미 다 날리고 다시 시작했을 것 같다. 하지만 회사의 프로덕트는 그것이 안되니 애초에 잘 작성이 되어있길 바라는 수 밖에 없으나, 대부분의 회사나 조직에서 그러기란 쉽지 않을 듯 하다. 그러니 분석하고 해석해서 최적의 상태로 만들어 낼 수 있는 능력이 중요시 되지 않을까?
숨은 복병은 styled-jsx 와 styled-components
왜인지는 모르겠으나, styled-jsx와 styled-components도 병행해서 쓰여 있었다. 조금이면 모르겠는데 꽤 많은 곳에서 사용이 되고 있어서 부트스트랩 컴포넌트, 부트스트랩 유틸리티 CSS, styled-jsx, SCSS를 동시에 통합하는 과정도 꽤나 많았다. 이래서 프로젝트의 스펙을 정하고 접근하는 것이 좋구나 하는 생각이 들었다. 차라리 한 가지 도구만 다른 도구로 마이그레이션하는 경우에는 변수가 크게 없고 복잡도가 높지 않았을텐데, 이런 드문드문 꽤나 보이는 CSS IN JS 덕분에 더 많은 시간이 소요된 것 같다.
세종대왕님이 사랑하는 한글, 컴포넌트 명으로 활용하겠습니다.

사용법이나 법률안내 등을 위한 가이드 페이지가 있다. 이 가이드 페이지는 하드코딩으로 관리가 되는데 컴포넌트로 분리해둔 각각의 내용들을 이름 짓기에는 내 영어 능력치가 한계가 있었다. 심지어 나 뿐만이 아니라 다른 사람들도 “디지털자산의 증권 여부 판단원칙”이나 “토큰 증권의 발행 유통 규율체계 정비방향” 따위를 영어로 적어두면 컴포넌트를 클릭해 파일을 확인한 후 내용을 보고 유추할 것이 뻔하다고 생각했다.
그런 이유로 이 가이드 페이지에 한해서 한글 컴포넌트명을 활용해보기로 했다. 한글코딩에 대한 부정적인 여론도 있지만 결국 좋은 개발의 핵심은 활용성, 사용성에 있지 않을까? 영어로 모든 것을 작성하는 것은 생산성에 지대한 지장을 미칠 것이라는 생각을 했다. 가령 개발자들의 케케묵은 말들 중에 하루의 절반은 변수명을 고민하는 것에 있다고 하질 않던가? 영어로 작성하는 것이 관행에도, 또 눈에 낯설지 않은 점 등에도 여러모로 좋을 수 있다고 생각하지만 (또 글로벌한 개발환경에도.) 아무튼 간에 이 프로덕트의 코드를 접하는 또 다른 개발자가 헤매이지 않았으면 했다.

이런 생각에 대표님을 통해 승인을 받고 한글로 컴포넌트를 작성했다. 한결 편안하게 확인하고 수정사항을 반영할 수 있는 형태라고 생각했다. 단순히 컴포넌트명만을 한글로 했을 뿐이지만 익숙한 언어의 등장에 체증이 내려가는 느낌도 들었다. 관행을 핑계로 효율을 저버리는 일은 굳이 할 필요 없지 않을까?
그 외
모아라 타입, 인터페이스.
타입도 한 곳에서 관리가 되지 않고 있었다. 대략 5-6개의 폴더 위치에 나뉘어져 관리가 되고 있었는데, 그 때문에 통일한 타입이 여러번 지정되어 있어야 하는 번거로움이 있었다. 리팩토링을 하며 이를 자연스럽게 루트 type폴더로 한 곳에 모아 관리를 하도록 했다. 사실 너무 당연한 구조이지만 이런 당연한 구조도 이루어지지 않은 상태였다. 눈물.

사용하지 않는 패키지 그리고 import 제거하기
템플릿을 활용해서 그런 지 설치된 패키지의 수가 80여개 가량이 되었다. 이중 50여개는 사용하지 않는 패키지 였는데, 프로젝트를 보고난 후 제일 먼저 사용하지 않는 패키지를 줄이는 작업을 했다. 일일이 사용 중인 지 의존성이 있는 지 확인하고 제거를 하니 한결 프로젝트가 가벼워졌다. 또한 사용 중이지 않거나 혹은 무분별하게 정렬되어있는 import 문도 정리하거나 카테고리화하여 정렬하는 과정을 거쳤다. 이를 통해 얻어낼 수 있는 성능 향상은 미비하겠으나 개발자가 코드를 파악할 때에는 정리되어 있는 편이 좋으니 굳이 시간을 들여서 정리했다. 이 노력이 추후 유지보수에 도움이 되길.

마치며
사실 이렇게 열심히 리팩토링을 했다고 해도 내 실력이 미천한 것과 또 일정을 맞추기 위한 빨리빨리 정신 때문인 지 내가 리팩토링을 한 것들도 다시 한 번 보고 리팩토링 해야하는 비효율이 발생하고 있다. 그 때문인 지 초기 설계에 대해서 얼마나 중요한가를 뼈저리게 느끼게 된다. 물론 탄탄한 설계 위에서도 시간이 흐름에 따라 많은 비효율이 발생하겠지만 훨씬 더 빠른 대응이 가능할 것 같다는 생각이 든다.


![[트러블슈팅] 서버를 터뜨린 쟈그마한 함수](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1748357643167%2Ffc68d237-0bfe-4f79-8e28-15fd98c5710d.png&w=3840&q=75)
![[기술 서적 후기 및 요약] 쏙쏙 들어오는 함수형 코딩](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1743129459556%2F14a7d741-d22e-4622-98e4-1857e449821e.png&w=3840&q=75)
![[Daily Flow 1.] Validator 리팩토링](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1741161717995%2Fa62693a8-0f24-4dc9-8d80-cefe541ed663.png&w=3840&q=75)