Assistfit
프론트엔드 개발자
프론트엔드 팀을 리딩하며 피트니스 CRM 기능 개발 및 유지보수 진행
주요 프로젝트
- Radix 기반의 디자인 시스템과 스토리북을 통한 문서 시스템 구축
기여도: 100%
- 잘못된 아키텍처와 인프라 문제를 진단 및 개선
기여도: 100%
- SSE 기반의 실시간 출석알림 기능 개발
기여도: 100%
- 앱 결제 상품의 상태에 따른 환불 기능 개발
기여도: 100%
사용한 기술
출석알림 기능
SSE 기반의 실시간 출석알림 기능
디자인 시스템 & 스토리북
Radix 기반의 디자인 시스템과 스토리북을 통한 문서 시스템 구축
Swit
프론트엔드 개발자
다양한 플랫폼(웹/앱)을 지원하는 채팅/칸반 기반의 글로벌 협업 서비스 개발
주요 프로젝트
- 프로젝트 기능 개발 및 유지보수
기여도: 100%
- 리팩토링을 통한 코드 품질 개선
기여도: 90%
- LLM을 통한 채팅 서비스 개발
기여도: 30%
사용한 기술
Swit 프로젝트 관리 기능
모든 프로젝트의 업무 뷰어
Swit 업무 상태 관리
업무 상태 변경 및 관리 기능
Swit 칸반 보드
상태/버킷/담당자 기준의 칸반보드
Swit 대시보드 뷰
프로젝트 진행 상황을 한눈에 볼 수 있는 대시보드

Swit 캘린더 뷰
일정 관리를 위한 캘린더 인터페이스

Swit 리스트 뷰
업무 목록을 상태별로 관리하는 리스트 뷰

Swit 타임라인 뷰
프로젝트 일정을 시간순으로 확인할 수 있는 타임라인

