지인을 통해 연락이 왔다. 딥페이크 기반으로 밈을 만드는 서비스를 준비하고 있는데, 개발자가 필요하다고. 서비스 소개 자료를 보니 재밌었다. 사용자 얼굴을 GIF 밈에 합성해서 나만의 짤을 만드는 앱이다. 2021년 3월, 4명으로 구성된 창업 팀에 합류했다.
서비스
SwapDo는 딥페이크 기반 얼굴 합성 밈 생성 서비스다. Android와 iOS를 지원했다.
핵심 기능은 얼굴 합성이다. 앱에서 제공하는 GIF나 이미지 콘텐츠에 사용자의 얼굴을 합성하면 새로운 짤이 만들어진다. 합성은 백그라운드에서 처리되기 때문에 결과를 기다리는 동안 다른 콘텐츠를 둘러볼 수 있었다. 완료되면 푸시 알림이 왔다.
가상 성형 기능도 있었다. 유명인의 눈, 코, 입을 부위별로 골라서 자기 얼굴에 합성할 수 있었다. 밈 월드컵은 재밌는 주제의 콘텐츠를 토너먼트 형식으로 선택하는 기능이었다. 커뮤니티에서는 만들어진 짤을 공유하고 댓글을 달 수 있었다.
역할
팀장을 맡았다. 4개월간 팀 운영을 하면서 동시에 개발을 했다. 기여도로 보면 백엔드 서버 개발이 80%, Android 앱 개발이 30%, 합성 기술 개발이 10% 정도였다.
아키텍처
서비스 구조는 단순했다. Android/iOS 클라이언트가 Apache 기반 백엔드 서버에 REST API를 호출한다. 백엔드는 PHP로 작성했고, 데이터는 MariaDB에 저장했다. 에러 추적은 Sentry를 사용했다.
얼굴 합성은 별도의 환경에서 처리했다. 백엔드가 합성 요청을 받으면 Anaconda 가상 환경의 Python 스크립트를 호출한다. 합성이 완료되면 결과 파일의 경로를 백엔드에 반환하는 구조였다.
flowchart LR
subgraph Client
Android
iOS
end
Client -- "에러 로그" --> Sentry
Client -- "요청 (CRUD)" --> Backend
Backend -- "응답 (JSON)" --> Client
Backend["Apache\n백엔드 서버\n(PHP)"]
Backend -- "데이터 저장/조회" --> MariaDB[(MariaDB)]
Backend -- "합성 요청" --> Anaconda["Anaconda\n합성용 가상 환경\n(Python)"]
Anaconda -- "합성 결과 위치" --> Backend
Anaconda -- "합성 결과" --> Storage[("파일\n스토리지")]
합성 과정은 여러 단계를 거쳤다. 사용자 얼굴을 인식하고, 얼굴 랜드마크를 추출한다. GIF 콘텐츠의 각 프레임 정보를 가져온 뒤, 3D 모델링으로 얼굴을 합성한다. 경계선과 피부색을 보정하고, 프레임별로 합성한 결과를 다시 GIF로 인코딩한다. OpenCV, Dlib, FaceAlignment 같은 라이브러리를 사용했다.
flowchart LR
A["사용자 얼굴 인식"] --> B["얼굴 랜드마크\n추출"]
B --> C["GIF 프레임\n정보 추출"]
C --> D["3D 모델링 및\n얼굴 합성"]
D --> E["경계선 및\n피부색 보정"]
E --> F["프레임별 합성"]
F --> G["GIF 인코딩"]
G --> H["합성 결과\n전달"]
| 얼굴 인식 | 랜드마크 추출 | 3D 모델링 | 얼굴 합성 | 합성 결과 |
|---|---|---|---|---|
![]() | ![]() | ![]() | ![]() | ![]() |
기술적 기여
백엔드 리팩토링
합류 당시 백엔드 코드는 하나의 파일에 모든 로직이 들어 있었다. MVC 패턴을 도입하고 OOP로 구조를 분리했다. 요청 처리, 비즈니스 로직, 데이터 접근을 계층별로 나누자 코드 가독성이 올라갔고, 응답 시간도 약 10% 개선됐다.
Android 무한 스크롤
콘텐츠 목록의 스크롤 성능이 좋지 않았다. 스크롤할 때마다 버벅거림이 느껴졌다. 무한 스크롤 로직을 개선해서 스크롤 속도를 약 60%까지 끌어올렸다. 이미지 로딩에 Glide를 사용하고, RecyclerView의 재활용 로직을 정비한 결과였다.
비동기 합성 요청
얼굴 합성은 서버에서 처리 시간이 걸린다. 사용자가 합성 버튼을 누르고 결과를 기다리는 동안 앱이 멈춰 있으면 안 됐다. Android의 Service 컴포넌트를 활용해서 합성 요청을 비동기로 처리했다. 합성이 백그라운드에서 진행되는 동안 사용자는 다른 콘텐츠를 탐색할 수 있었고, 완료 시 FCM 푸시 알림으로 결과를 안내했다.
회고
처음으로 창업 팀에 합류한 경험이었다. 기획된 제품을 받아서 만드는 것이 아니라, 제품이 어떤 형태여야 하는지를 함께 고민하면서 코드를 작성했다. 팀장 역할도 처음이었다. 개발과 팀 운영을 동시에 하는 것이 쉽지 않았지만, 제품 전체를 조망하는 시야를 갖게 된 계기였다고 본다.
기술적으로는 PHP 기반의 REST API 설계, Android 앱의 성능 최적화, 백그라운드 처리 패턴을 경험했다. 작은 팀에서 여러 역할을 맡다 보니 백엔드와 모바일을 넘나드는 개발을 하게 됐고, 그 과정에서 서비스 전체 흐름을 이해하는 감각이 생겼다.
2021년 7월, 프로젝트는 자연스럽게 마무리됐다. 지인의 연락 한 통에서 시작된 5개월이었다. 돌이켜 보면 제품을 함께 만들어가는 경험이 가장 큰 배움이었다.




