JetBrains Day 서울 2018 참가 후기

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

11월 10일 GDG Devfest Seoul에 이어 11월 22일 목요일 JetBrains Day 서울 2018에 참가하였습니다. 사이트에 따르면 약 1200명 규모로, 지하 1층과 지하 2층에서 진행되었습니다.

Shot on Galaxy S8

이 중 Keynote, Github의 DevOps, ChatOps 소개, Kotlin – What’s New, Kotlin/Anywhere, Kotlin에서 제공하는 Coroutines을 사용하는 방법, Kotlin @ Coupang Backend 적용기 에 참여하였습니다.

이번 글에서는 들었던 세션에 대해 정리를 하려 합니다.

Keynote – 기조연설: 개발자의 생산성을 높이기 위한 장벽 제거

강연자는 Hadi Hariri님으로, 본인에게 있어서는 코틀린을 처음 도입하려 할 때 이 분의 강의(Advance Kotlin Programming) 를 듣고 공부하였기에 실제로 강연을 듣는 것이 감격했습니다.

아무튼, 본 강연에서는 다른 전통적인 기업보다 JetBrains이 일하는 방식에 대해 소개하였는데, 이전 기업들이 9시에 출근해서 5시까지 근무하는 등 다소 fix된 근무를 하는 것이 아닌, 언제 어디서나 자신이 자유의지를 가지고 개발한다는 것(Breaking down the working hours barrier) 입니다.

실제로 어떤 개발자는 밤에 출근해서 다음날 아침에 가는 일도 많다고 하는데, 이는 모니터링 같은 것이 아니라 그 사람이 원해서 그렇게 근무한다고 예제를 들었습니다.

다만 이 규칙이 통하지 않을 때가 있는데, 바로 미팅(Meeting)입니다. ‘여기서 미팅 좋아하시는 분이 있으신가요?’ 라고 질문하셨을때, 아무도 손을 들지 않았습니다. (이 때 사진을 찍어야 겠다고 농담을 하셨던 것 같습니다)

미팅을 좋아하는 사람은 없다고 합니다. 미팅을 왜 좋아하지 않는가 하면, 대부분 나쁜 미팅을 하기 때문입니다. 여담으로 나쁜 미팅은 X같다고도 합니다. (Bad Meetings suck.)

여기서 나쁜 미팅이란, 실제로 얻어지는 결과는 없고 의미를 생성할 수 없는 미팅을 말합니다. 나쁜 미팅이 있는가 하면 좋은 미팅도 있길 마련입니다. 좋은 미팅은 반대로 실제로 행동 가능한 Action Items 를 창출하는 미팅입니다.

좋은 미팅을 위해서는 미팅의 목적을 정의할 필요가 있는데, 여기에서는 Coordination(동등) 과 Status Update(상태 업데이트) 가 있습니다. Coordination의 경우에는 가급적 단일 주제로 이야기 하며, 상기에서도 언급한 Action Items 를 가지고 나올 수 있도록 하는 것입니다.

Status Update는 나는 ‘오늘(이번주) 은 이 것을 했어’ 라고 자신이 수행한 업무에 대해 공유하는 것 입니다. 단순히 공유하는 것 뿐이라면 이 것은 가치를 생성하지는 않습니다.  서로를 믿고, 상호협력적으로 소통이 가능해야 합니다. Status Update를 돕기 위해서는 Tracking Tools나 Logging Standups를 사용할 수 있는데, 이 것으로 ‘목표 달성을 인지하는 것‘ 이 가능합니다.

무엇보다 Status Update를 하기 위해서는 여러 방법으로 서로를 알아가는 것이 좋습니다. 누가 어떤 일을 하는지 알 필요가 있습니다. 서로를 알아가는 방법에는 여러 방법이 있는데, 이메일을 최소화하고 이슈트래커를 활성화하는 것입니다.

여기서 이슈트래커는 단순히 디버그나 개발 이슈 등 기술적 문제뿐만이 아니라 일상적 이슈에도 사용하는 것입니다. 이메일은 다소 정중(Polite) 해서 내가 관심을 가지지 않는 것인데도 수신할 수 있습니다. 반면 이슈트래커는 자신이 관심이 있는 이슈라면 그 곳에서 댓글로 통해 이야기를 나눌 수 있으며, 관심이 떨어진 경우에는 빠질 수 있습니다.