Wins
웹 개발자
AI 기반 네트워크 관제 시스템 웹 파트 개발
주요 프로젝트
- AI 기반 관제시스템 웹서버 개발
기여도: 100%
- AI 기반 관제시스템 UI 개발
기여도: 80%
사용한 기술
ESE
플랫폼 개발자
시설물 통합 관제 시스템 및 영상 통합 관제 시스템 개발
주요 프로젝트
- 영상 통합 관제 시스템 개발
기여도: 40%
- 시설물 통합 관제 시스템 개발
기여도: 30%
- 재난 안전 플랫폼 개발
기여도: 30%
사용한 기술
핵심 가치
개발자로서 추구하는 가치와 방향성
문제에 빠르게 도전
복잡한 문제를 마주했을 때 신속하게 분석하고 효율적인 해결책을 찾아냅니다.
지속적인 성장을 추구
자기 개발을 통해 더 나은 개발자로 성장하기 위해 노력합니다.
아이디어
아이디어를 통해 문제를 해결하는 오픈소스를 개발하여 기여합니다.
문제 해결
UX부터 DX까지 다양한 문제를 마주하고 빠르게 도전
AI 코드 생성의 일관성 문제 해결
문제 상황
- AI가 생성한 코드가 팀 컨벤션을 따르지 않음
- 컴포넌트 내부 정의, useEffect 파생 상태 등 반복적인 안티패턴 발생
- 79개 규칙을 문서화했으나 규칙 누락이 본질적으로 발생
해결 접근법
- 규칙을 "검증"이 아닌 "슬롯 기반 구조적 강제"로 전환
- 빈 슬롯이 있으면 코드 생성 자체가 불가능한 스키마 설계
- 3단계 프로토콜로 설계 → 검증 → 생성 자동화
슬롯 기반 프로토콜
- Phase 1: 파일 유형에 맞는 스키마 로드
- Phase 2: 모든 슬롯을 필수로 채우고 Design Guard 확인
- Phase 3: Grammar Scan 후 코드 생성
데이터 기반의 정량적 코드 분석
문제 상황
- AI에게 코드 수정을 요청하면 프롬프트에 따라 결과가 달라지는 일관성 문제 발생
- 수동 코드 분석은 누락이 쉽고 리팩토링의 정량적 근거가 부족
해결 접근법
- React Compiler의 정적 분석 파이프라인에서 구조화된 분석 데이터를 추출하여 AI에 제공
- 동일 코드 입력 시 항상 같은 분석 결과로 결정적이고 일관된 리팩토링 수행
- 리팩토링 전후 재분석으로 객관적 평가 가능
데이터 기반 분석 파이프라인
- SSA 변환: 변수 버전을 추적하여 데이터 흐름 분석
- Effect 분석: Read/Mutate/Freeze 등 부수효과 분류
- Reactive 분석: Props, State 기반 의존성 체인 파악
Next.js 스트리밍 SSR 인프라 문제 해결
문제 상황
- Amplify 배포 후 스트리밍 SSR이 작동하지 않음
- 모든 데이터가 준비될 때까지 빈 화면이 표시되어 사용자 경험이 저하됨
- Amplify가 Lambda를 Buffered 모드로 실행하여 스트리밍 응답이 차단되는 것이 원인
해결 접근법
- SST(Serverless Stack)를 도입하여 Lambda Function URL을 Streaming 모드로 구성
- OpenNext의 Wrapper를 aws-lambda-streaming으로 변경하여 스트리밍 SSR 활성화
- 페이지 최상위의 cookies() 호출을 하위 컴포넌트로 분리하여 동적 렌더링 범위를 최소화
핵심 변경 사항
- Lambda 응답 모드: Buffered → Streaming으로 전환하여 준비된 콘텐츠부터 점진적 전송
- 렌더링 구조 개선: Suspense 경계를 활용해 독립적인 컴포넌트별 hydration 최적화
- 배포 환경구축: Github Actions를 통해 브랜치별 배포 환경 구성
확장 가능한 DatePicker 컴포넌트 설계
문제 상황
- 캘린더 클릭만 지원하고 직접 입력 후 자동 파싱이 불가능
- 폼 라이브러리 통합이 복잡하고 UI 커스터마이징이 어려움
해결 접근법
- 파싱, 유효성 검사, 포맷팅을 하나의 core 훅으로 통합하여 양방향 동기화 구현
- Composition 패턴으로 Root, Input, Calendar 등을 독립 컴포넌트로 분리
- 계층화된 API 설계로 standalone부터 RHF 통합까지 단계적 확장
계층화된 API 설계
- Layer 0: 독립 컴포넌트 (기본 상태 관리)
- Layer 1: 편의 훅 (옵션 셋업)
- Layer 2: React Hook Form 통합
- Layer 3: Controller (render prop 패턴)
관련 블로그 글
DatePicker 컴포넌트 설계Swit 업무 필터링 기능의 UX 통일
문제 상황
- 각 화면(대시보드, 캘린더, 간트차트 등)에서 업무 리스트 필터링 UX가 상이함
- 상태, 담당자, 참여자, 우선순위 등 동일한 필터가 화면마다 다르게 구현됨
- 필터 구현 코드가 화면마다 중복되어 유지보수가 어려움
해결 접근법
- 모든 필터링 옵션을 표준화 할것을 기획적으로 제안
- 모든 화면에서 동일한 필터링 UX를 제공하여 사용자 경험 일관성 확보
- 필터링 로직을 모듈화하여 코드 중복 제거 (4,000라인 → 700라인, 약 82.5% 감소)

