미리보기
기본 정보

👋 안녕하세요, 코드를 통해 비즈니스 가치를 전달하고자 하는 백엔드 개발자 조안나입니다.
기술 스택
TypeScript, JavaScript, TypeORM, Node.js, NestJS, MySQL, AWS, Docker, C, C++, Linux
경력
주식회사엑셈
연구원 | 개발 2본부
2022.10. ~ 2023.10. (1년 1개월)
DB 모니터링 솔루션을 만드는 회사입니다. 고객사 환경에 설치되는 DB 성능정보 수집 데몬을 만드는 팀에서 일했습니다. 저는 IBM DB2 성능정보 수집 모듈을 담당했습니다.
TCP/IP 프로토콜로 통신하는 데몬 프로그램 기능 개발 및 유지 보수
윈도우, 유닉스, 리눅스 환경에 모두 작동하는 코드를 작성하고 다양한 환경에서 발생하는 이슈에 대한 트러블 슈팅
을 하였습니다.
멀티 스레딩 환경에서 발생하는 버그, 패킷 전송 과정에서 발생하는 버그, 서로 다른 OS/CPU로 인해 생기는 차이로
인한 버그 등을 경험하였습니다. 이를 통해 멀티 스레딩에 대한 깊은 이해와 tcp dump와 와이어 샤크를 통한 네트
워크 디버깅 방법, OS, CPU에 대한 지식 등을 얻을 수 있었습니다.
팀 공용 로그 라이브러리 리팩토링
기존 로그 라이브러리에는 로그 레벨과 관련된 기능이 없어 로그 작성자가 일일이 수기로 입력해야 했습니다. 또, 출
력 스트림이 하나로 고정되어 있어 같은 내용의 로그임에도 표준 출력용으로 한 줄, 파일 저장용으로 또 한 줄 작성
해야 했습니다. 이 때문에 코드 중복이 발생하고 같은 위치의 로그임에도 내용이 다를 때도 있어 혼란을 야기하는 상
황이었습니다.
이를 개선하기 위해 로그 레벨을 도입해 명확성을 높이고, 필요한 레벨(ex: 디버그 레벨)의 경우 한 번의 호출로 파
일, 표준 출력 스트림에 모두 출력할 수 있도록 변경하였습니다. 이에 더해 로그가 호출된 코드의 라인 넘버와 함수명
을 출력하도록 변경해 디버깅 편리성을 향상시켰습니다.
신버전 모듈 성능 테스트
고객사에서 모듈의 CPU 사용률을 낮추어달라는 요청이 들어와 CPU를 소모하는 계산 관련된 로직을 다른 모듈로
이전한 신버전 모듈이 개발되었고, 이에 대한 실제 CPU 사용률 측정이 필요했습니다.
DB 부하 툴인 DB Hammer로 많은 쿼리를 발생시켜 DB 성능 정보 수집 모듈에도 많은 부하가 가해지는 상황을 만
들었습니다. 이후 리눅스 top 프로그램이 이전 호출의 내용을 기억하면서도 버퍼가 꽉 차지 않도록 옵션을 주어 성
능 정보를 측정할 수 있도록 하여 1시간 동안의 CPU 사용량을 측정하였습니다.
구버전 / 신버전 모듈 각각 성능 테스트를 진행하고, 그래프로 나타내는 비교 보고서를 작성하였습니다.
C++ 98 버전을 최신 버전으로 올리는 방법 리서치
프로그램이 고객사 환경에 설치되기에 기존에는 모든 환경을 포용하기 위해 C++ 98 표준을 사용하고 있었습니다.
C++ 11부터 사용할 수 있는 유용한 기능들을 사용하고 싶다는 니즈가 생겼습니다.
이에 C++ 라이브러리인 libstdc++의 C++11 버전을 낮은 버전의 리눅스 배포판에서 재빌드해 낮은 버전의 배포판
에서도 사용 가능하도록 커스텀하는 방법을 고안했습니다.
제약사항은 C++ 11 버전의 libstdc++ 빌드시 필요한 gcc 컴파일러의 최소 요구 버전이 있다는 것이었습니다. 리눅
스 배포판 별, 버전 별 사용되는 gcc의 버전을 조사 후 고객사와 비교해 리눅스 환경에서 C++11 로의 버전업이 가능
함을 밝혔습니다.
또한 커스텀한 libstdc++을 정적 라이브러리로 빌드 시 포함하는 방법과 동적 라이브러리로 빌드 후 링크시키는 방
법 중 정적 라이브러리를 포함시키는 방법은 라이센스 문제가 있어 동적 라이브러리로 빌드한 뒤 링크하는 방법을
구체적으로 문서화하였습니다
프로젝트
댕댕워크
프로그래머스 데브코프 풀스택 엔지니어링 코스
2024.04. ~ 진행 중
프로그래머스 웹 풀 사이클 부트캠프에서 팀으로 진행한 프로젝트입니다. 디자이너 1, 프론트 3, 백엔드2, 인프라 1로 구성되었으며 저는 백엔드를 담당했습니다. 인프라도 일부 담당했습니다.
사용 기술
서버 : Typescript, Nest.js, Node.js, TypeORM
DB : MySQL, Redis
인프라: NginX, Docker, Github Actions, Graphana, Loki
클라우드: AWS(EC2, RDS, S3) 오라클 (Instance)
주요 성과
API 응답 속도 30% 개선 (30ms → 21ms)
쿼리 성능 81.3% 개선 (쿼리 cost 457 → 85.4)
산책 경로 데이터 72% 경량화 (145KB → 39KB)
날씨 정보 요청 시간 99.76% 단축 (19,512ms → 46ms)
로컬 캐싱을 통해 데이터 획득에 걸리는 시간 약 40% 개선 (6.88ms -> 4.12ms)
주요 구현사항
ERD 설계
데이터의 성격을 고려해 정규화 / 비정규화를 적용하여 ERD를 설계하였습니다.
각 강아지의 종과 관련된 정보는 여러 강아지 사이에서 중복되기에 Breeds 테이블로 분리해 정규화하였습니다.
산책 중 강아지의 배변 횟수는 배변 위치를 저장한 Excrements 테이블에서 추출할 수 있었지만, Excrements 테
이블은 주기적으로 삭제되기에 산책일지 테이블에 excrmentCount 컬럼을 만들어 비정규화했습니다. 산책일지는
자주 조회되는 데이터라 조회시 JOIN 횟수가 줄어드는 이득도 있었습니다.
기능 구현
산책 가능한 강아지 목록 조회
산책 시작 / 중지
산책일지 CRUD
강아지 일주일 산책 현황 통계 조회
API 성능 개선 [BLOG]
기존에는 연관성이 없는 쿼리 작업도 순차적으로 동기 실행하도록 구현되어 있었습니다.
이를 Promise.all을 사용해 병렬 실행되도록 리팩토링 해 API 응답 속도를 평균 30ms -> 21ms로 30% 개선하였
습니다.
한 쿼리에서 에러가 나면 이후 진행할 필요성이 없어, Promise.allSettled가 아닌 Promise.all을 사용했습니다.
쿼리 성능 개선 [BLOG1] [BLOG2]
산책일지 조회 쿼리가 복잡해 유저 수 증가시 성능 저하가 우려되었습니다.
EXPLAIN PLAN 분석을 통해 더 많은 Row를 반환하는 테이블이 드라이브 테이블로 사용되고 있어, Nested
Loop를 사용하는 조인 과정에서 성능을 저하시키고 있음을 알게 되었습니다. 이에 더 적은 Row를 반환하는 테이
블에 먼저 접근하도록 조인 순서를 변경하였습니다.
조건절에 사용되는 두 가지 컬럼에 대한 Composite index를 생성하여 필터링 단계를 한 단계로 줄였습니다.
이를 통해 쿼리 cost를 457 -> 85.4로 81.3% 개선하였습니다.
산책 경로 데이터 경량화 [BLOG]
산책 시 유저의 경로를 GPS 포인트의 배열로 저장하고 있었는데, 비즈니스 규칙으로 정한 최대 3시간 산책시에
420KB까지 커질 수 있어 절감의 필요성을 느꼈습니다.
우선 경로를 기록하는 단위를 거리는 1m → 10m, 시간은 1초 →2초로 조정하고 데이터 타입을 바꾸어 최대 145KB
까지 줄였습니다. (프론트엔드 팀원이 수행)
이후 선분 단순화 알고리즘인 Ramer-Douglas-Peucker 알고리즘의 적용으로 최대 145KB -> 39KB로 약 72%
경량하였습니다.
날씨 API 모듈 구현 [BLOG]
기상청 날씨 API의 응답 속도가 너무 느려 홈 화면의 날씨 컴포넌트 렌더링 속도가 지연되었습니다.
이를 해결하기 위해 서버에서 날씨 정보를 미리 요청해 저장해두고 클라이언트가 기상청이 아닌 서버로 요청을 보내는 구조로 변경하기로 하였습니다.
날씨 정보는 기존 서버에 저장된 유저의 데이터와 연관성이 없고 인증, 인가도 필요하지 않아 별도의 모듈로 구현해
복잡도를 낮추었습니다.
날씨 모듈은 엔드포인트가 하나밖에 없어 프레임워크 없이 Node.js를 사용하였습니다.
날씨 데이터는 당일 데이터가 아니면 의미가 없기에 데이터의 양이 일정 크기 이상 늘어나지 않고, 자주 조회되는
데이터이므로 인메모리 DB인 Redis를 사용해 조회 성능을 높였습니다.
이를 통해 날씨 정보 요청에 걸리는 시간이 100번 요청시 평균 19512ms -> 46ms로 약 99% 감소했습니다.
일주일 강아지 통계 정보 데이터 로컬 캐싱
홈 화면에서 유저가 소유한 모든 강아지의 일주일 산책 통계 데이터를 보여주는 기능이 있습니다. 통계 데이터를 생성하기 위해 여
러 테이블에 접근해 데이터를 가공하는 복잡한 쿼리가 필요했습니다. 자주 접근되는 홈 화면에서 매번 이러한 쿼리
를 실행하는 것이 성능 저하의 요인이 될 것 같아 우려되었습니다.
Nest.js의 cache manager 서비스로 해당 데이터를 캐시하였습니다.
데이터의 실시간성을 보장하면서 성능을 최적화하기 위해 EventEmitter로 관련된 데이터가 변경되는 것을 감지해
캐시를 업데이트 하도록 하였습니다.
이를 통해 데이터 획득에 걸리는 시간을 100번 요청 평균 6.88ms -> 4.12ms로 약 40% 감소했습니다.
AWS S3 이미지 서버 구축 [BLOG]
산책 시 유저가 사진을 촬영할 수 있는 기능이 있어 사진을 저장하기 위한 이미지 서버 구축이 필요했습니다.
서버에서 직접 이미지 업로드 시 소모되는 리소스가 부담되어 다른 방법을 찾아보았습니다.
보안이 확보된 presigned URL을 활용해 서버가 아닌 클라이언트에서 이미지를 업로드하여 확장성 있는 서버를
구축했습니다.
AWS와 Vercel로 백엔드 / 프론트엔드 배포
프로그래머스 부트캠프가 종료되어 무료로 제공되던 aws 서버를 더 이상 사용할 수 없게 되었습니다.
팀 공용 aws 계정을 새로 만들고 EC2와 RDS로 백엔드, Vercel로 프론트엔드 서버를 이전 배포하였습니다.
기존 서버는 프론트엔드와 백엔드의 도메인이 서로 달라 크로스 도메인 이슈가 있었는데, 사설 도메인을 구입하고
각각 메인 도메인/서브 도메인으로 바인드해 해결했습니다.
실시간 로그 모니터링 환경 구축
Blue-Green 정책으로 배포 시마다 새로운 컨테이너가 생성되어 이전 컨테이너의 로그에 접근이 힘들었습니다.
호스트 시스템에 도커 볼륨을 연결하여 컨테이너가 재시작되어도 로그가 유지되도록 하였습니다.
Graphana Loki 대시보드를 배포하고 실시간으로 로그를 전송해 모니터링 환경을 구축했습니다.
대규모 더미 데이터 생성 쿼리 작성 [BLOG]
쿼리 성능 개선을 위한 테스트를 위해 대규모 더미 데이터를 갖고 있는 테스트 레포지토리를 만들고자 했습니다.
비용이 들어가는 툴을 사용하지 않는 방법을 찾아보았고 재귀를 사용해 문법이 간결한 MySQL의 Recursive CTE
를 사용하였습니다.
10만 유저를 가정한 1.9GB의 랜덤 데이터를 약 4분 30초 내로 생성할 수 있는 더미 데이터 생성 쿼리를 작성하였
습니다.
git hook 작성
원활한 협업을 위한 컨벤션이 많아지면서 이를 지키는 데 소요되는 리소스가 커지고 실수도 많아졌습니다.
git hook을 사용해 커밋시 eslint와 prettier 검사를 자동으로 실행하고 통과하였을 경우에만 커밋할 수 있도록 강
제하였습니다. 또 브랜치 명이 컨벤션에 맞을 경우에만 원격 브랜치에 push가 가능하도록 하였습니다.
백엔드 레포에 서버 외 다른 모듈이 추가됨에 따라 변경사항이 있는 모듈에 대해서만 hook이 작동하도록 변경해 불
필요한 절차를 방지했습니다.
이를 통해 오류를 방지하고 개발 편의성을 높였습니다.
포트폴리오
교육
프로그래머스 풀사이클 엔지니어링
사설 교육
2023.11. ~ 2024.05. | 졸업
이노베이션 아카데미
사설 교육
2021.03. ~ 2022.10. | 졸업
덕성여자대학교
대학교(학사) | 문화인류학과
2013.03. ~ 2018.08. | 졸업
자격증
컴퓨터활용능력
1급 | 대한상공회의소
2020.07.
자기소개
👋 안녕하세요, 코드를 통해 비즈니스 가치를 전달하고자 하는 백엔드 개발자 조안나입니다.
저는 C, C++ 개발자로 1년간 일하다가, 웹 기술에 깊은 관심을 갖게 되어 Typescript와 Nest.js를 주력으로 사용하며 웹 백엔드 개발자로 전향을 준비하고 있습니다. 이를 위해 <댕댕워크> 프로젝트를 꾸준히 리팩토링하며 기술을 익히고 있습니다.
🛠 문제 해결에 능숙한 개발자
이전 회사의 데몬 프로그램은 고객사 환경에 설치되었기에 직접 디버깅이 불가능한 경우가 많았습니다. 나타나는 이상동작과 로그를 토대로 문제 원인을 유추해야 했습니다. 이를 통해 로그를 파악하는 능력과 문제의 전후 맥락을 살피는 능력을 키웠습니다.
💶 성능을 개선하는 개발자
백엔드 개발자의 중요한 임무 중 하나가 성능을 향상시켜 서버 비용을 절감하는 것이라고 생각합니다. <댕댕워크> 프로젝트에서 산책일지의 경로 데이터를 줄이기 위해 line-simplication 알고리즘을 찾아 적용해 데이터 크기를 약 72% 감소시켜 RDS 비용에 대한 걱정을 던 경험이 있습니다. 또 API 성능 30%개선, 쿼리 cost를 81.3% 개선한 경험을 통해 비효율적인 코드의 문제를 인식하고, 성능을 최적화하는 방법을 배웠습니다.
🔑 운영을 생각하는 개발자
전 회사에서의 경험을 통해 디버깅에 로그가 정말 중요하다는 것을 알게 되었습니다. 출시 후 발생할 수 있는 다양한 문제를 미리 대비하기 위해 Winston 라이브러리를 사용해 로거를 구현하고 Grafana Loki 대시보드에 배포해 실시간 모니터링 환경을 구축했습니다. 배포 환경과 로컬 환경의 DB 차이로 인한 문제를 로그 분석을 통해 신속히 해결한 경험은 운영의 중요성을 더욱 깨닫게 해주었습니다.
👩👦👦 협업을 중시하는 개발자
팀의 성공이 개인의 성공보다 중요하다고 생각합니다. <댕댕워크> 프로젝트에서 주 단위 스프린트와 코드리뷰를 통해 팀원들과 협업하며 긍정적인 영향을 주고받았습니다. 또 테스트를 위한 더미 데이터 생성 SQL 작성으로 팀에서 테스트 데이터를 편하게 생성할 수 있도록 돕고, git hook을 통해 팀의 컨벤션을 지켜야 커밋과 푸시가 가능하도록 해 원활한 협업을 가능하게 했습니다. 덕분인지 피어리뷰에서 감사하게도 팀 분위기에 긍정적인 영향을 미쳤다는 평가를 받은 적이 있습니다. 이러한 협업 경험은 팀의 목표 달성과 개인의 성장 모두에 큰 도움이 되었습니다.
🧡 서비스에 진심인 개발자
개발하는 서비스에 애정을 갖고 임합니다. <댕댕워크> 프로젝트 기획 단계에서 디자이너가 없었지만 직접 피그마를 활용해 플로우차트와 와이어프레임을 작성하여 팀원들과 공유했습니다. 이후에도 사용성을 고려해 의견을 내며 지속적으로 참여했습니다. 또한, 서비스의 성능 개선을 위해 기상청 날씨 API 응답 속도 문제를 해결하고자 별도의 캐싱 서버를 구축하여 응답 시간을 99% 단축시켰습니다. 이를 통해 사용자 경험을 크게 개선하였습니다.