그러면 이메일 대신 Slack는 어떠한가 싶으면, Slack협업 도구로서는 굉장히 좋은 도구임에도 불구하고 자칫하면 비생산성이 될 수 있습니다. (온라인 표시가 뜨기 때문에, 누군가 메세지를 보냈을 때 읽지 않는다면 ‘왜 이 것을 읽지 않죠?’ 라며 묻는 경우가 있다고 한다.)

이메일이나 이슈트래커, Slack등은 정보에 대해 발행하는 것(Push) 입니다. 반대로 정보를 수신하는 것(Pull) 에도 관심을 가져야 합니다. 여기에는 Wiki 가 대표적인 예로 들 수 있습니다. 다만 정보가 많으면 많을 수록 좋은 것이 아닌, 사람이 소화할 수 있는 정도여야 합니다.

다른 방법으로는 Internal Newsletter(사보) 가 있을 수 있습니다. 다른 팀에 속한 인원이 어떻게 일하고 있는지도 가끔은 인지할 필요하기 있기 때문입니다. 또, Internal Conference가 있을 수 있습니다. 이 컨퍼런스는 기술에 대한 것 뿐만이 아닌 세일즈, 마케팅 등 기술과 관련되지 않은 것도 상관 없습니다.

이러한 방법으로 미팅을 좋은 미팅으로 만들어도, Management 가 문제가 될 수 있습니다.

JetBrains 에서는 자잘한 관리나 보고가 없고, 어떠한 행동을 할 때 권한이 필요 없다고 합니다. 위의 사진과 같은 계층을 가진 회사라면 상사가 단순히 목표를 중시하며 목표를 달성하지 못하면 심한 말을 하는 경우가 있습니다. (흔히 이 사례로 KPI가 있는데, KPI를 도입하면 개발에 의해 생성되는 부가가치에 의미 없이, KPI 달성 그 자체가 목표가 되는 경우가 있다고 합니다.)

이러한 장벽을 없애면, 개발자에게 돌아오는 것은 자유 그 자체입니다. 다만 자유에는 비용이 있길 마련입니다.

자가 관리를 통해 개발자 자신을 관리해야 하며, 책임감 있게 업무를 수행해야 하며 어떤 일을 우선적으로 할 것인지에 대한 우선순위를 정해야 하고, 안될 때는 ‘NO’ 라고 말할 수 있어야 하고, 열정을 관리할 필요가 있습니다. (지나친 열정은 문제를 일으킬 수 있습니다.) 그리고 중요한 것은, 자신이 지금 하고 있는 일이 가치를 더할 수 있는 일인지 스스로에게 자문하는 것입니다.

그리고 이 자유는 사원과 사원간의 믿음이 있어야만 성립합니다. 그 사람을 믿지 못한다면 그 사람이 어떤 것을 해도 믿지 않을 것입니다.

상기 언급하였듯이 관리가 없으면 리더십은 있는가? 라고 질문할 수 있습니다. 여기서 리더십에 대한 정의가 필요할 것 같습니다.

먼저, 병목을 없애주는 힘을 가지고, 위임하는 법을 배우고, 가이드라인을 제공할 수 있어야 되며 남이 이야기하는 것을 경청하는 법을 아는 사람이 리더십을 가진 사람이라고 할 수 있습니다.

이러한 과정을 거쳐 문화를 만들어 냈다면, 문화를 유지하는 것도 중요합니다. 문화는 주입되는 것이므로 당신이 지켜낼 필요가 있습니다.

문화를 지켜내기 위해서는 피드백에 중점을 두고, 앉아서 변화를 기대하지 않고, 문화를 보호하지만 변화에는 열려있어야 합니다.

Trust in people. Care for people.
We'll do our best.

마지막으로, 이 슬라이드를 끝으로 강연은 종료되었습니다.

기조 연설인 만큼 어떠한 강연보다 길게 진행되었는데, 오늘 들은 강연 중에서는 제일 인상에 깊었던 강연입니다. 회사가 성립하기 위해서는 지속적인 성과를 낼 필요도 있지만, 서로를 믿고, 보호하고, 소통하면서 더 나은 부가가치를 생성할 필요도 있습니다.