통합된 필터링 UI - 모든 화면에서 동일한 사용자 경험 제공
Swit 모노레포 아키텍처 변경
문제 상황
- 짧은 시간에 동시다발적으로 많은 기능을 배포
- 그에 따라 배포시 순환참조로 인해 빌드에러 발생
해결 접근법
- 각 패키지가 단방향으로 참조하도록 설계
- 개발자들이 아키텍처에 따를 수 있게 커스텀 eslint 룰을 통해 가이드 제공
단방향 참조 아키텍처
효과적으로 커뮤니케이션 하기
문제 상황
- 팀원이 많아지면서 의견을 나누기 어려워짐
- 의사결정 과정이 투명하지 않고 히스토리가 남지 않음
- 비동기적 커뮤니케이션이 어려움
해결 접근법
- GitHub Discussion을 활용하여 의사결정 히스토리 기록
- 비동기적 커뮤니케이션 활성화로 시간대와 상관없이 의견 교환 가능
- 글로 정리하는 과정에서 생각을 더 명확히 표현하는 효과
GitHub Discussion 활용 예시
주제: eslint 활성화 룰 정의
참여자: 5명
결과: 기존의 일부 룰을 비활성화하기로 결정
웹소켓 모듈을 통한 DX 개선
문제 상황
- 웹소켓을 통해 서버와 통신할 때 특정 리소스를 해제하려면 이벤트를 보내어 관리해야 함
- 이러한 리소스 관리를 컴포넌트 단위에서 직접 처리하고 있었음
- 비즈니스 로직과 웹소켓 리소스 관리 로직이 혼재되어 코드 복잡성 증가
해결 접근법
- 리액트 쿼리와 유사한 설계를 가진 웹소켓 모듈 개발
- 컴포넌트는 웹소켓 모듈의 API만 사용하도록 구조 개선
- 리소스 관리 및 이벤트 처리 로직 중앙화
웹소켓 모듈 사용 예시
// 이전: 컴포넌트에서 리소스 관리
const ChatComponent = () => {
useEffect(() => {
// 채팅방 입장 이벤트 전송
socket.send(JSON.stringify({
type: 'JOIN_ROOM',
roomId: roomId
}));
return () => {
// 컴포넌트 언마운트 시 채팅방 퇴장 이벤트 전송
socket.send(JSON.stringify({
type: 'LEAVE_ROOM',
roomId: roomId
}));
};
}, [roomId]);
// 비즈니스 로직...
}
// 이후: 웹소켓 모듈 사용
const ChatComponent = () => {
// 리액트 쿼리와 유사한 API
const { data, isLoading } = useWebSocketResource({
resourceType: 'CHAT_ROOM',
resourceId: roomId,
// 리소스 관리는 모듈에서 자동으로 처리
});
// 비즈니스 로직에만 집중
}Tanstack Query를 통한 DX 개선
문제 상황
- 메모리 최적화를 위해 사용하지 않는 데이터는 캐시에서 제거해야 함
- 컴포넌트의 구조가 복잡해짐에 따라 컴포넌트 라이프사이클에 맞춰 캐시를 삭제하는 것이 어려워짐
해결 접근법
- Tasntack Query가 실험버전으로 Angular에서 사용 가능하다는 것을 알게 됨
- 테스트 프로젝트를 만들어 DX를 향상 시키도록 제안함
관련 블로그 글
Tanstack Query for Angular변경하기 쉬운 코드로 만들기
문제 상황
- API 인터페이스가 그대로 리덕스 인터페이스로 사용됨
- 서버 인터페이스의 변경이 클라이언트에 직접적으로 영향을 미침
- 커다란 인터페이스를 모든 컴포넌트에서 사용해 인터페이스가 점차 거대해짐
- 인터페이스 변경이 많은 컴포넌트에 직접적인 영향을 미쳐 코드 간 의존성 증가
해결 접근법
- API 인터페이스와 뷰 인터페이스 분리
- 각 컴포넌트에 필요한 값만 모아 컴포넌트별 props 인터페이스 생성
- 인터페이스 통째로 전달하지 않고 필요한 값만 선택적으로 전달
인터페이스 분리 예시
이전: 하나의 거대한 인터페이스
// 이전: 하나의 거대한 인터페이스
interface TaskData {
id: string;
title: string;
status_id: number;
assignee_ids: string[];
created_at: string;
watchers: string[];
comments: Array<{
id: string;
content: string;
user_id: string;
created_at: string;
}>;
// 20개 이상의 속성...
}
// 컴포넌트에 통째로 전달
<TaskCard task={taskData} />개선: 컴포넌트별 인터페이스
// 컴포넌트별 맞춤 인터페이스
interface TaskCardProps {
id: string;
title: string;
status: {
id: number;
name: string;
color: string;
};
assignees: Array<{
id: string;
name: string;
avatar: string;
}>;
// 필요한 속성만 포함
}
// 필요한 데이터만 매핑하여 전달
<TaskCard
id={task.id}
title={task.title}
status={getStatus(task.status_id)}
assignees={getAssignees(task.assignee_ids)}
/>RxJS의 메모리 누수 해결하기
문제 상황
- RxJS 사용 시 메모리 누수 발생
- 구독(subscription) 해제가 제대로 이루어지지 않음
- 장시간 사용 시 브라우저 성능 저하 및 크래시 발생
해결 접근법
- RxJS 스터디 및 세미나를 통한 팀 역량 강화
- 핫 옵저버블과 콜드 옵저버블의 정확한 구분
- 개발자 도구를 활용한 메모리 누수 지점 분석
- 구독 관리를 위한 표준 패턴 도입 및 적용
RxJS 메모리 누수 해결 패턴
// 이전: 구독 해제 누락
ngOnInit() {
this.dataService.getData().subscribe(data => {
this.data = data;
});
}
// 이후: 구독 관리 패턴 적용
private destroy$ = new Subject<void>();
ngOnInit() {
this.dataService.getData()
.pipe(takeUntil(this.destroy$))
.subscribe(data => {
this.data = data;
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}하드웨어 SDK 호환성 높이기
문제 상황
- 제조사마다 다른 SDK를 사용하여 영상 모듈 연동 필요
- RTSP 프로토콜 연동 시 호환성 문제 발생
- 표준 문서와 실제 구현 간 차이로 인한 오류
해결 접근법
- RTSP 프로토콜 표준 문서 분석
- 네트워크 패킷 분석 도구를 활용한 통신 흐름 파악
- 제조사별 SDK 차이점 분석 및 추상화 레이어 개발
RTSP 프로토콜 분석 결과
문제점: 제조사별 RTSP 구현 차이로 인한 연결 불안정
해결책: 표준 RTSP 클라이언트 개발 및 제조사별 특화 처리 로직 추가
결과: 연결 안정성 90% 이상 향상
보이지 않는 에러 개선하기
문제 상황
- 사용자가 보고하지 않는 숨겨진 에러로 인한 기술 부채 증가
- 프로덕션 환경에서만 발생하는 간헐적 오류 추적 어려움
- 소스맵 없이 난독화된 코드에서 에러 발생 위치 파악 불가
해결 접근법
- Sentry에 소스맵 연동으로 정확한 에러 발생 위치 파악
- 에러 발생 패턴 분석 및 우선순위화
- 잠재적 문제 코드 개선으로 사전 예방적 유지보수
Sentry 소스맵 연동 결과
TypeError: Cannot read property 'value' of undefined
at Object.t.updateTask (app.5f8e2d31.js:2:159223)
at e.value (app.5f8e2d31.js:2:159822)TypeError: Cannot read property 'value' of undefined
at TaskService.updateTask (services/task-service.ts:247)
at TaskComponent.saveChanges (components/task/task.component.ts:183)지속적인 성장
다양한 기술 스택을 익히고 발전하는 개발자
AI 기반 개발
AI 에이전트와의 협업을 통해 개발 생산성을 높이는 방법을 탐구하고 있습니다. 문서 기반 개발 프레임워크, AI 에이전트의 컨텍스트 관리, 그리고 데이터 기반 함수형 리팩토링 등 AI 시대의 새로운 개발 패러다임을 학습하고 있습니다.
React
프론트엔드 개발에 관심을 가지기 시작한 때에 한국에서 리액트가 점차 인기를 얻기 시작했습니다. 이때부터 지속적으로 사용해보며 더 나은 개발 경험을 추구하고 있습니다. SSR 프레임워크의 부상과 함께 Next.js, Remix, Qwik 등 다양한 렌더링 전략을 학습하고 있습니다.
CSS
SSR 환경에서의 CSS in JS 호환성 문제와 타이포그래피, 레이아웃 등 CSS의 깊은 영역을 학습하고 있습니다.
TypeScript & Effect
Effect는 TypeScript 기반의 함수형 프로그래밍 라이브러리로, 타입 안전한 에러 처리와 의존성 관리를 제공합니다. 이를 통해 복잡한 비동기 흐름을 안전하게 다루는 방법을 학습하고 있습니다.
프로토 버퍼를 통한 효율적인 통신
JSON을 통한 REST API는 개발이 쉽고 연동이 간편하지만, 바이너리보다 크기가 커서 많은 비동기 통신이 발생하는 앱에는 적합하지 않습니다. gRPC에서 사용하는 프로토버퍼를 이용해 서버와 웹소켓을 통해 통신함으로써 네트워크 효율성을 높이고 타입 안정성을 강화하는 방법을 연구하고 있습니다.
관련 블로그 글
아이디어
새로운 아이디어로 문제를 해결하는 오픈소스 프로젝트
React Context Query
React Context API를 사용할 때 발생하는 불필요한 리렌더링 문제를 해결하는 라이브러리를 개발하여 오픈소스로 공개했습니다.
함께 일해보세요
새로운 프로젝트나 협업 기회가 있으시다면 언제든지 연락주세요.
함께 멋진 것을 만들어 나갈 수 있기를 기대합니다.