2018 한 해를 돌아보며…

2018년.

기나고도 짧은 1년이 지나가고, 이제 2019년이 다가옵니다.

그런 기념으로, 2018년의 중요하고 변화점이나 느낀 점을 살펴보고 2019년에 달성하고 싶은 목표를 적어보려 합니다. (물론 개발적으로요.)

1월 – PyxisBaseApp (MVVM + Dagger)

2018년 1월 20일, PyxisBaseApp라는 MVVM + Dagger + Databinding + Retrofit 스택을 가진 베이스 앱을 작성하기 시작, 2018년 12월 31일 기준으로 배포 버전 1.3.3, 커밋 수 316개의 적당한 규모의 베이스 앱을 제작하였습니다.

이 베이스앱의 전/후로 지금까지의 본인 안에서의 개발 패러다임이 바뀌었는데, 전에는 일정한 패턴 없이 Activity 하나에 집중하는 형태였다면 지금은 일정한 패턴을 따라서 MVVM 과 Continous Integration을 목적으로 개발하고 있습니다.

이 때 MVP를 거치지 않고 MVVM으로 바로 거친 이유로는 당시 같은 회사에 계셨던 개발자분이 MVP를 사용하셨는데 이 구조를 보니까 Activity – Contract – Presenter가 강제되는 형태로 조금 비효율적으로 보였기 때문입니다 . 그리고 마침, 안드로이드에서 Android Architecture Component 라고 하는 구조가 나왔었기에 MVVM을 좀 더 쉽게 작성할 수 있었습니다.

이렇게 PyxisBaseApp는 계속해서 변화를 거쳐 9월 29일에는 JFrog Artifactory를 통해 본격적인 라이브러리 형태의 베이스 앱을 제작했고, 나름대로 만족할 구조가 탄생하였습니다.

3월 – Annotation Processor

1월과 2월에는 MVVM 구조를 중점으로 적용했다면, 3월에는 중복되는 코드를 줄이기 위한 Annotation Processor에 대해 집중했습니다.

지금까지 어노테이션을 Reflection 을 통한 접근방법만 사용했었는데, 타겟으로 하는 어노테이션이 있는 클래스나 메서드 대상으로 코드를 생성하는 Annotation Processor의 도입으로 Dagger의 Activity, Fragment, ViewModel의 주입이 어노테이션 하나를 부착하는 것 만으로도 끝나고, CustomView의 Attribute 파싱 등을 빠르게 할 수 있었습니다.

물론, 이 떄 공부한 지식으로 Annotation Processor 기반 기술을 도입하거나 분석할 때 큰 도움이 되었기도 했습니다. (Databinding나 Dagger 등)

7월 – RxJava

계속 미루고 왔었던 RxJava 도입을 이 때부터 시작하였습니다. 처음에는 Listener 형태의 Callback를 Observable로 변경하는 것에서부터 Socket 통신의 RxJava wrapper까지 작성하면서 이전에는 쉽게 달성하지 못했던 스레드 관리나 데이터 소스로부터의 효율적인 합성을 달성하였습니다.

