ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 서울대학교 컴퓨터공학과 "모바일 컴퓨팅과 응용" 과목 수강 후기
    카테고리 없음 2020. 12. 28. 23:36

    모바일 컴퓨팅과 응용(이하 모컴응) 과목은 각종 사이트에서의 수강평이 적은 전공선택 과목으로, 강의하는 교수님이 이 과목을 맡아 가르친 업력이 짧은 것이 그 원인으로 보였습니다.

    짧은 수강평과 실라버스를 미루어 논문 팔로우 정도의 강의이며, 안드로이드 프로그래밍이 강의 중간중간에 섞여 있는 정도를 확인했습니다. 모바일 앱 개발과 관련되나, 아주 프랙티컬한 개발방법론을 다루지는 않을 것이라는 느낌을 받았습니다.

    클라이언트 개발을 어느 정도 할 줄 알아 무난하게 수강할 수 있겠다고 생각해서 수강하게 되었습니다.

    첫 전공선택 조별과제의 시작

    우리 과가 학교를 칼졸업하기 위해서는 이수해야 하는 졸업필수 과목이 빡빡하게 많아서, 3학년 1학기까지 다니면서 전공선택 과목을 들어본 적이 없습니다. 이 과목은 4학년 과목으로, 교수님은 초반부터 다음과 같은 사항을 명확하게 했습니다.

    1. 중간고사는 진행하지 않으며, 대신 어플리케이션을 4인 1조로 개발하는 조별과제가 있다.
    2. 조별과제는 프로포절, 중간발표, 기말발표로 이루어지고, 4학년 과목 특성상 이미 개발 능력이 어느 정도 있음을 가정하고 진행한다.

    적당히 기말고사와 조별과제가 있는 과목이고, 지필고사보다는 과제 형식의 수업을 선호하므로 그대로 수강하기로 했습니다. 강의 게시판에 이력을 써서 공고를 올려 팀빌딩을 했습니다.

    비록 실습 세션은 안드로이드 자바로 이루어져 있었지만, 조별과제 어플리케이션의 플랫폼에 제약을 두지 않았습니다. 따라서 좀더 익숙한 iOS 어플리케이션을 개발하고 싶었으나, 개발하려면 맥을 구해야 하는 iOS 앱의 특수성상 좀처럼 구하지 못했습니다. 따라서 희망을 접고 안드로이드 어플리케이션을 개발하기로 했습니다.

    6개 조로 나누어져 있었는데, iOS 네이티브와 플루터로 개발한 조도 있었습니다. 플랫폼이야 사실 아무래도 상관이 없다지만 익숙한거로 하는 게 제일이죠.

    전공선택의 조별과제를 처음으로 듣습니다만, 상당히 원활히 들어가는 듯한 느낌이 들었습니다. 졸업필수라서 꾸역꾸역 듣는 게 아니라, 경향상 안 맞는다고 느껴지면 바로 수강취소할 수 있는 점이 다른 것일까요?

    팀메이트의 구성

    이 팀은 제가 게시판을 올린 뒤에 사실상 선착순으로 구한 팀으로 만들었습니다.

    A씨 : 14학번으로, 경영학 전공인데 컴퓨터공학을 복수전공한 분입니다. 서버 개발 신입으로 구직을 하고 있었으며 졸업학기셨습니다.
    B씨 : 14학번 단일전공생으로, 군대를 마치고 4학년을 다니고 있는 분입니다. 장고로 꽤나 많은 개발을 해 오셨습니다.
    C군: 저와 동학번인 15학번 졸업학기를 다니고 있는 단일전공생으로, 복학 전에 가끔씩 마주친 적이 있습니다.

    제가 아무래도 어플리케이션 개발의 도메인에 능숙하므로 초기 매니징은 제가 이끌어가게 되었습니다. 대략적인 룰은 다음과 같습니다.

     

    1. 업무적으로 필요한 사항은 슬랙에서 진행한다.
    2. 어도비 XD로 진행하되, 만들어진 화면은 제플린으로 공유한다.
    3. 도큐멘테이션은 노션으로 정리한다.
    4. 어플리케이션이 잘 개발되는 지 확인하기 위해서, 일주일에 두 번 정도는 오프라인 킥오프를 한다.

    뭐 전형적인 어플리케이션 개발 프로세스라고 할 수 있었습니다. 대략적으로 역할 분배를 결정지은 뒤에, 어플리케이션 컨셉에 대해서 작업이 들어갔습니다.

    WebRTC를 활용한 화상통화 어플리케이션 작성

    풀타임 근무가 아니고 가끔 작업할 때, 4인의 개발자가 3개월동안 만들어낼 수 있는 어플리케이션의 공수를 가늠해 볼 때 그렇게 많은 기능을 넣을 수가 없습니다.

    회원가입의 과정을 없애고 게시판 수가 하나 이상 되지 않는, 심플한 커뮤니티성 어플리케이션 정도가 아슬아슬한 수준이라고 생각합니다.

    그정도 공수를 감안할 때, 핵심 기능은 적당한 난이도의 단 하나를 끼워넣을 수 있습니다. 구글 안드로이드 공식 사이트에서 여러 개를 고민하다가, webrtc를 이용한 화상통신 어플리케이션을 만들기로 최종 결정하였습니다.
    codelabs.developers.google.com/?cat=android

     

    Google Codelabs

    Google Developers Codelabs provide a guided, tutorial, hands-on coding experience. Most codelabs will step you through the process of building a small application, or adding a new feature to an existing application. They cover a wide range of topics such a

    codelabs.developers.google.com

    [검토했던 목록들]

     

    기술은 화상통신 어플리케이션으로 했고, 컨셉은 두 명의 유저가 밥을 같이 먹을 때를 가정한다는 것으로 정했습니다. 그래서 코이터Coeater 앱을 컨셉으로 프로포절을 진행했습니다.

    WebRTC와 화상 통화의 개발

    요즘은 대부분의 고급 기능들이 래핑되어, 개발자는 api만 하루이틀 문서 읽으면 휘리릭 붙여볼 수 있는 것이 대부분입니다. webrtc는 다만, 기초적인 작업이 여러 방면으로 이루어져 있어서 여러 군데를 동시에 건드려야 하므로 조금 더 까다로웠다고 생각합니다.

    안드로이드 클라이언트: google에서 제공하는 webrtc 래핑 클라이언트를 활용해, 클라이언트 사이에서 중계를 하도록 합니다.
    시그널링 서버: 두 클라이언트가 서로 화상통신을 하기 위해서는, webrtc 에서는 세션디스크립션 등의 두 클라이언트의 정보를 주고받는 과정이 필요합니다. 이 과정은 따로 규격을 정의해 둔 것이 없으므로, 소켓 통신 등을 이용해서 자유롭게 구현하는 것이 일반적입니다. 이 용도를 위해 만들어지는 서버입니다.
    턴/스턴 서버: 안드로이드 클라이언트와 시그널링 서버만 있어도, 같은 와이파이 회선 상에서는 정상적으로 동작합니다. 하지만, 서로 다른 회선에서 화상통화를 하려면, 영상정보를 중계하는 턴 / 스턴 서버의 배포가 필요합니다.

    턴/스턴 서버가 반드시 존재해야하는 것을 감안하지 못하고 개발했기 때문에, 중계가 잘 안 되는 이유를 근본적으로 진단하지 못해서 어려움을 겪었습니다. 이를 알았다면, 모든 테스트를 동일한 네트워크 회선에서 진행했을 것입니다.

    아무튼 다양한 코드들을 검토하고 시도해보면서, 적당히 돌아가는 프로토타입 화상통화 어플리케이션을 만들어 중간발표를 무난하게 진행했습니다.

     

    대략적인 빌드가능한 샘플은 웹 버전이나, 아래 링크가 제일 명확하다고 생각합니다.

    codelabs.developers.google.com/codelabs/webrtc-web#0

     

    Real time communication with WebRTC  |  Google Codelabs

    Learn how to stream media and data between two browsers. Get to grips with the core APIs and technologies of WebRTC. Capture and manipulate images using getUserMedia, CSS, and the canvas element. Set up a peer connection and exchange data directly between

    codelabs.developers.google.com

     

    안드로이드 어플리케이션의 설계

    저를 제외한 다른 조원은 안드로이드 플랫폼에 대한 이해가 낮거나, 자바 안드로이드 환경에서만 경험했습니다. 저는 코틀린과 리액티브 환경에 익숙했는데, 이 프로젝트의 대략적인 기술 스택을 정할 필요가 있었습니다.

     

    RxJava가 동시성 잡는데 좋다지만, 그걸 굳이 배워가면서 할 필요는 없다고 생각되었습니다.

    안드로이드는 액티비티에 모든 네트워크 통신을 우겨넣으면 코드가 복잡해질 뿐만 아니라, 간단한 어플리케이션에서는 중요도가 비교적 떨어지는 스레드 관리 문제때문에, 코드의 가독성이 크게 떨어지는 문제가 있습니다. 물론 어플리케이션의 복잡도가 올라가면 스레드 관리를 신경써야 하지만, 3개월 짜리 프로젝트에 스레드까지 챙겨갈 이유는 없습니다.

     

    따라서 자바보다는 비교적 유연한 코틀린을 메인 언어로, LiveData와 코루틴을 이용해서 ViewModel을 만드는, 간단하지만 명확한 설계로 가기로 했습니다. LiveData와 코루틴을 쓰면 RxJava를 굳이 공부할 필요는 없되, 핸들러를 이용해서 스레드를 바꿔주는 행동은 굳이 신경쓰지 않아도 되는 장점이 있습니다.

     

    당시 조원들에게 넘겨준 문서를 인용합니다.

     


    class SplashViewModel(
        private val api: AuthApi,
        private val userManageProvider: UserManageProvider
    ) : ViewModel() {
    
        val isLoginSuccess: MutableLiveData<Boolean> by lazy {
            MutableLiveData<Boolean>()
        }
    
        fun onCreate() {
            viewModelScope.launch(Dispatchers.IO) {
                val instanceId = getInstanceId()
                when (val myInfo = getMyInfo(instanceId)) {
                    is Result.Success<UserManage> -> {
                        userManageProvider.updateUserManage(myInfo.data)
                        isLoginSuccess.postValue(true)
                    }
                    is Error -> {
                        isLoginSuccess.postValue(false)
                    }
                }
            }
        }
    
        private fun getInstanceId(): String {
            return FirebaseInstanceId.getInstance().id
        }
    
        private suspend fun getMyInfo(uid: String): Result<UserManage> {
            return try {
                val response = api.register(uid, uid)
                Result.Success(response)
            } catch (e: HttpException) {
                login(uid)
            } catch (e: Exception) {
                Result.Error(e)
            }
        }
    
        private suspend fun login(uid: String): Result<UserManage> {
            return try {
                val response = api.login(uid)
                Result.Success(response)
            } catch (e: HttpException) {
                Result.Error(e)
            } catch (e: Exception) {
                Result.Error(e)
            }
        }
    }

    도커를 쓸 줄 알았다면..?

    발표하기 직전에, 불상의 이유로 코턴 서버가 다운된 적이 있었습니다. 문제는 코턴 서버를 구축할 때 과정을 적절히 문서화하지 않아서, 기억을 더듬어가면서 겨우 구축할 수 있었습니다.

    만약 도커를 쓸 줄 알았다면, 도커 컨테이너에 코턴 서버를 격리해 두었을 수 있었기 때문에, 좀더 원활히 구축할 수 있었을 것 같습니다.

    서비스의 고도화

    기초적인 프로토타이핑은 중간발표때 의미있을 정도로 끝냈으니, 기말발표에는 조금 더 발전된 단일 어플리케이션을 만드는 데 집중했습니다.

    본래 목적은, 화상통화 기능에 얼굴인식 SDK나, 화면 공유 SDK를 붙여서, 얼굴을 트래킹하고 이모티콘을 붙이는 피처를 만드는 것이었습니다.

    webrtc의 원천인 웹프론트에서는 비교적 용이하게 만들 수 있는 기능이었는지 모르나, 안드로이드로 한번 래핑되고 나니 생각만큼 호락호락하지 않은 작업이었습니다.

    프레임을 후킹해서 직접 하려니 성능이 떨어지는 문제가 있었고, 필터를 붙이려면 opengl 라이브러리를 활용해야 하는 문제가 있었습니다. 또한, 얼굴 인식의 성능이 앱이 호리즌탈 모드일 때만 높은 문제들이 있었습니다.

    그런 고로, 이런 고급 기능은 버리고, 소켓 통신을 이용한 게이미피케이션 기능을 서너 개 붙여서 마무리짓기로 결론내렸습니다.

     

    추가한 피처는 세 개입니다:

    1. 로티 라이브러리를 사용해서, 이모지를 보내면 상대방 클라이언트의 동일한 좌표에 뿌려주는 피처
    2. 시그널링 서버를 조금 매만져서, 서로 O/X 게임을 진행하는 이구동성 게임 피처
    3. 유투브 api를 이용하여, 한 유저가 유투브를 공유하면 두 클라이언트가 동시에 볼 수 있도록 설정합니다.

    발표와 디자인

    네 명이 모두 개발에 몰두하는 성향일 경우에, 오히려 최종 프로덕트가 더 뒤떨어지는 결과를 낳습니다. 앱을 런칭하는 데는 기획이나 디자인적인 요소가 더 큰 영향을 차지하곤 합니다.

     

    제가 쓴 초안과 최종 발표자료 before-after

     

     

    주된 안드로이드 개발이나 일정 관리는 제가 진행했지만, A씨와 B씨에게 디자인이나 프레젠테이션 작성, 발표에서는 많은 도움을 받았습니다. 특히 A씨의 제가 작성한 초안을 발표자료로 표현하는 능력에 감탄했습니다.

    또 이 강의가 영어강의이므로, 발표를 영어로 진행해야 했습니다. 저는 영어 발표를 괴멸적으로 못하기 때문에, 여기서도 영어가 유창한 A씨의 도움을 많이 받았습니다.

    아쉬웠던 점

     

     

    평소에 개인앱은 많이 만들어 봤는데, 3개월이라는 짧은 시간 안에 그래도 소규모의 어플리케이션을 만들어볼 수 있는 기회를 얻었다고 생각합니다.

    조원의 다양한 서버, 클라이언트, 디자인 구성으로 인해서 효율적으로 개발 작업을 할 수 있었는데, 처음 구상했던 프로덕트와, 막상 완료된 어플리케이션에 괴리가 생겨서 아쉽습니다.

    아자르같은 핫한 화상통화 어플리케이션을 만들 수는 없었겠지만, 조금 더 기획에 엣지 포인트를 주었으면, 효율적으로 매력적인 프로덕트를 만들어낼 수 있었다는 생각이 듭니다. 일단 화상통화 기능이기 때문에, 괴멸적으로 신규 유저가 없는 상황에서는 설치를 기대하기가 지극히 어렵다는 게 가장 큰 문제입니다. 코턴 서버를 유지시킨다면 상당한 비용이 들 것이므로, 조만간 어플리케이션은 내려야 되지 않을까 싶습니다.

    발표 자료

    이 프로젝트의 발표 자료와 코드를 첨부합니다.

    클라이언트 코드 : https://github.com/coeater/coeater-android

     

    coeater/coeater-android

    Android Client for Co-eater Application. Contribute to coeater/coeater-android development by creating an account on GitHub.

    github.com

    Rest API 서버 코드 : https://github.com/coeater/coeater-rest

     

    coeater/coeater-rest

    REST API. Contribute to coeater/coeater-rest development by creating an account on GitHub.

    github.com

    시그널링 서버 코드 : https://github.com/coeater/coeater-signalserver

     

    coeater/coeater-signalserver

    Typescript-base Coeater Signal Server. Contribute to coeater/coeater-signalserver development by creating an account on GitHub.

    github.com

    최종 발표 프레젠테이션 : https://github.com/coeater/presentation/blob/master/Co-Eater_final_vf.pdf

     

    coeater/presentation

    coeater project presentation. Contribute to coeater/presentation development by creating an account on GitHub.

    github.com

     

Designed by Tistory.