하나의 마일스톤이 끝난 뒤
기능 개발에 집중하느라 바빴던 스프린트가 끝나고, 하나의 일정이 마무리된 후 리팩토링 기간을 가졌다. 이번 개발에서 아쉬웠던 점은 크게 3가지 정도가 있었는데
- 디렉토리 체계의 미비
- 지역 상태와 전역 상태 관리 간 명확한 흐름이 없음
- 명확한 주 기술 없이 레거시로 남아 있던 CSS 라이브러리의 남발
이번 리팩토링 기간에 이 모든것을 다 해결하고, 확장성을 가져가며, 추후 계속 추가될 기획에도 바로 대비할 수 있도록 하는게 목표이다.
디렉토리 체계의 미비
사실 회사코드를 너무 많이 보고 건들이지 않은 곳이 없어서, 어디에 어떤 기능, 컴포넌트들이 있는지 알고있긴하다. 지금은 괜찮긴 하더라도, 추후 들어올 동료 개발자가 보거나 점점 코드가 많아질때 언젠가는 보물찾기를 해야할 상황이 올 수도 있기 때문에 우선적으로 대비하기로 했다.
예전 포스팅에서, 아주 잠시 언급하고 넘어간 적이 있긴하다.
Vience Canvas라는 전체 통합 서비스에서는 논코딩툴
/ AI 트레이닝
/ DRIVE
서비스 등 모두 연계되지만, 각각 따져보아도 하나의 독립적인 서비스가 될 수 있다. 하지만, 이 서비스들은 서로 너무 복잡하게 코드들이 엮여 있었고, 그것이 공통컴포넌트를 쓰기 위함이라기 보다는 여러 개발자들이 이전에 거쳐서 만들었기 때문에 각자의 컨벤션이 모두 담겨있는 이유였다.
그래서 우선은, 이런 상황을 라우터별로 따로 분리를 하였고, 그중에서 공통적으로 사용가능한 부분들에 대해서는, 최대한 활용하려 common
에 모두 적용시켰다.
이게 디렉토리 체계를 잡기전, 가장 먼저 해야할 일
이 중에서, workspace의 경우에는 FSD 아키텍쳐로 가져갔다. rete라이브러리를 커스텀 하는 과정에서, 초기에 class로, 노드들의 데이터들이 정의가 되어져있으며, 각각의 사이드 패널이 사실상 하나의 큰 서비스가 될 수 있었기 때문에 적합한 요소였던 것 같다.
추가로, 위의 사진은 rete 로직의 대부분을 제외하고, 노드 수준에서의 시각화를 보여준 것이며, rete까지 포함을 시키게 된다면,
더 많지만, 간단하게는 위의 과정을 모두 포함하는 큰 서비스이다. 즉, rete 라이브러리를 커스터마이징 하면서, 추가되는 rete만의 상태와, 각 노드들의 지역상태, 그리고 이 사이를 동기화 시키는 전역 상태만 해도 3가지를 모두 일관성있게 관리해야했다. 또한 하나의 노드가 하나의 각각의 페이지를 가지고 있고, rete 관리 창또한 하나의 페이지가 되기 때문에 일반적인 구조로는 가져갈 수 없었다.
그 중에서, FSD를 선택하게 된 이유는, 다음의 이유가 있었다.
기능별로 모듈을 명확히 구분하여, 유지보수성과 확장성을 높이는 데 최적화되어 있다. 예를 들어, features는 비즈니스 로직을, entities는 비즈니스 데이터를, widgets는 재사용 가능한 UI 컴포넌트를 담당하도록 역할을 나눈다. 이를 통해 각 노드별로 다른 기능을 별도의 슬라이스로 관리할 수 있으며, 기능별 디렉토리 구조로 그룹화하여 의존성을 최소화할 수 있다. 또한, 내부적으로는 세부 기능 단위(세그먼트)로 다시 나누어 관리함으로써 복잡도를 줄인다.
실제 workspace 서비스에서는 rete를 최상위에 두고, 이를 features 내 하나의 서비스로 설계하였다. 덕분에 각 기능이 독립적으로 동작하면서도 필요한 경우 쉽게 조합할 수 있으며, 특정 기능의 변경이 다른 부분에 미치는 영향을 최소화할 수 있다. 이런 구조는 서비스의 규모가 커져도 안정적으로 확장 가능하도록 만들었다.
그래서 최종적로 이렇게, rete 로직과, 노드들의 로직을 분리시켜 구조적인 개선에 성공하였다.
지역 상태와 전역 상태 관리 간 명확한 흐름이 없음
workspace에서는 관리해야 할 상태가 세 가지 있다. rete 상태, 리액트 상태, 전역 상태이다. 그런데 rete의 특성상 가장 먼저 실행되며, 변경 사항이 발생하면 엔진이 재가동된다. 이 과정에서 전역 상태가 이를 제때 최신화하지 못하면, rete의 작업이 끝날 즈음에 전역 상태의 값 변경이 먼저 완료되어 버려, DOM에서 불일치가 발생할 수 있다.
예를 들어, 특정 노드 데이터가 rete에서 변경되었지만 전역 상태와 동기화가 늦어져, 화면에는 이미 변경된 값이 반영되었는데 실제 엔진 상태는 이전 값으로 남아있는 경우가 생길 수 있다.
이 상세 내용은, 추후 따로 블로그를 작성할 계획이다.
그래서 결론은, 디버깅을 위해서라도 이 상태들의 흐름을 추적할 필요가 있었고 최대한 단방향으로 흐르도록 적용시켜야 했다. 그리고 이전에 회사 상태를 Zustand로 바꾼일이 있었고,
Zustand는 Flux 아키텍처 기반의 특성을 갖고 있어 상태의 흐름을 한 방향으로 흐르게하기 좋았다. 이를 활용하면 rete 상태 → 전역 상태 → 리액트 상태로 이어지는 명확한 데이터 흐름을 만들 수 있어, 상태 불일치 문제를 최소화할 수 있었다.
workspace는 FSD 아키텍처를 기반으로 설계되었기 때문에, 기능별로 모듈화할 수 있었다. 이를 통해 상태 관리 로직 역시 각 기능 단위로 독립적으로 배치할 수 있었고, 불필요한 의존성을 줄이고 있었다. 여기에 전역 상태로는 Zustand를 사용해 Flux 패턴을 구현하고, 지역 상태 대부분은 Reducer로 관리하는 방식을 결합했다.
이런식으로, 현재 custom processing에 대한 노드의 지역 상태를, 단방향으로 마들기 위해서, 여러 기준으로 분리했을때 제일 적합한 패턴을 설계했었다.
Reducer는 모든 상태 변경을 명시적인 action을 통해서만 처리하기 때문에, 디버깅 과정에서 전역/지역 상태 모두 단방향 흐름을 갖도록 통일한 덕분에, 상태 변경의 예측 가능성이 높아졌고, 기능 추가나 리팩토링 시에도 기존 동작에 영향을 최소화할 수 있었다.
결과적으로, FSD의 모듈화, Zustand의 Flux 기반 전역 상태 관리, Reducer를 통한 명시적 지역 상태 관리라는 세 가지 요소가 결합하여, 복잡한 상태 동기화 문제를 안정적으로 해결하고, 장기적인 유지보수와 확장성까지 확보할 수 있었다.
명확한 주 기술 없이 레거시로 남아 있던 CSS 라이브러리의 남발
스타일드 css, 인라인 css, styled-component등이 scss등이 모두 사용되어있었고, 모듈화를 하는 과정에서, 레이아웃을 담당하던 스타일이 하나라도 삭제된다면, 틀이 다 깨지는 현상이 있었다. 그래서, 기준이 되는 css라이브러리가 필요했고, 그 기준에서는 제일 중요한건 쓰기 편한 것
이었다.
다른 부가적인 이유도 있긴했지만 기능개발과 최적화적인 요소에 더 집중을 해야했고, css의 경우에는 새로 학습하기 보다는 통일성이 중요시 했기 때문에 신속한 개발을 위해서 Tailwind를 사용했다.
그리고, 예전 유튜브로 강의를 할때 이렇게 Tailwind에 대해서 이야기를 한적이 있었는데, 회사 상황과 어느정도의 유지보수, 컨벤션등에 적합하다고 판단되었기 때문에 온보딩때 이 영상을 재생해서, 금방 메인 기술로 선택될 수 있었다.
이때, UI버그나, 다크모드 그리고 메인 색상등도 모두 정의하고 개선하였다. 특히 반응형 작업도 중간에 계속 빠르게 수정할 수 있었다.
한 달 동안 진행한, 3가지 리팩토링이 이후 개발 속도를 빠르게 끌어올리는 전환점이 되었다.