그리고 이 때, SocialLogin 기능과 RxJava를 합친 RxSocialLogin(https://github.com/WindSekirun/RxSocialLogin)을 개발하고 배포하였습니다.

8월

산업기능요원으로 근무하다보면 언젠가 찾아오는 시련인 훈련소(._. )를 다녀왔습니다. 따라서 이 때는 기록이 없습니다.

9월 – Docker를 통한 SaaS 컨테이너 배포

이 때까지 PyxisBaseApp는 프로젝트마다 멀티모듈로 포함되어 있었기에 버전 관리가 안되고, 여러 프로젝트마다 다른 베이스 앱 코드를 가지고 있었기에 코드 관리도 더더욱 힘들었습니다.

그래서 Docker를 공부하고 새 인스턴스에 JFrog Artifactory를 올리고 PyxisBaseApp를 모듈 단위 배포가 아닌 라이브러리 형태 배포로 변경하였습니다.

추가적으로, 처음으로 BLE 앱을 원개발하면서 RxAndroidBle(https://github.com/Polidea/RxAndroidBle) 도 사용해보았습니다. 다소 어려웠지만 notify, write 이벤트를 쉽게 처리할 수 있었던 것이 가장 마음에 들었습니다.

12월 – Jenkins 도입

이전에는 CircleCI를 사용했었으나 Private project에는 적용하지 못하고 오픈 소스 프로젝트만 사용하였습니다. 그래서, 꽤나 이전부터 계획은 있었음에도 쉽게 도입할 수 없었던 Jenkins를 Docker의 힘을 빌려 사용하게 되었습니다.

그리고 12월 25일, 대망의 확장 공사를 시작하면서 지금까지 분리되어있던 블로그 인스턴스 + (Artifactory/Jenkins) 인스턴스를 합쳐 지금의 인스턴스로 이사하면서 메일 서버나 FTP 서버 등도 전부 Docker를 통해 관리하게 되었습니다.

마무리

2018년에만 공부하고, 새로 도입해서 실제 사용한 기술이 MVVM, DataBinding, RxJava, Dagger (DI), Retrofit, ObjectBox, Docker, Jenkins, AndroidX, Static Analysis 로 작은 것 까지 포함하면 20개는 족히 넘을 것 같습니다.

2019년에는 빠르게 변화하기 보다는 기존에 사용하던 기술을 좀 더 가다듬어 좀 더 전문적인 지식을 가질 수 있도록 열심히 갈고 닦아야 될 것 같습니다.

그리고, 대망의 그 날(2019-04-19)도 얼마 남지 않았고요. 후후…

GDG Devfest Seoul 2018 참가 후기

Shot on Galaxy S8 @세종대학교 광개토관 입구

2018. 11. 10. 토요일에 세종대학교 광개토관에서 개최된 GDG Devfest Seoul 2018 에 일반 참가자로 참여했습니다.

개발 관련 컨퍼런스 참여는 이번이 두 번째로, 첫 번째는 소규모로 진행된 모임 식의 컨퍼런스였고, 두 번째가 금일 참가한 Devfest 입니다.

Shot on Galaxy S8

이 중, ‘Data Uni-Directional Architecture in Android’, ‘함수형 프로그래밍과 안드로이드 테스팅’, ‘빠르다는 것 그 이상, Isomorphic PWA’, ‘Android DataBinding for Modularization, ViewModel and Testing’ 총 4개 세션에 대해 참가하였으며, 마지막 세션은 개인 사정으로 인하여 불참하였습니다.

각 세션에 대해 총평을 하기 전 부스에 대해 간단히 설명해보자면, 참여한 부스는 GDG Developer, 카카오페이, 레이니스트, 알지피코리아, 크래커나인 5개 부스로 (나머지 1개 부스도 있었지만 갈 당시에는 부스 준비중이라 참여를 못했습니다.) 이 중 그나마 관심이 갔던 것이 크래커나인 이었습니다.

다만 막상 설명을 들었을 때 제플린과는 호환이 안된다는 것을 알게 되어 조금 아쉬웠던 점도 있습니다. (직원분 말씀으로는 Sketch에서 export 하신다고 하였지만, 현재 회사에서 디자인 부서는 제플린을 사용하고 있기 때문입니다.) 다만 다음에 Sketch를 사용할 일이 있다면 꼭 사용해보고 싶은 기능일 만큼 충분히 매력적이긴 합니다.

이제 들었던 4개의 세션에 대해 간단히 말하려고 합니다.

Data Uni-Directional Architecture in Android

Uni-Directional Architecture (단뱡항 아키텍쳐) 를 대상으로 강의를 진행하셨고, Flux, Redux, MVI에 대해 각각이 가지는 속성과 차이점에 대해 코드와 같이 진행되었습니다.

이전 MVI에 대해 접해본 적은 매주 발송되는 Android Weekly나 Medium에서 발행되는 포스트밖에 없어 실제로 어떤 개념인지에 대해 명확히 알지는 못했는데, 나름대로 강의를 듣고 정리하였습니다.

먼저, View 와 State 간의 분리를 진행하고 State가 한 방향에서만 수정을 할 수 있다는 것이 UDA의 중점 개념이었던 것 같습니다. State 와 View가 각각 영향을 줄 경우에는 모든 작업이 비동기적으로 이루어지기 때문에 언제 어느 액션이 발생했는지 모르고, 이에 따라 사용자에겐 버그로 보일 수 있기 때문입니다.

따라서 하나의 작업이 끝나면 다음 작업을 진행하는 ‘동기적 작업’ 을 이용해 작업이 순차적으로 진행될 수 있게 하고, 그 과정에서 State의 관리에 이점을 가지거나 State의 변경 지점이 명확해지기 때문에 코드에 대한 안정성이 높아진다는 것 같았습니다.

Capture on https://speakerdeck.com/maryang/data-uni-directional-architecture-uda-in-android?slide=72

즉 위의 사진이 중점 포인트라고 할 수 있습니다.

하지만 현재 사용하는 패턴이 DataBinding와 RxJava를 이용한 MVVM 패턴이고, 데이터 바인딩의 양방향 데이터바인딩은 UDA에서 제시하는 단방향 접근으로 되지 않기 때문에 적용하기 힘든 부분이 있다고 판단했습니다. 이에 관련되어 질문을 드리려 했으나, 앞에 있던 사람이 먼저 질문하여 같이 답변받았으나 데이터바인딩과는 호환이 좀 어렵다고 답변을 받았습니다.

다만 복잡한 State의 관리가 필요한 곳에 부분적으로 도입하면 괜찮을 것 같다는 생각이 있었습니다.

함수형 프로그래밍과 안드로이드 테스팅

안드로이드의 테스트인 Local과 Instrument 테스트 중에서 Local 테스트, 즉 단위 테스트에 관련된 강의였습니다.

이 강의에서는 테스트 가능한 코드를 잘 작성하기 위한 전략에 대한 강의를 진행하셨는데, 중점이 된 사항이 있습니다.

테스트 가능한 코드와 불가능한 코드 분리

단위 테스트에 사용되는 android.jar 는 실제 코드를 포함하고 있지 않은 파일이기 때문에 Android Platform API에 의존하는 코드는 테스트가 불가능합니다. 반면에 Android Platform API에 의존하지 않는 순수 비지니스 로직은 테스트가 가능합니다.

MVP 패턴에서는 Presenter를, MVVM 패턴에서는 ViewModel를 테스트 가능하게 하려면 Android의 어떤 Platform API에 의존하지 않게 하여 Mock이 필요 없이 검증만 하면 되는 방식으로 진행해야 된다고 했던 것 같습니다.

View는 최대한 Passive하게 작성

이 말은, View는 어떤 비지니스 로직을 가지지 않고 Passive 하게 (a.k.a 멍청하게) 작성하는 것을 으미합니다.

위 두 사항을 제대로 반영하려면, 함수형 프로그래밍에 나오는 순수 함수(Pure Function. 다른 말로는 1급 함수라고도 합니다.) 를 적용하면 되는데, 순수 함수는 외부의 다른 State에 대해 영향을 받지 않고 주어진 Input에 대해 항시 같은 Output를 반환하는 함수입니다. 이렇기 때문에 순수함수는 그 특성 덕분에 Side effect가 없으며, 프로젝트의 종속적이지도 않게 되기 때문에 재사용성이 가능합니다.

이 순수함수를 이용하여 작성하게 되면, 작성한 비지니스 로직의 테스트는 해당 메서드의 반환이 예상한 대로 도출되었는지 확인하면 됩니다.

전체적으로 이미 알고 있던 내용이었지만, 지금 본인이 구성하고 있는 ViewModel 이 Android Platform API에 반쯤은 의존하고 있었다는 사실이 조금 아쉽게 느껴졌습니다. 그래서 본 강의를 들으면서 비지니스 로직을 최대한 분리하는 방향으로 설계를 해야 되는가 싶기도 했습니다.

빠르다는 것 그 이상, Isomorphic PWA

왜 갑자기 다음 Mobile 세션인 Flutter를 듣지 않고 이 강의를 듣게 된 것은, 2주 전 쯤에 전 회사 동료와 현 회사 동료 3명이서 같이 저녁을 먹은 적이 있었는데, 그때 나온 이야기가 PWA에 대한 이야기였기 때문입니다.

그 개발자가 ‘싱글 페이지에 라우터를 부착하여 렌더링을 진행하고, 서비스 워커로 네이티브 기능을 활용할 수 있다’ 라는 말을 했었는데, 그 말을 듣고 어느정도 찾아보았으나 프론트엔드 개발을 진행한 경험이 거의 없기 때문에(아주 예전에 AngluarJS + Cordova로 하이브리드 앱 프로젝트를 진행한 적이 있었긴 했다.) 애매하만 이해하고 있었습니다.

그래서 이 세션이 있다는 것을 보고, 지금은 정확히 알지 못해도 차후에 서비스를 설계할 때 큰 도움이 될 수 있지 않을까 하는 생각에 들었습니다.

해당 강의에서는 ‘느린 웹은 사용자에게 공포 영화보다 더 큰 공포를 준다‘ 라는 말로 시작하면서 서비스의 웹 앱에 대해 Dynamic Code Splitting, Lazy Loading, Server-Side Rendering, SPA 등을 활용하여 사용자가 웹을 로드하고 인풋을 받을 때까지의 시간(First Interactive Time)을 최소화하는 기나긴 과정을 설명했습니다.

먼저 SPA(Single Page App) 에 다루었는데, 기존의 HTML 파일 단위로 링크를 이동하는 것이 아닌 하나의 앱 안에서 라우터(Router)로 경로를 불러오는 기술을 말합니다. 이로서 얻는 이점은 파일 단위로 링크를 이동하는 것이 아니기 때문에 캐시 처리에 용이하고, 로드가 끝난 다음에는 마치 네이티브와 같은 네비게이션을 보여주기 때문입니다.

다만 이 SPA에도 단점이 있다면, 처음 로드하는 시간이 매우 길다는 것입니다. 그에 대한 근본적인 문제는 Javascript, 즉 JS 파일이 로드되기 위해서는 Parse / Compile / Execute 과정을 거쳐야 하는데 이 과정이 브라우저의 메인 스레드를 블로킹하여 진행되기 때문에 사용자는 작업이 끝날 때 까지 기다려야 합니다.

The Cost of Javascript, https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e

위 사진은 같은 용량(170KB) 인 JS 파일과 JPEG 파일을 로드했을 때 로드하는 데에 걸리는 시간을 측정한 것입니다. 여기서 JPEG는 0.1초 안에 모든 작업이 완료되었음을 알 수 있지만, JS의 경우 최대 3초까지 작업이 걸린다는 것을 알 수 있습니다.


The Cost of Javascript, https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e

이렇기 때문에 JS 파일의 사이즈를 줄여 로드하는 시간을 최소화하는 방법이 있는데, 그것이 구글에서 발표한 PRPL (Push Render Pre-cache Lazy-Load) Pattern이다. PRPL 패턴은 MVVM와 같이 디자인 패턴의 한 종류가 아닌 웹을 배포할 때의 예시 패턴이라고 볼 수 있습니다.

PRPL의 주요 관점은 주요 리소스를 먼저 로드하고, Route를 진행합니다. 이 과정에서 불러올 확률이 낮은 것들은 해당 Route가 불렸을 때 Lazy Load 하는 것입니다.


The Cost of Javascript, https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e

이와 관련해서 Dynamic Code Splitting 과 Lazy Load가 사용되는데, 이는 상기되었던 사항과 같이 JavaScript 로드는 메인 스레드를 블로킹하여 진행되기 때문에 Router 기반으로 페이지를 잘게 나눠 처음에 클라이언트에 렌더링 목적으로 전송되는 JS 파일을 최소화하는 것입니다.

중요 컴포넌트(랜딩, 또는 방문 페이지를 분석했을 때 사용자가 처음에 방문할 확률이 높은 페이지)는 초기 로드때 가져오며, 나머지는 비동기나 Lazy Load를 처리합니다. 해당 강연자는 React를 사용하고 있었기에 React-Loadable 라는 라이브러리를 사용했다고 합니다.

그 다음, Minify 와 Compress가 있는데, 컴포넌트 별로 분리한 JS를 한번 더 압축시키는 것입니다. Minify 에는 Webpack를, Compress에는 일반적으로 사용되는 gzip를 사용했다고 합니다.

상기 문단에 잠깐 설명되었던 중요 컴포넌트에 대해서, 방문자 수의 95%를 차지하는 것이 랜딩 페이지 및 이벤트 정보 페이지이기 때문에 사용자가 인풋을 하기 보다는 정보를 표시하는 페이지로 분류된다고 설명하면서, 사용자가 필요한 정보를 빠르게 노출하여 First Time를 줄이는 것이 좀 더 효과적이라고 했는데 그 사항을 달성하기 위해 도입한 것이 Server-Side Rendering라고 합니다.

Server-Side Rendering의 경우 서버와 클라이언트 둘 다 렌더링을 하여 클라이언트단에서 렌더링 하는 시간을 최적화 하는 것이라고 표현할 수 있습니다.

Draw by draw.io, 필기로 그린 것으로 원래 자료와는 다소 차이점을 보일 수 있습니다.

간단히 도식화하면 위와 같은데, 클라이언트단에서 최상단 / 를 요청하면 서버가 렌더링한 Static file를 내려주고, 클라이언트에서는 assets를 다운로드 받으며 렌더링을 진행합니다. 서버가 렌더링한 SSR HTML 과 클라이언트가 렌더링한 CSR HTML 이 같으면 이상적(Isomorphic) 로 표현한다는 것이라고 설명하셨습니다.

이 과정에서 서버가 렌더링 할 때 API 요청이 필요한데, 서버가 렌더링 할 때에는 클라이언트가 렌더링할 때와는 다르게 DOM 객체가 존재하지 않고, React에서의 Lifecycle가 호출되지 않기 때문에(정확히는 라이프사이클에서 비동기적 처리가 되지 않는다고 하셨는데, 정확히 들은건지는 모르겠다.) 분기 처리를 다 해야 된다고 말했던 것 같습니다.

마지막으로 짧은 시간을 남기고 PWA에 대해 설명했는데, PWA 체크리스트 상의 항목을 만족하면 된다고는 했었는데 너무 빨라서 정확히 듣지 못했으므로 차후에 포스팅으로 정리할 수 있으면 정리하려 합니다.

Android DataBinding for Modularization, ViewModel and Testing

이 강의에서는 Databinding 의 기본 사용법 (표현식, 어노테이션, 양방향 데이터바인딩)에 대해 설명하고, 데이터바인딩이 내부에서 어떻게 작동하고 작동되는 코드에 영향을 주는 dirtyFlags가 어떻게 매핑되어 구성되어 있는지에 대해 설명했습니다.

다만 이 강의에 대해서는 별로 집중하지 못했는데, 아마 Android Dev Summit 2018의 이 세션과 60% 이상 동일하다고 할 수 있습니다.

다만 마지막의 dirtyFlags 에 대해서는 지금까지 데이터바인딩을 사용하면서도 내부 코드를 분석해도 표현식이 어떻게 바인딩 어댑터에 사용되는지를 확인했을 뿐이지, 그 곳에 존재하는 dirtyFlag에 대해서는 신경을 쓰지 않았기 때문에 새로운 내용이었습니다.

이에 관련해서는 차후에 따로 정리하겠습니다.

마무리

전체적으로 4개 세션에 대해 평가하자면 대체적으로 만족했습니다. 가장 아쉽게 느낀 것은, 평소에 잘 알고 있는 사항이 아니라 애매하게 알고 있던 사항이나 모르는 사항에 대해 들었으면 좀 더 유익한 시간이 되지 않을까 싶었습니다.

다시 시간을 돌린다면, ‘GCP를 활용하여 코딩 없이 앱 서비스 분석 인프라 구축한 삽질기’ 와 ‘실전 SPA 상태관리 톺아보기’, ‘GTA5를 이용한 자율주행 자동차 만들기’ 를 듣고 싶다고 막연하게 생각했었습니다.

아마 다음 참여할 컨퍼런스는 11월 22일(목요일) 에 열리는 JetBrains Day 서울 2018로, 처음 코틀린을 접할 때 큰 도움이 된 강사분인 Hadi Hariri가 직접 와서 강의하니 좀 더 집중해서 들을 수 있을 것 같습니다.

마침 장소도 오늘과 같은 곳이니, 이번엔 덜 헤멜 수 있도록 바라면서 글을 마칩니다. 🙂

Upgrade PyxisPub to v2

기존에 사용하고 있던 Hestia 테마가 2.0 버전으로 올라가면서 Gutenberg 에디터에 대한 호환이 되지만, 여전히 Gutenberg 가 가지고 있는 블록에 대한 지원은 반 정도만 지원하는 문제가 있었습니다.

그래서, Gutenberg 호환 및 블록 사용 가능 및 content-width 조정이 가능한 테마를 찾아보니 Atomic Blocks Theme 가 사용 가능한 것 같아 바로 적용을 시작했습니다.

따라서 이 글에서는 주요 변경 사항을 공지합니다.

로고 & 새 블로그 부제목

버전 2에 맞춰 블로그 부제목을 Developing History 에서 Development Life 로 변경하였습니다. 사용한 폰트는 Hanken round 이며 라이센스가 공개된 폰트를 사용했습니다.

사용한 색상은 #363a46(글자), #2e3340(원) 입니다.

단, 흰색의 P가 작아서 안 보이는 경우가 있기 때문에 실제 로고에 사용할 때에는 P 글자는 제외합니다.

나름대로 균형은 맞춘 것이라고 볼 수는 있을 것 같습니다(..)

테마 변경에 따른 구조 변경

기존 메인 페이지는 요약된 글 목록이 무한 스크롤 되게 처리되었지만, Atomic Blocks의 블로그 페이지에서는 글의 모든 내용이 펼쳐지므로 블로그에 접속할 때 성능 이슈가 있습니다.

따라서, 기존에 글 목록으로 제공하던 메인 페이지를 정적인 페이지로 제공하였습니다.

또한 하단에서 소개할 Full-width 지원을 위해 사이드바도 제외하였습니다. 카테고리 / 글 목록 / 히트 수에 대해서는 하단에 제공됩니다.

Full-Width 이미지 지원

Medium 처럼 이미지의 가로가 화면 기준 100%로 꽉 차게 하는 Full-width 지원을 시작했습니다. 또한 화면 기준 100% 이외에도 본문 기준 100%도 지원합니다.

라이센스 표기

사이트 맨 하단에 컨텐츠 라이센스에 대해 표기하였습니다.

그 외

그 외 사항으로는 사용하지 않는 이미지 70개에 대한 삭제 및 Opcache, CSS Cache 등을 비워 서버가 무리하지 않도록 반영하였습니다.

어느새 블로그를 운영한지 1년 4개월이 넘어간 것 같습니다. 앞으로도 더 꾸준히 포스팅 할 수 있도록 노력하겠습니다.