지금 다니는 회사는 다소 산출물만 강요하는 특징이 있어 매일매일 하루가 끝나면 ‘드디어 오늘 하루가 끝났다…’ 라며 지치고는 하지만, 그래도 직원들 끼리는(임원진은… (._.;; )  서로를 믿고 의지하기 때문에 힘내서 업무를 진행할 수 있는 것도 있습니다.

그러면서 느낀 것이, 다음 회사는 서로를 좀 더 믿고 의지해주는 회사로 가고 싶다고 생각했습니다.

이 강연이 끝나고 안영회님의 ‘소프트웨어를 모르는 대한민국의 위기’란 주제로 강연이 열렸지만, 같이 온 일행이 너무 늦게 온 탓에 (9시 20분에 역에서 모이기로 해놓고, 정작 9시 45분에 도착해서) 부스를 못 돌아본 것도 있기 때문에 이 시간을 이용해서 부스를 돌았습니다.

Github의 DevOps, ChatOps 소개

점심시간 1시간 반을 거치고, 다음 강연인 ‘Github의 DevOps, ChatOps 소개’ 에 대해 참가하였습니다.

이번 강연은 Github에 근무하고 계시는 Christian Lewis 님으로, Github 가 Github를 어떻게 배포하고 관리하는지에 대해 설명했습니다.

Github는 지난 몇 년동안 급격하게 성장했음에도 불구하고 서비스를 유지하고 있는 큰 요소라 하면 4가지가 있는데, Common Philosophy (공통된 개발 철학)과 Asynchrous Communication(비동기적 소통), Continous Delivery(CD), ChatOps가 있습니다.

강연 제목에도 나와있듯이 ChatOps는 Github가 Github를 관리하기 유지하고 관리하기 위해 사용하는 요소로 주로 Hubot를 이용합니다.

Hubot는 대화형 봇의 일종으로 배포나 일련의 작업 루틴을 자동화하는 봇입니다. 작게는 이미지 검색이나 지도 검색, 때로는 소리 지르기(!) 등 일에 즐거움을 가져오는 반면, 사이트를 배포하거나 production에 통합하는 과정, 그리고 CI/CD와의 통합 등을 해낼 수 있습니다.

Hubot를 통해 특정 저장소의 기록을 트래킹할 수 있고, 누군가 배포를 시행하려고 할 때 하여금 다른 사원이 리뷰할 수 있게 도와주고, 배포가 된후 문제가 발생했을 때 누구보다도 빠르게 그 문제를 알아채서 알려주기도 합니다.

모든 작업은 브랜치에서 작업되기에 production에는 영향이 가지 않고, 수 많은 리뷰와 문제점 파악을 거친 후에 production에 반영되기 때문에 production에는 영향이 없습니다.

Shot on Galaxy S8

브랜치를 생성하고, PR을 열어 논의나 결론을 내고, Production에 병합할 것인지를 정합니다.

전체적으로 production을 실패시키지 않고 Pull request나 테스트를 통하여 서비스의 전체 유지성을 확보할 수 있습니다. 또한, 브랜치 안에서 실험, 테스트를 하고 문제가 발생했을 때 쉽게 버릴 수 있으므로 리스크 없이 개발 진행이 된다는 것이 포인트입니다.

Kotlin – What’s New

Shot on Galaxy S8

이번 강연은 지난달에 Kotlin 1.3이 정식 출시되면서 출시된 기능에 대해 정리한 강연으로, 기조연설때 강연을 하셨던 Hadi Hariri님이 진행하셨습니다.

Hadi Hariri의 강연 방식은 직접 코드를 보여주고 실행하면서 진행하는 것이 큰 포인트인데, 이번 강연에도 그 사항이 적용되었습니다.

이 강연에서 정리된 Kotlin 1.3 변경점은 다음과 같습니다.

  • Main의 args 파라미터를 제거해도 구동이 가능하도록 변경함
  • 코루틴 (1.3정식) -> 코루틴이 구동될 범위를 스코프로 정의할 수 있도록 추가되었습니다. CoroutineScope를 상속하는 것으로 스코프를 정의할 수 있는데, 기본으로 전역으로 구동되는 GlobalScope가 있습니다. 다만 이 GlobalScope는 사용하는 것이 그렇게 권장되지는 않는데, 이는 개발자로 하여금 코루틴이 구동될 범위를 제한할 필요가 있기 때문입니다.
  • when 내부에 변수 할당 가능 -> 코틀린의 목적인 간결하고 분명한 코드를 위해, when 안에 변수를 할당할 수 있습니다. 할당된 변수는 when 문단에서만 사용이 가능합니다.
  • 변수를 immutable 하게 유지 -> when을 statement가 아닌 expression을 사용하는 것이 권장된다고 설명하셨는데, 변수를 var로 두고 when 을 사용해서 케이스에 맞게 값을 수정하는 것이 아닌 val value = when (somethingPredicate) 방식으로 값을 할당해 모든 케이스에 대응하는 것입니다.
  • 인터페이스에 companion object를 가질 수 있도록 변경되었습니다. 자바에서 companion object 에 정의된 속성이나 함수에 접근하려면 @JvmStatic 나 @JvmField를 사용하면 됩니다.
  • Nested annotation -> @Routing, @Routing.Path 등 어노테이션 내에 어노테이션을 생성할 수 있습니다. 또한 루트 어노테이션에서 companion object를 정의할 수 있는데, 이 companion object를 Nested annotation 에서 사용할 수 있습니다.
  • Inline Class -> inline의 기본적인 기능은 복사+붙여넣기를 좀 더 아름답게 해주는 것으로, 고차함수를 사용할 때 유용합니다. (다만 인라인을 하게 되면 해당 변수에는 object가 없어 reference를 hold할 수 없습니다. 이를 위해 crossinline나 noinline를 파라미터마다 부착할 수 있습니다.) 이 inline를 Class에도 적용시킨 것이 Inline Class인데, 하나의 생성자에 하나의 속성을 가집니다. 즉, inline class Name(val name: String) 라고 선언했을 때 이 Name는 실제로는 String로서 작동합니다.
    • 다만 이 것이 typealias 와 어떻게 다르냐 하면, typealias 는 동의어 개념으로 런타임이 없습니다. 하지만 inline class는 런타임이 있어 object로 작동할 수 있습니다.
  • Unsigned Int
  • Experimental Annotation -> 해당 메서드가 실험적인 기능으로 어느 때에 바뀔 수 있다는 것을 알려주는 어노테이션입니다. 해당 메서드를 사용하기 위해서는 @UseExperimetnal 를 선언해야 합니다.
  • Contract -> text != null 와 text.isNotNull 가 의미적으로는 같음에도 불구하고 컴파일러가 text.isNotNull을 통과했음에도 불구하고 non-null 속성으로 Smart Cast하지 못하는 문제에 대해, Contract는 컴파일러에게 이 메서드를 통과하면 null이 아니라는 것을 개발자가 보증하도록 선언할 수 있는 기능입니다.
  • 멀티 플랫폼 (Kotlin/Native)
  • 리플렉션 -> 코틀린 리플렉션과 자바 리플렉션이 있는데, 코틀린 리플렉션을 사용하면 코틀린 자체의 기능을 얻어올 수 있다.
  • SAM Conversion 강화 -> 자바로 선언된 인터페이스를 사용하기 위해서는 object: Action으로 선언해야 하는데, 이제 고차함수로서 사용할 수 있게 되었습니다.
  • Intersection Type -> 유형 매개변수를 사용할 때 유형 매개변수로 들어온 타입이 어떤 타입인지 정의할 수 있습니다.
    문서: https://kotlinlang.org/docs/reference/generics.html#generic-constraints
  • JvmDefault: 코틀린으로 생성한 인터페이스를 자바에서 interop할 수 있게 변경

Kotlin/Anywhere

이번 강연에서는 2010년 Kotlin 이 시작된 날로부터 지금까지 여러 플랫폼을 대상으로 지원하는 것을 소개하였습니다. 이전 강연과 마찬가지로 강연자는 Hadi Hariri님입니다.

Kotlin이 현재 지원하는 플랫폼은 다음과 같습니다.

  • Kotlin/JVM (Server / Desktop / Mobile)
  • Kotlin/JS (Web)
  • Kotlin/Script (Build Script, Test Script, Commandline Utilities, Routing Scripts (Ktor), Type-safe Configuration files(yml 대체), REPL, Console for Data Science)
  • Kotlin/Native Beta (IOS, MacOS, Windows, Linux, WA 등)
Shot on Galaxy S8

이 중 Kotlin/Native에 좀 더 중점을 두었는데, Kotlin Native는 네이티브 바이너리로 컴파일 되면서 모바일, 데스크톱 뿐만이 아니라 시스템과 임베디드까지 지원이 가능합니다.

Shot on Galaxy S8

컴파일러로는 LLVM 5.0을 사용하는데, 코틀린 소스 코드를 코틀린 컴파일러로 통해 컴파일 하고, LLVM으로 플랫폼 코드로 변화시킵니다.

이로서 Kotlin 으로 대부분 플랫폼을 개발할 수 있어, Common Code를 가지고 각각의 플랫폼에 맞는 코드만 작성하는 등의 개발이 가능합니다.

Shot on Galaxy S8

여기에서 expect 와 actual가 등장하는데, expect는 플랫폼이 구현해야 될 것을 추상화 하는 키워드이고, 실제로 구현하는 것은 actual 키워드를 부착하여 구현합니다.

이 다음에는 실제로 Kotlin/JS나 Kotlin/Script, Kotlin/Native가 실제로 어떻게 동작하는지 예제를 통해 설명하였습니다.

Wrap up

… 왜 갑자기 두 개의 강연을 건너뛰기 했냐면, 집중이 잘 안되었습니다(..)

Shot on Galaxy S8

모든 강연이 끝나고 질문을 받으면서 행사는 마무리 되었습니다.

정리

GDG Devfest는 커뮤니티 주최였던 반면 JetBrains Day는 회사가 주최하는 것도 있어 부스 관리나 등록 데스크 등 다소 퀄리티가 높았습니다. 또한, 영어로 진행되는 강연이 반 이상이고 외국에서 온 손님도 있었기 때문에, 자리마다 무선 수신기가 있어 통역사가 실시간으로 통역하면서 진행했던 것도 다소 놀랐습니다.

Shot on Galaxy S8

또, 좋았던 것은 책상이 있었기에 노트 필기를 열심히 했다는 것입니다. GDG Devfest때도 있었지만 필기가 다소 대충이었는데, 이번에는 제대로 작성하기도 했었습니다.

Shot on Galaxy S8, 기조 연설 당시 필기

비록 평일이지만 많은 사람이 참가하여 의미 있던 시간이 아니었을까 생각해봅니다. 특히 인생에서 몇 손가락 안에 들 정도로 명사를 직접 만나 강연을 들은 것은 아마도 평생 잊혀지지 않을 것 같습니다.

ObjectBox Converter 베이스 모음집

도입

최근 진행하고 있는 개인 프로젝트인 ‘どこでもゆかりん’ 프로젝트에서 ObjectBox 를 중심으로 로직을 구성하는 기능이 있다.

ObjectBox에는 Converter란 개념이 있는데, ObjectBox가 지원하지 않는 타입을 사용할 경우에 지원하는 형태로 map할 수 있는 기능이다.

이 글에서는 해당 프로젝트에서 사용한 ObjectBox Converter의 베이스 형태를 작성해둔 것을 정리하려 한다.

Enum

import io.objectbox.converter.PropertyConverter

open class PropertyEnumConverter<T, R>(private val values: Array<T>, private val default: T,
                                       private val predicate: T.(R) -> Boolean,
                                       private val supplier: (T) -> R?) : PropertyConverter<T, R> {

    override fun convertToEntityProperty(databaseValue: R?): T? {
        if (databaseValue == null) return null
        for (state in values) {
            if (state.predicate(databaseValue)) {
                return state
            }
        }
        return default
    }

    override fun convertToDatabaseValue(entityProperty: T?): R? {
        if (entityProperty == null) return null
        return supplier(entityProperty)
    }
}
 class VoiceEngineConverter : PropertyEnumConverter<VoiceEngine, String>(
        VoiceEngine.values(),
            NONE, { this.id == it }, { it.id })

첫 번째 파라미터에는 해당 Enum의 전체값, 두 번쨰 파라미터에는 값이 없을 때의 기본값, 세번째는 Enum과 db에 있는 값을 map 할 때 사용할 조건, 마지막 네번째 필드는 map 할 값이다.

Json

보통 커스텀 클래스를 다른 엔터티의 값으로 사용하려 할 때 발생한다.

import com.google.gson.Gson
import io.objectbox.converter.PropertyConverter

open class PropertyJsonConverter<T>(private val cls: Class<T>) : PropertyConverter<T, String> {
    override fun convertToEntityProperty(databaseValue: String?): T? {
        if (databaseValue == null) return null
        return Gson().fromJson(databaseValue, cls) as T
    }

    override fun convertToDatabaseValue(entityProperty: T?): String? {
        if (entityProperty == null) return null
        return Gson().toJson(entityProperty)
    }
}
class PresetItemConverter : PropertyJsonConverter<PresetItem>(PresetItem::class.java)

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가 직접 와서 강의하니 좀 더 집중해서 들을 수 있을 것 같습니다.

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