Froxy는 개구리를 뜻하는 ‘Frog’와 ‘Proxy’의 합성어로, 사용자가 직접 코드를 실행하지 않고도 결과를 빠르게 확인할 수 있는 서비스입니다. 🐸💻
Gist에서 코드를 복제하고 실행 환경을 설정하는 번거로움 없이, Froxy와 함께라면 폴짝! 뛰어넘어 간편하게 코드를 실행하고 결과를 확인할 수 있습니다. 다양한 기능을 통해 코드를 테스트하고 실행 결과를 즉시 확인해 보세요!
부스트캠프 챌린지 과정에서는 매일 도전 과제를 수행하며, 동시에 그룹원들의 과제를 Gist를 통해 확인하고 피드백하는 시간을 가집니다.
이 과정에서 캠퍼들은 Gist 경로를 찾아 로컬 환경에 클론(clone)한 뒤 실행하는 일련의 과정을 반복하게 되며, 특히 익숙하지 않은 도구를 사용하면서 이를 수행할 때 여러 가지 개발 환경 문제를 겪게 됩니다.
Froxy는 이러한 반복적인 코드 확인과 실행 과정을 보다 간편하고 효율적으로 지원하기 위해 만들었습니다. Froxy는 캠퍼들이 실행 환경에서 발생하는 문제를 줄이고, 코드 리뷰와 피드백에 더 집중할 수 있는 환경을 제공합니다. 이를 통해 캠퍼들이 과제 수행과 코드 리뷰에 있어 생산성을 높이고, 학습 과정에 더 몰입할 수 있도록 돕는 것이 Froxy의 목표입니다.
사용자의 Gist 코드를 쉽고 빠르게 게시할 수 있게 만들었습니다.
다른 캠퍼가 올린 Gist를 빠르게 찾을 수 있습니다.
코드의 입력값 제공해 빠르게 실행할 수 있습니다.
Froxy의 프론트엔드에서는 서버 데이터를 효과적으로 UI로 전달하는 것이 핵심 과제였습니다. 이를 위해 아래와 같은 기술적 도전에 집중했습니다.
- Tanstack Query를 사용해 서버상태를 관리하고 있었기 때문에 각 도메인마다 구조화된 QueryKey가 필요했습니다.
- 이를 위해, API 계층에서 사용하는 fetch 함수를 인자로 받아 QueryKey와 QueryFunction을 함께 동적으로 생성하는 QueryKey Factory를 구현했습니다.
- 이를 통해 프론트 코드 전역에서 구조화된 QueryOption들을 선언적으로 재사용할 수 있었습니다.
- 프론트엔드 코드의 유지보수성을 높이기 위해 계층화된 아키텍처를 도입했습니다.
- 각각의 계층(API, Query, Hook, UI)를 통해 추가 요구사항이 생겼을 때 필요한 코드를 계층으로 분리해 독립적으로 개발할 수 있었습니다.
- 또한 도메인 모델을 설계해 각각에 도메인에 필요한 비즈니스 로직을 캡슐화해 UI에서 불필요한 비즈니스 로직을 선언하지 않고 UI로직만 관리할 수 있도록 했습니다.
sequenceDiagram
participant UI
participant Hooks
participant Query
participant API
UI->>Hooks: useCustomHook 호출
Hooks->>Query: 데이터 쿼리 요청 (fetch or mutate)
alt Cache HIT
Query->>Query: 캐시 데이터 반환
Query-->>Hooks: 도메인 Model과 쿼리 옵션 전달
else Cache MISS
Query->>API: HTTP 요청 전송 (Axios, fetch 등)
API-->>Query: 응답 데이터 반환 후 Model로 래핑
Query-->>Hooks: 도메인 Model과 쿼리 옵션 전달
end
Hooks-->>UI: 도메인 Model과 상태 전달
UI->>UI: UI 업데이트
- MSW를 이용해서 백엔드의 API 개발이 완료되지 않은 상태에서 API 호출과 관련된 시나리오를 테스트할 수 있었습니다.
- MockRepository를 이용해 요청 조건에 따라 데이터를 동적으로 응답하도록 구현했습니다.
- 이를 통해 인증이 필요한 요청에 대한 로직이나 tanstack query를 미리 적용해보고 테스트해볼 수 있어서 나중에 실제 API를 연결할 때 빠르게 진행할 수 있었습니다.
로딩 시 Fallback UI |
에러 시 Fallback UI |
- 리액트를 선언적으로 사용하기 위해서 로딩 상태는 Suspense가, 에러 상태는 ErrorBoundary가 관리하도록 역할을 분리하고자 했습니다.
- Layout Shift 문제 방지와 사용자 경험 개선을 위해서 Skeleton UI를 사용해서 로딩 시 fallback UI를 구현했습니다.
- ErrorBoundary와 tanstack query의 useQueryErrorResetBoundary() 훅을 이용해서 오류 발생 시 재시도가 가능하도록 에러 fallback UI를 구현했습니다.
- 쉘을 이용한 방법보다는 nest에서 직접 docker를 관리하고자 했습니다.
- git clone, image build보다 빠른 속도를 위해 컨테이너에 직접 파일을 parsing, 삽입하도록 구현했습니다.
- 컨테이너와 소켓을 통해 입출력 결과를 반환할 수 있습니다.
- queue를 이용해 요청이 순차적으로 처리되도록 했습니다.
- container pool을 직접 관리하여 리소스 사용률을 감소시켰습니다.
graph LR
API[API 요청] -->|요청 추가| RedisQueue[Redis Queue]
RedisQueue -->|작업 요청| DockerService[Docker 서비스]
DockerService -->|컨테이너 요청| Pool[컨테이너 Pool]
Pool -->|할당된 컨테이너| Container[컨테이너]
Container -->|작업 실행| Task[js 실행]
Task -->|결과 반환| Container
Container -->|컨테이너 반납| Pool
Container -->|작업 결과| Response[API 응답]
DockerService -->|결과 반환| RedisQueue
- GitHub 공식 client Octokit 모듈 사용이 nest와의 호환성 문제로 인하여 REST API를 통해 모듈을 직접 구현했습니다.
- 이때 type-safe한 환경을 만들기 위해서 응답과 요청에 대한 type 추론이 가능하도록 설계했습니다.
- 이는TypeScript의 장점을 최대한 활용할 수 있도록 dto로 파싱하여 응답을 필터링하고 유효성 검사를 할 수 있게 되었습니다.
- update 함수를 쓰는 과정에서 다대다 관계의 데이터는 관계 테이블을 통해 연결되기 때문에, 직접 필드로 접근해 조건을 걸 수 없는 문제를 발견했습니다.
- 다대다 관계를 사용하는 repository에서 update 사용 시, 쉽게 보이는 오류이며 save로 임시로 오류를 막았으나 find 및 save로 인한 원자성 해침을 막기 위한 방침이 필요했습니다.
- 또한 tag 미사용 시 데이터를 자동으로 삭제하는 기능을 위해서, tag-lotus relation 테이블을 추가하여 one-many 관계로 분리하였습니다.
분류 | 기술 스택 |
---|---|
공통 |
|
프론트엔드 |
|
백엔드 |
|
패키지 매니저 |
|
배포 |
|
협업 |
김민우 | 이나경 | 김현지 | 문준호 |
FE | FE | BE | BE |