- 경북대학교 공동구매 커뮤니티
- 대량으로 사면 저렴한 생활용품 살 때, 학교 기숙사에서 배달 음식이 먹고 싶은데 배달팁 때문에 너무 비싸 비용을 나누고 싶을 때, 1+1 행사하는 쇼핑몰 옷을 하나만 사고 싶을 때 같이 살 학생을 편리하게 찾을 수 있도록 도와주는 서비스
🎉 총 다운로드 수 727 (2022.03.02일 기준) 달성!
- 안드로이드 전용 앱과 합하면 총 다운로드 수 1200 이상!
- 총 회원가입자 수 1000 이상 달성!
- 앱스토어 소셜 네트워킹 카테고리 110위 달성! (2021.09.15일 기준)
- iOS, Android, 백엔드, 기획자, 마케터로 진로를 희망하는 경북대 학생들이 모여 애매한 강의 프로젝트말고 제대로된 프로젝트를 하나 해보자 하고 탄생한 앱
-
대학생들의 지갑은 가볍습니다. 옷, 생활용품, 배달음식,
어떤걸 사더라도 최대한 싸고 가성비 좋게 구매하고 싶어합니다.
-
그런데 저렴하게 구매하고 싶으면 대량으로 또는 1+1으로 구매해야 할 때가 많습니다.
그래서 공동구매라는게 존재합니다.
-
경북대학교에는 공구에 대한 수요가 많아 아래 사진과 같이 카카오톡 오픈채팅방 형태로 공구 모집이 많이 이루어져 왔습니다.
-
하지만 오픈채팅방은 게시글 형태로 구분되지 않아 UI/UX적으로 많은 불편함을 느꼈습니다.
- 한 번에 많은 글이 올라오면 글이 묻히기 일쑤
- 잡담과 섞여 공구 모집 글 구분이 어려움
- 공구 참여자와 별도 채팅방을 다시 한 번 더 개설해야하는 불편함
- 사기 또는 잠수에 대한 위험성 多
- 공구 모집 글 확인 및 신규 모집 글 개설 기능
- 모집 중인 공구와 모집 완료된 공구 구별 가능
- 마감된 공구는 별도 마감처리하여 더 이상 채팅방 입장이 되지 않게 구현
- 공구 글 수정 기능
- 공구 글 검색 기능
- 채팅 기능
- 공구하고 싶은 품목을 올리면 자동으로 채팅방 개설 → 희망자가 채팅방에 참여하는 방식
- WebSocket과 StarScream 라이브러리를 이용한 실시간 채팅 기능
- Socket에 연결되어 있지 않으면 FCM을 통해 개인 알림 발송 가능
- 채팅 참여, 나가기, 실시간 사용자 Ban 기능
- 사진 보내기 기능
데모 영상 링크 : https://drive.google.com/file/d/1AWt3Opp9z7dmQ26cTil_KCyJ1GYzKdyv/view?usp=sharing
- MVVM (ReactorKit)
- iOS 개발자 1명
- Android 개발자 2명
- 백엔드 개발자 1명
- 기획자 2명
- iOS 앱 전체 개발
- v 1.1 출시 이후 iOS 개발자 1명이 더 투입되어 협업 중
- 개발팀장
- 전체 개발 일정 조율 및 팀 전체와 함께 기능 구현 방안 토론 주도
- 모두가 초보였기 때문에 iOS, Android와 백엔드 담당 팀원들과 수많은 시행착오가 있었지만 원활한 중재자 역할을 수행하여 순조로운 개발이 가능하였습니다.
- 디자인
- 초기에 디자이너를 구하지 못해 제가 Figma로 프로토타이핑을 진행했었습니다.
- 실제 유저의 피드백을 지속적으로 받고 싶어 “개발자에게 건의사항 보내기”라는 기능을 추가했었습니다.
- 건의사항이 접수되면 팀이 쓰는 협업툴과 즉시 연동이 되어 아래와 같이 어떤 불편함을 느끼는지 확인할 수 있었습니다.
[ 피드백 받고 개선 및 추가한 주요 기능 ]
- 채팅방에서 사진 보내기 기능 추가
- 채팅방/공구글에서 상대방이 링크를 올리면 URL로 인식하고 이를 탭했을 때 브라우저로 이동
- 기존 단방향이던 건의사항 보내기 기능을 양방향으로 바꿔 개발팀과 실제 1:1 문의가 가능하게끔 변경
- 기존 학생 인증 방식인 웹메일 인증 방식에 대한 불편 접수가 많아 모바일 학생증 캡쳐 (OCR 검사) 기능 추가
- Firebase Dynamic Link를 이용한 공구글 공유 기능 추가
- 공구글 정렬 기능 추가 (’모집 중 우선’, 최신순’)
✅ 스토리보드 → 100% Code-based layout으로 전환
- 협업 시 발생하는 conflict 최소화, 빌드 타임 단축과 code based UI에 대한 감각을 익히기 위해 존재하던 40개 이상의 Storyboard VC와 XIB를 전부 SnapKit, Then, BaseViewController를 이용하여 전환
✅ Git Flow를 이용한 버전 관리 및 협업 연습
- 좌측 사진: Git Flow 사용 전
- 우측 사진: Git Flow 사용 후
✅ 팀원과의 코드 리뷰 실시
- 서로 오류를 봐주고 더 효율적인 방법은 없는지 체크하여 전체적인 코드 품질을 올릴 수 있었습니다.
✅ Shared Instance 사용 지양 및 Dependency Injection 적용
- Thread-safe 하지 않은 Shared instance 사용을 지양하고, 필요한 곳에서 직접 생성 후 사용하는 것으로 변경
- 한 클래스가 다른 객체를 직접 생성하는 부담을 줄여주고, 해당 클래스가 정확히 어떤 다른 객체에 의존하는지 명확히 보여주기 위해 Dependency Injection 적용
✅ ReactorKit 전환
- 기존에는 View Controller와 ViewModel의 통신을 위해서 Delegate Pattern을 이용
- 하지만 Delegate protocol이 커질수록 상태 관리가 어렵고 코드 가독성이 매우 떨어져 RxSwift를 이용한 바인딩이 절실해 보였음
- 부분적으로 적용해 나가기 쉽고 상태 관리가 용이한 ReactorKit을 사용하기로 선택 후 지금까지 80% 이상 전환 완료
- 코드의 가독성이 눈에 띄게 좋아졌고, 어떤 함수가 실행되는지 파악하기 위해 이리저리 파일을 찾는 횟수가 현저히 감소
✅ Alamofire → Moya 전환
- 모두 별개로 작성되어 있던 API 통신 함수는 유지보수하기 어렵고, 지나치게 코드의 양을 늘리기 때문에 Moya 를 사용하여 전부 리팩토링 완료
- 좌측 사진: Moya 사용 전
- 우측 사진: Moya 사용 후
-
Coordinator Pattern 적용
- 기존 MVVM 구조에서 Coordinator 패턴을 적용시킨 MVVM-C 구조를 적용해 Navigation Logic을 ViewController와 분리 가능
- RxFlow 적용 완료
- 기존 MVVM 구조에서 Coordinator 패턴을 적용시킨 MVVM-C 구조를 적용해 Navigation Logic을 ViewController와 분리 가능
-
채팅 Local Caching
- 채팅 목록 불러오기가 현재는 API 호출을 통해서만 이루어지는데, Local Caching을 이용하여 불필요한 API 호출 횟수를 줄이고 로딩 시간을 줄여 더 나은 사용자 경험 구현이 가능해 보인다.
- Realm 또는 CoreData를 이용한 Local Caching 적용 예정
- 채팅 목록 불러오기가 현재는 API 호출을 통해서만 이루어지는데, Local Caching을 이용하여 불필요한 API 호출 횟수를 줄이고 로딩 시간을 줄여 더 나은 사용자 경험 구현이 가능해 보인다.
-
Unit Test 적용
- 기능이 점점 많아지면서 테스트해야 할 기능도 많아지고 깜빡하고 테스트를 하지 않으면 치명적인 오류 발생 가능성이 농후
- Index out of range error, UI error, nil 처리 등 다양한 에러를 자동적으로 테스트하기 위한 Unit Test 가 절실해보임
- Unit Test 적용 예정
-
Fast Lane 도입으로 배포 자동화
- v1.0, 1.0.1, 1.1, 1.1.1 등 다양한 버전을 앱스토어에 배포하면서 불필요하게 낭비되는 바이너리 업로드 시간과 심사 제출 준비 시간이 있다는 것을 깨달음
- 배포 자동화를 통한 불필요하게 낭비되는 시간을 줄일 필요가 있어보임.
- Fast Lane 도입 예정
✅ 백엔드와 첫 협업
- 처음으로 백엔드와 협업을 했던 프로젝트였습니다. iOS 기본 문법을 배우고 바로 시작해서 모르는 것이 투성이었습니다.
- 처음 들어보는 수많은 용어들 🤯: JWT, AccessToken, RefreshToken, MultipartFormData, JSON Encoding, PostMan, ERD, FCM 등등..
- 모르는 것이 있으면 공부하고, 팀원과 함께 나아간다는 마인드로 정기적으로 스터디 세션을 열어 개념을 익히고 프로젝트에 개념을 적용하였습니다.
- 수십개의 각각 다른 API..어떤건 query string, 어떤건 multipartFormData, 또 어떤건 json string.. 처음에는 너무 혼란스러웠지만 백엔드 팀원과 차근차근 이야기하고 인터넷을 뒤져가며 어떻게든 API 통신이 이뤄지게 했습니다.
- 무엇보다, 협업이 처음이다보니 오류가 나면 프론트 문제인지 백엔드 문제인지 파악하는 것이 처음에 제일 힘들었습니다.
- 백엔드 문제라도 왜 문제가 일어나는 것 같은지, 나는 무엇을 시도해봤고 이렇게 해도 안 된다는 것을 차근차근 백엔드 팀원의 입장에서 생각하며 소통하는 역량을 기르게 되었습니다.
✅ 채팅 기능 (WebSocket)
- 제일 막막했었고 제일 시간이 오래 걸렸던 기능입니다.
- 단순히 채팅 내용이 왔다갔다하는 것을 넘어서 실시간성 보장 + 이전 채팅 불러오기 + Socket이 끊기면 FCM 보내고 알림 받기 등 사용자 입장에서 생각하고 구현해야 할 것이 너무 많아 초보 입장에서 많이 어려웠습니다.
- 관련 문서나 블로그도 거의 없어 맨 땅에 헤딩하듯 수 많은 오류를 맞닥뜨리면서 구현에 성공했습니다.
✅ 수 많은 경우의 수 생각
- 개발을 할 때는 항상 Golden Path을 생각하지만, 실제 유저는 개발자가 상상하지도 못한 방법으로 앱을 사용한다는 것을 몸소 느꼈습니다.
- 1.0 출시 후 수백명이 몰렸을 때 각종 crash/error 로그가 Crashlytics와 자체 서버에 찍히는 것을 보고 식은 땀을 흘렸습니다.
- iOS, Android, 백엔드 할 것 없이 사전에 발견하지 못했던 문제가 다수 발생해 급하게 1.0.1, 1.0.2 버전 등을 배포했었습니다.
→ 다양한 에러 처리에 대한 필요성을 느꼈고 각 에러에 따라 사용자한테 적절하게 UI로 표시해줘야 한다는 것을 깨달았습니다.
REST API
연동 방식에 대해 알고 프로젝트에 적용해 볼 수 있었습니다.Web Socket
을 이용한 실시간 채팅 기능을 구현해 볼 수 있었습니다.- Storyboard와 Code-Based Layout 두 개 모두 활용해 볼 수 있었으며 둘 사이의 장단점을 몸소 느낄 수 있었습니다.
BaseViewController
,Moya
등을 적용하여 코드 재사용성을 높이기 위한 고민을 해 볼 수 있었습니다.Dependency Injection
에 대해서 공부하고 왜 필요한지 이해할 수 있었습니다.Delegate Pattern
의 한계를 느끼고RxSwift
와ReactorKit
을 공부하고 직접 프로젝트를 개선해 볼 수 있었습니다.- “ 하위 호환 "과 관련된 문제를 고민하고 적용해 볼 수 있었습니다. (크누마켓 앱 버전 & iOS 버전)
- 무조건 최신 앱 버전을 사용하는 유저만 고려하지 않고, 이전 버전 과 최신 버전 사용자들이 서로 호환될 수 있게 UI와 Model 부분을 고려하였습니다.
✅ 인스타그램 홍보 계정 개설
✅ 인터뷰 영상 촬영
✅ 경북대 신문 인터뷰
-> 따라서 별도로 사용하고 싶으시다면 kevinkim2586@gmail.com 으로 성함과 사유를 알려주시면 사용해 보실 수 있도록 테스트 계정을 임시로 보내드리도록 하겠습니다. 감사합니다 :)
-> 현재 보고 계시는 Repository는 Fork가 된 버전입니다. 실제 Repo는 private organization에 저장되어 있으며 지속 유지보수 중입니다. 따라서 커밋 기록과 코드는 실제와 다를 수 있음을 알려드립니다.