Naver Tech Concert Day-1

06. Android Kotlin을 통한 개발 전략

  • 발표자 : 신동길 (네이버 / 네이버앱개발)
  • 동영상 : https://tv.naver.com/v/4655590/list/272653
  • 슬라이드 : https://www.slideshare.net/NaverEngineering/15android-kotlin
  • 세션설명 : 코틀린을 안드로이드에 적용하기 위해서는 안드로이드에 맞는 모듈의 개발, 거버넌스, 코딩 패턴, 디자인 패턴 등의 전략적 고려 사항이 필요합니다. 네이버앱에 코틀린을 적용한 경험을 토대로, 기존 프로젝트(또는 신규 프로젝트)에 코틀린을 적용할 때 반드시 고려해야 할 사항과 적용하면서 나온 사례를 통해서 최적화된 적용 방법을 공유합니다.

네이버 테크 콘서트 앱는 머티리얼 디자인만 사용하여 개발함.

자바를 컨버팅해 코틀린을 적용한 경우 심플하지 않고 문제도 많았음.

컨버팅시 물음표를 너무 많이 만듬.

코틀린 코드를 자바에서 사용할 경우 코틀린 코드에 붙어야할 부분도 많음.

코틀린을 배워도 자바 스타일로 짜는 경우가 많음. (코드를 너무 줄여서 가독성이 떨어진다는 평들)

코틀린으로도 긴 소스를 유지보수 명목으로 전달받았을 때 사례

  • 정적 호출이 많아 클래스명부터 쓰는 코드들이 많음.
  • 위의 문제로 alias 목적으로 함수 작성하여 사용.

아래 3코드는 동일한 기능임. (적어도 1번째는 피하도록 해보자.)

  • Java
if(LoginManager.getInstance().isLoggedIn() == false) {
    LoginManager.getInstance().loginWithDialog(this, ActivityCode.INAPP_WEBVIEW_BOOKMARK_LOGIN);
}
  • Kotlin
if(naverLoggined == true) {
    naverLogin.loginWithDialog(this, ActivityCode.INAPP_WEBVIEW_BOOKMARK_LOGIN)
}
  • Kotlin (DSL)
isNaverLoggined {
    naverLogin.loginWithDialog(this, ActivityCode.INAPP_WEBVIEW_BOOKMARK_LOGIN)
}

코틀린의 유용한 기술들

  • 람다 (Java 8, Javascript)
  • 오퍼레이터 (C++)
  • 오버로딩 (C++)
  • Method Extension (C#)
  • Property (Object Pascal)
  • DataStream Model (Direct X, java 8)

함수형

함수의 파라미터와 리턴형으로 함수를 표현한 자료형.

모든 함수는 함수형으로 형으로 표현 가능.

함수, 람다, 익명함수, 함수 참조 등을 변수로 선언 & 전달할 때 사용.

val onClickListener = object: View.OnClickListener {
    override fun onClick(view: View?): Unit { }
}
typealias onClick = (View?)->Unit

val runable = object: Runnable() {
    override fun run(): Unit { }
}
typealias aliasRun = ()->Unit

람다 식(Lamda Expression)

함수를 불필요한 부분 생략하고 기호화하여 간결화한 것.

Expression 이므로 함수와 달리 코드 중간에서 값을 리턴하지는 못함.

val buttonClick: onClick = { view -> /* Code */ }
val buttonClick2: onClick = fun(view: View?) { /* Code */ }

연산자 재정의

ExpressionTranslated to
a + ba.plus(b)
a += ba.plusAssing(b)
a()a.invoke()
a == ba?.equals(b) ?: (b == null)
a[i]a.get(i)

프로퍼티

  • 변수에 대한 처리와 변수 값을 묶어 놓은 것
  • 함수는 내부 저장을 안하지만, 프로퍼티는 내부에 저장하는 필드를 두어 중복 동작을 막을 수 있음.
  • 프로퍼티는 작성하는 사람은 복잡하지만 쓰는 사람을 위한 개념.
fun loadNaverAppIcon(): Drawable? { return icon }

val naverAppIcon: Drawable? = null
get() {
    if(field != null) return field
    // Code
    return field
}

자바 코드 변환

예전에는 모든 프로퍼티를 nullable (? 붙여서)로 해주었으나, 이젠 컴파일 에러 나도록 변환해 줌. (개발자가 생각해보고 고쳐야 함.)

멤버 변수의 초기화

  • Optional(?)

    • Null로 초기화하고 나중에 값을 지정

      private var mTitle: TextView? = null
  • lateinit (기존 코드 바꿀때는 정석으로 보임)

    • 초기 값을 지정하지 않고 생략 후 나중에 대입

    • 변수 접근시 초기화 여부를 확인하지 않음

      private lateinit var mTitle: TextView
  • by lazy (delegator)

    • 사용 시점 초기화 됨.

    • 코드 블록으로 초기화 하므로 다른 처리 가능

      private val mTitle: TextView by lazy { findViewById<TextView>(R.id.txt_name) }
  • init{} (Activity나 Fragment는 onCreate 시점에 init을 해야해서 적절하지 않음. View 정도에나 적절할 듯)

    • 초기 값을 지정하지 않고, 이 함수에서 지정 가능

    • 객체의 초기화 시에 값을 지정할 수 있음.

      init {
          mTitle = findViewById(R.id.txt_name)
      }

Nullable 처리

  • Java

    public View getView(int position, View convertView, ViewGroup parent) { }
  • Kotlin

    override fun getView(position: Int, convertView: View, parent: ViewGroup): View { }

위에서 convertView는 null이 가능해 @Nullable를 붙여줘야 컨버팅시 nullable이 가능해짐.

클래스 중첩 최적화

코틀린은 한 파일에 여러 개의 객체 선언 가능하나, 최대한 빼내는게 깔끔함.

opinion 으로 스태틱 쓰는 경우도.

해당 파일에서만 쓸 경우 private 붙임.

internal class Monet {
    fun request(): ImageRequest = ImageRequest()
    inner class ImageRequest { }
}
inner class ImageRequest { }

internal class Monet {
    fun request(): ImageRequest = ImageRequest()
}

Optional(?.) 최적화

  • ? 선언
    • 꼭 필요한 경우만 쓰고 init/late init/lazy 로 피할 수 있으면 피해라
    • !!는 확실히 검증된 경우만 사용
  • let, apply 표준확장 함수
    • 동일 변수에 2개 이상의 ?.를 사용할 때 쓰며, 과용하면 오히려 어려워짐.
  • Elvis(?:)
    • 조건문 내에 쓸 때 생각해볼 것

체인닝을 하는 건 좋지만, 길어지면 해석이 어려워짐.

네이버 앱의 브라우징 제일 큰 클래스의 경우 3800 라인 정도였으나, 코틀린 변경 후 2500 라인으로 줄어들음.

코드 효율화를 위한 툴킷 정의와 활용

  • 패키지 레벨 전역 변수 함수

    • Global Context : Application Context, Handler 등등
    • Systems Managers : ConnectionManager, ActivityManager 등등
    • System Util Functions : Screen info, dp2px 등등
    • 3가지 초기화 방식 (단순변수, 지연 초기화된 변수, Property)
  • 연산자

    • setOnClickListener 등을 plusAssign 연산자 등으로 대체 가능
    • get/setExtra 관련 함수들도 get/set 연산자 등으로 대체 가능
  • 고차함수 정의 (DSL 스타일)

    • Orientation 예제

      val isPortrait: Boolean
      	inline get() = appContext.resources.configuration.orientation == Configureation.ORIENTATION_PORTRAIT
      
      inline fun isPortrait(block:()->Unit) = if(isPortrait == true) block() else Unit
      inline fun isPortrait(blocks:Pair<()->Unit, ()->Unit>) = if(isPortrait == true) blocks.first() else blocks.second()
      
      fun testOrientation() {
          isPortrait{ showToast("Screen is portrait!") }
          
          isPortrait{ 
              showToast("Screen is portrait!") 
          } others {
              showToast("Screen is landscape!") 
          }
      }
    • API Levels 예제

      inline fun sdkRange(sdk: IntRange, block: ()->Unit): Any = if(SDK_INT in sdk) { block() } else Unit
      inline fun sdkFrom(sdk: Int, block: ()->Unit): Any = if(SDK_INT >= sdk) { block() } else Unit
      inline fun sdkTo(sdk: Int, block: ()->Unit): Any = if(SDK_INT <= sdk) { block() } else Unit
      
      const val OS_N = android.os.Build.VERSION_CODES.N
      
      sdkFrom(OS_N) { /* New OS */ }
      sdkRange(JB..KK) { /* Old OS */ }
    • Catch all Exceptions 예제

      var safeReportDebugProc: ((String?)->Unit)? = { }
      inline fun safe(block:()->Unit): Throwable? {
          val result = try {
              block()
              null
          } catch (e:Throwable) {
              e.printStackTrace()
              safeReportDebugProc?.invoke(e.message?:"")
              e
          }
          return result
      }
      
      fun testSafe() {
          safe {
              val file = File("")
              FileInputStream(file).use {
                  it.read()
              }
          }
      }

팀 개발 공동 개발을 위한 거버넌스

  • 너무 다양한 스타일이 존재
  • 개발자의 언어 이해 능력의 차이가 나므로 스타일을 어느 정도 정할 필요 있음.
  • 어떤 스타일의 금지가 아니라 어떤 패턴의 코드에는 어떤 스타일을 우선할 것을 권장하게 정의
  • 시스템 클래스에 대한 함수확장이나 전역변수의 대한 가이드 라인도 어느 정도 필요

Q&A

Q : Kotlin 기본 내장 함수인 let, apply, with, run 등은 비슷하게 사용할 수 있어 보이는데, 규칙 같은걸 정하는지?

A : 각 함수마다 개념적인 정의대로 사용하며, 될 수 있으면 중첩하지 않도록 사용 중. 네이버도 적용 중이라 완벽히 정해지지 않았음.

Q : 확장 함수 사용시 해당 클래스의 메소드인지 확장함수의 메소드인지 구분짓는 규칙이 있는지?

A : interface를 쓰면 됨. Kotlin에서는 interface에 companion이나 함수도 정의 가능하고, class에 다중 상속도 허용되는 구조.

'IT > 행사' 카테고리의 다른 글

[행사] Microsoft Azure Everywhere  (0) 2019.01.11
[행사] Naver Tech Concert Day-1 06  (0) 2019.01.07
[행사] Naver Tech Concert Day-1 04  (0) 2019.01.04
[행사] Naver Tech Concert Day-1 03  (0) 2019.01.04
[행사] Naver Tech Concert Day-1 02  (0) 2019.01.04

Naver Tech Concert Day-1

05. Material Design의 철학과 적용 사례

머티리얼 디자인의 등장

기존 구글에서는 모바일도 웹도 디자인에 그리 신경쓰는 곳은 아니었음.

2011년부터는 홀로테마로 구글 디자인이 개선됨.

사용자에게는 플랫폼과 무관하게 동일하게 기능을 요구하지만 플랫폼 별로 다른 부분은 부담이 됨.

그래서 다양한 플랫폼을 아우르는 일관된 디자인이 필요하게 됨.

현대적이고 개발자가 이해하기 쉬워야 함.

  • 아날로그 고유 속성에 중점
    • 물리적 속성
    • 형태 변환
    • 움직임
    • 높이, 음영, 객체 간 계층 구조
  • 주요 특성
    • 입체적 표면
    • 의미있는 모션
    • 인쇄물 같은

머티리얼 디자인이 2013, 2014년에 소개되고, 디자인 서포트 라이브러리가 2015년부터 지원됨.

머티리얼 디자인의 아쉬운 점

  • 부족한 엔지니어링 리소스
    • 라이브러리 한계 (네비게이션 드로우, 플로팅 액션 버튼 등)
    • 디자인과 개발 프로세스 간 연결이 자연스럽지 않음
  • 비주얼 표현의 제약
    • 앱들 간의 차이를 나타내는데 제약
    • 모바일(안드로이드)를 위한 디자인으로 간주됨

새로운 머티리얼 디자인

추가된 주요 특성

  • 유연한 기반
  • 크로스 플랫폼

머티리얼 파운데이션

머티리얼 디자인 기반으로 좋은 디자인을 제안하며 생각보다 유연함.

기존에는 높이와 그림자에서 상관관계가 까다로웠으나,

머티리얼 파운데이션에서는 계층을 표현하기 위한 높이와 그림자 쓸 뿐이며, 그림자 색대비 등을 사용자가 표현할 수 있음.

하지만 색대비나 외곽선, 그림자 등을 통해서 서피스를 구분할 수는 있어야 함.

구글에서는 머티리얼 파운데이션을 활용한 프로토 앱을 사례로 만들었음.

예로 Basil 이라는 앱에서 예로 TAB의 변경을 확인할 수 있음.

역시 네비게이션 드로우도 재해석하여 완전히 변형해서 사용할 수 있음.

머티리얼 디자인 가이드 라인

Material Theming

훨씬 많은 자유도와 독창적인 심벌을 지원하기 위해 나옴.

  • 컬러테마 : 컬러 선택시 레이어 등에 색상, 농도 등을 추천함.
  • Typography : 기존 Roboto만 지원했으나, 다른 폰트 특히 한글 폰트도 크기에 맞춰서 나옴.
  • Iconography : 5가지의 타입으로 아이콘 지원.
  • Motion : 애니메이션 등이 지원됨.

Tools

  • Theme Editor : 디자인 작업이 이루어지는 곳, 스케치에 플러그인으로 들어가 있음.
  • Gallery : 디자인 결과물을 볼 수 있는 곳

Components

기존 한국의 쇼핑 앱의 경우 머티리얼이 온전히 지원 못하였으나 이제 지원 가능함.

  • Bottom App Bar
  • Banner
  • Extended FAB (기존 FAB에 텍스트가 들어간 엄청 큰 FAB로 보면 됨)
  • Chips
  • Image Lists
  • Text Fields 2가지 제공
  • Backdrop (Front 레이어와 Back 레이어로 나뉘어 구현.)

안드로이드에서 Material Design Components 사용하기

material compnents Android 깃허브 레파지토리에서 확인 가능.

https://github.com/material-components/material-components-android

완전한 오픈 소스는 아니고 구글 내부에서 어느정도 개발 완료되면 푸시 됨.

Dependencies

dependencies {
    implementation 'com.google.android.material:material:1.0.0'
    // Other dependencies
}
...
// androidx 사용 전이라면 support 28버전 이상 사용
dependencies {
    implementation 'com.google.android.support:design:28.0.0'
    implementation 'com.google.android.support:support-v4:28.0.0'
    // Other dependencies
}

직접 Material components 빌드하여 사용하기(포함된 샘플 앱은 빌드 안됨;)

git clone https://github.com/material-components/material-components-android.git

./gradlew uploadArchives -PmavenRepoUrl="file://localhost/<path_to_aars>"

즉 커스텀이 가능함.

커스텀 뷰, 커스텀 스타일, 헬퍼 등으로 구성됨.

Material Button의 예

<!-- 일반 버튼 -->
<Button
        android:id="@+id/material_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/cat_button_label_enabled" />
<!-- 아이콘 버튼 -->
<Button
        android:id="@+id/material_icon_button"
        style="@style/Widget.MaterialComponents.Button.Icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/cat_button_label_enabled"
        app:icon="@drawable/ic_dialogs_24px" />

결론

Material Design이 빡빡한 컨셉에서 유연하고 유저 커스텀이 가능해졌음.

'IT > 행사' 카테고리의 다른 글

[행사] Naver Tech Concert Day-1 06  (0) 2019.01.07
[행사] Naver Tech Concert Day-1 05  (0) 2019.01.07
[행사] Naver Tech Concert Day-1 03  (0) 2019.01.04
[행사] Naver Tech Concert Day-1 02  (0) 2019.01.04
[행사] Naver Tech Concert Day-1 01  (0) 2019.01.04

Naver Tech Concert Day-1

04. 디자인 1도 모르는 개발자, UX디자인 시작하기

  • 발표자 : 최유리 (N Tech Service / NTS UX디자인실 설계&콘텐츠운영디자인)
  • 동영상 : https://tv.naver.com/v/4412357/list/272653
  • 슬라이드 : https://www.slideshare.net/NaverEngineering/13-1-ux-ux-121402323
  • 세션설명 : 통계에 따르면 2018년 1분기에는 앱스토어에 약 220만개, 구글플레이에 약 380만개의 앱이 등록되어 있다. 이 치열한 경쟁속에서 사용자에게 오래도록 사랑받는 앱이 되려면 UX디자인은 선택이 아닌 필수다. UX디자인은 디자이너만의 영역이 아닌 개발팀 모두가 함께 만들어내야하는 가치이다. UX디자인에 관심을 갖고 참여한 개발자가 서비스 성공에 어떤 역할을 해 내는지 알아보자.

잘 나가는 앱을 만들고 싶다면? UX 디자인에 참여 필요.

사용자에게 중요한 건? 내 삶에 어떤 가치를 주는 가.

사용자에겐 서비스에 들어간 기술과 시간과 노력엔 관심이 없음.

UX 디자인은 일종의 프레임워크라 할 수 있음.

Focused on product

Focused on user

디자인적 사고는 문제를 발견해 해결 방법을 제시하는 것.

모두는 디자이너라 할 수 있음.

Lean UX Cycle

PLAN -> think -> make -> check -> think -> make

Lean UX 경험내용 1

UX 디자인 분석 단계를 개발팀과 함께 진행.

Key Feature 워크샵.

결과 : 기능의 목적과 목표를 이해하고 구현 가능한 스펙을 정의하여 품질 완성도가 올라감.

Lean UX 경험내용 2

UX 디자인 워크샵.

서비스 목표와 전략 수립. 핵심 기능 도출.

결과 : 사용자 가치 중심으로 스펙 변경, 플랫폼 전체를 바라보는 시각 형성.

UX Design을 개발자와 함께 함으로 목표와 가치 도출하고 사용성 테스트를 통해 문제점 발견이 용이함.

그 결과로는 기술 중심에서 사용자 중심으로 사용자에게 의미 있을만한 것을 제공하기 위해 집중함.

UX 디자인 함께 하면 좋은 점

  • 공동의 목표 세워, 자발적이고 주체적인 의사결정 가능
  • 시간과 비용 중심이 아닌 사용자 가치 중심의 스펙 정의가 가능
  • 밀접한 협업 가능
  • 신속한 결과 도출 및 검증 가능
  • 낭비를 줄이고, 위험요소 미리 감지 가능
  • 서비스 질이 좋아짐

UI와 UX 디자인

User Interface

  • Technical
  • 어떻게 작동하는가? 어떻게 보이는가?
  • 사용편의성, 일관성, 심미성

User eXperience

  • Emotional
  • 어떻게 느끼는가?
  • 사용자 가치, 사용자 환경(Context), 만족도, 재접근

Experience

  • 오가닉 경험(Organic Experience) : 즉흥의, 즉석의 등 의도가 없는 순수한 경험
  • 설계된 경험(Designed Experience) : 사용자가 고려되고 계획던 경험. 사용자가 경험했으면 하는 감정을 정의.

사용성보다 사용자 가치가 더 우선적

효율적인 UX 디자인 프로세스 = Lean UX + Agile UX

애자일 UX 방식은 초기 비용이 높으나 후반으로 갈 수로 낮고 상대적으로 워터폴은 비용 뿐만이 아니라 리스크도 높아짐.

Lean UX Cycle은 경험과 측정을 근거로 현상의 원리를 밝히는 과정

가설을 세우고, 분석하고, 설계하고, 그것을 테스트한 후 실행에 옮김.

PLAN : 공동의 비전과 목표

  1. 프로젝트의 목표는?
  2. 내가 이 프로젝트를 통해 얻고자 하는 것은?
  3. 우리의 주요 고객은 누구인가?
  4. 프로젝트 진행에 걸림돌이 되는 것은? 위험요소는?
  5. 서비스의 성공적인 완성은 무엇으로 판단할 것인가?

THINK : 사용자를 이해하고 니즈를 구체화

Pain vs Gain

MAKE : 사용자 경험 전략과 가치를 정의

Elevator Pitch

  • 제품 고유의 특징
  • 사용자 가치
  • 핵심 기능

Kano Analysis

CHECK : 핵심 기능의 실현 가능성을 평가

NUF(New/Useful/Feasible) Test

Usability Test

'IT > 행사' 카테고리의 다른 글

[행사] Naver Tech Concert Day-1 05  (0) 2019.01.07
[행사] Naver Tech Concert Day-1 04  (0) 2019.01.04
[행사] Naver Tech Concert Day-1 02  (0) 2019.01.04
[행사] Naver Tech Concert Day-1 01  (0) 2019.01.04
[행사] 앱쇼코리아 2018 참석기  (0) 2018.12.21

Naver Tech Concert Day-1

03. MVVM with Grab Architecture

  • 발표자 : 정승욱 (Grab / 안드로이드 개발)
  • 동영상 : https://tv.naver.com/v/4637223
  • 슬라이드 : https://www.slideshare.net/NaverEngineering/12mvvm-grab-architecture-mvvm
  • 세션설명 : 구글이 Android Architecture Component 의 ViewModel 을 발표하면서 다양한 시각의 MVVM 구현이 제시되고 있습니다. 여전히 많은 사람들이 혼동하는 MVVM 구현에 대해 올바른 안드로이드 MVVM 구현을 공유하고자 합니다. 이를 위해 안드로이드에서 어떠한 기본 작업이 선행되어야 하는지, 다양한 문제 상황에 대한 해결책에 대해 알아보고 MVVM 이 Grab 에서 어떻게 활용되고 있는지 알아보겠습니다.

국내 MVVM 이해도 오류가 많음. (국내 포스팅 등...)

예로 아래의 경우 뷰에서 옵저빙을 하는 부분이 문제임.

class MainViewModel {
    val title LiveData<String>
}
...
class MainActivity {
    val viewModel: ViewModel
    val textView: TextView
    fun onCreated() {
        viewModel.title.observe(this) {
            textView.text =it
        }
    }
}

Android Architecture Component의 ViewModel

AAC의 ViewModel은 MVVM의 ViewModel과는 무관함.

AAC의 ViewModel은 Activity와 Fragment의 Life Cycle 의존성을 낮추는 것.

LiveData는 Repository로부터 데이터 변화 반응/적용이 목적이며 ViewModel은 LiveData로부터 View에 필요한 데이터를 관리함.

MVVM의 ViewModel

View와 ViewModel 연결 최소화

ViewModel은 데이터의 변화를 View에 전달

View는 화면 정보의 변화를 ViewModel에 전달

위에서 잘못된 코드는 아래와 같이 변경되어야 함.

class MainActivity {
    val viewModel: ViewModel    
    fun onCreated() {
        dataBinding.setVariable(BR.vm, viewModel)
    }
}

안드로이드에서 DataBinding 사용에 문제 사항들

  1. LifeCycle
  2. Databinding으로 다 표현하기 힘든 View 이벤트
  3. Resource 등 Context를 접근해야 하는 경우

LifeCycle

그랩에서는 LifeCycle 문제를 위해 RxBinder를 만들어 사용함. (Trello의 RxBinder 참조)

class ViewModel(val rxbinder: RxBinder) {
    init {
        rxbinder.bind(ON_DESTROYED) {
            Observable....
        }
    }
}
...
class RxBinder {
    val map: Map<Event, CompositDiposable>
    fun apply(lifeEvent: Event) {
        map[lifeEvent]?.clear()
    }
    fun bind(lifeEvent: Event, body:()->Disposable) {
        map[lifeEvent].add(body())
    }
}
...
open class RxActivity{
    val rxbinder: RxBinder
    fun onCreated() {
        rxbinder.apply(ON_CREATED)
    }
}

View 변화 감지

GlobalLayoutChangeListener 등은 데이터 바인딩으로 구현이 어려움.

위의 경우 2-way 바인딩 구현해야 하며 3개의 function을 구현해야 하며 이해가 어려움.

이를 위해 2-way 바인딩 구현보다는 usecase를 만들어 회피 사용함.

class GetVisibleAreaUsecase(view1) {
    fun observe(): Observable<Rect> {
        return Observable.create {e->
                                  e.onNext(view1.height)
                                  view1.addGlobalLayoutChange{
                                      e.onNext(view1.height)
                                  }
		}.distictUntilChanged()
    }
}
...
class ViewModel(usecase:GetVisibleAreaUsecase) {
    init{
        usecase.observe().subscribe{
            /* do something */
        }.bindUntil(rxbinder)
    }
}

Resource 접근

ResouceProvider 라는 랩핑을 만들어 context를 전달해 사용

class ResourceProvider(context: Context) {
    fun string(resId: String) = context.resource.getSting(resId)
}

ActivityResult는 매니저를 만들어 Activity에서 메소드 실행시 ViewModel에서 구독됨.

class Activity {
    val resultManager
    fun onActivityResult() {
        resultManager.onResult()
    }
}
...
class ResultManager{
    fun listen(observer)
    fun onResult()
}
...
class ViewModel(resultManager) {
    init{
        resultManager.listen {
            // do something
        }
    }
}

위의 모든 것이 구현된다면 대략...

class ViewModel(rxbinder, usercase, resultManager) {
    init{
        // many things are here
    }
}
...
class Activity: ResultableRxActivity {
    fun onCreated() {
        dataBinding.setVariable(BR.vm, viewModel)
    }
}

실제 액티비티의 역할은 아래 정도?

액티비티에서 DataBinding과 DI만?

class MainActivity: RxResultableActivity{
    @Inject lateinit var vm: MainViewModel
    fun onCreated() {
        dataBinding.setVariable(BR.vm, vm)
    }
}

그랩에서는 단일 Layout을 조각내기로 함.

한 레이아웃을 뷰를 나눠 각각을 노드화하여 처리.

각 뷰 별로 바인딩 노드가 되고, 각 노드에 ViewModel이 인젝션됨.

바인딩 노드는 부모뷰와 ViewModel을 받음.

1. Activity

class ConfirmActivity{
    fun onCreated() {
        BackButtonNode({parentView}).dependency(root).build()
        TaxiTypeNode({parentView}).dependency(root).build()
        ExtraInfoNode({parentView}).dependency(root).build()
        PayConfirmNode({parentView}).dependency(root).build()
        //...etc...
    }
}

2. 5번 TaxiTypeNode

class TaxiTypeNode(parentView:()->ViewGroup): BindingNode{
    @Inject lateinit var vm: ViewModel
    fun build() {
        depdency.inject(this)
        binding(parenteView(), vm)
    }
}

3. BindingNode

open class BindingNode {
    fun binding(parentView: ViewGroup, vm: ViewModel) {
        val binding = ViewBinding.inflate(vm.layoutId, parentView)
        binding.setVariable(BR.vm, vm)
    }
}

4. Root Parent XML

<FrameLayout>
    <FrameLayout android:id="@+id/parent1" />
	<FrameLayout android:id="@+id/parent2" />
</FrameLayout>

노드화의 장단점

  • 장점 : Node 제어로 View 플러그인화 가능
  • 단점 : BackKey, Save/Restore Instance 등 다양한 처리 구현

위 구조는 작은 사이즈에서 중간 규모의 앱에서는 과도하며, 인터랙션이 많거나 View 자유도, 재활용이 높은 앱에 권장함.

정리

View는 XML

DataBinding 필수요소

감지하기 어려운 뷰 변화는 ViewUsecase

LifeCycle, Result 위한 처리 필요

Resource 접근은 Wrapper 처리

Node 예제는 Optional

Q&A

Q : 그랩에서는 AAC 사용 안하는지?

데이터 용도로 맞지 않고 라이프사이클 처리도 직접 함으로 Room, LiveData, AAC의 ViewModel 등은 사용 안함.

Q : 노드 사용 사례는?

루트 노드에서 라우터가 하위 노드를 컨트롤하며, 하위 노드를 구성하도록 지시함.

Q : 이재원님(MS Expert)의 안드로이드의 MVVM 오류에 대한 내용이 반영되었는지?

반영된 내용임.

Q : RxBinding이 그랩에서 자체적으로 만든건지?

외부(Trello)에서 아이디어만 가져오고 자체 구현함.

Q : Activity에서 ViewModel을 직접 참조할 일이 없다는데? Activity에서 반응에 대한 부분을 ViewModel에 전할때는?

데이터 바인딩으로 처리됨.

Q : 노드의 상대적인 위치는 어떻게 지정?

루트노드에서 Parent 대비 상대적인 위치가 지정되어 있음.

Q : 전통적인 Activity와의 차이는?

레이아웃 부분이 static으로 지정되어 있지만, 노드에서는 노드 단위로 다른 화면에서도 재활용이 가능함.

Q : 빈 레이아웃에 attach/dettach 하는 방식이 Fragment와 비슷한데?

그랩에서는 Fragment를 사용안함. onRestore 시 등 재생성 충돌등의 문제가 있어 별도로 노드 처리함.

Q : 기본 선수 지식은?

DataBinding(2-way까지), MVP에 대한 깊은 경험, MVP에서 MVVM으로 변화에 대한 이해 필요.

Q : ViweModel에서 Resource ID를 가지는 이유는?

ViewModel에서 어떤 리소스와 매칭되는지 판단을 했지만, 편의상 Node보다 ViewModel에서 가지고 있음.

Q : 2-way 바인딩 사용 사례는?

2-way 바인딩이 한번 이상 재사용시에는 2-way 바인딩을 빼서 사용을 권고함.

Q : DataBinding이 MVVM에 필수인데 Anko의 경우는?

Anko같은 경우는 네이티브 코드이고 Anko로 작성한다 해도 중간에 추상화 코드가 나오는 게 아니라 현재 구현된 상태가 최선인 듯. 현재로썬 Anko와는 궁합이 좋지 않음.

Q : AlertDialog는 어떻게 처리?

AlertDialog도 노드로 처리

Q : 싱글 액티비티에서 히스토리 관리는?

상위 노드에서 관리하며, 히스토리 관리하는 모듈이 있음.

Q : 그랩은 모두 싱글액티비티임?

메인 플로우들은 싱글 액티비티이나 페이먼트, 리워드 등은 아님. 그래서 onResult 처리가 필요했음.

Q : Trello RxLifeCycle에서 추가된 기능은?

자체적으로 필요한 부분만 추가되고 Trello에서는 필요한 것만 빼서 씀

Q : MS 제안한 MVVM 의도대로 분업이 되었는지? (XML은 디자이너, ViewModel은 엔지니어)

그랩에선 디자이너는 UX/비주얼(7:3정도) 디자이너로 나뉘며, xml이나 ViewModel 모두 엔지니어가 작업

Q : Save Instance 상태는 어떻게 관리하는지?

노드별로 저장해서 상위 노드에 전달하고 복원 시작시 하위 노드에 다시 전달함. 복잡한 부분이라 라이브러리화해서 사용 중.


Naver Tech Concert Day-1

개요

  • 행사명 : Naver Tech Concert

  • URL : http://techcon.naver.com/

  • 일정 : DAY 1- 2018년 11월 1일(목) 10:00 - 17:30

    DAY 2- 2018년 11월 2일(금) 10:00 - 17:30

  • 장소 : 정자동 네이버 그린팩토리 본사 2층 CONNECT HALL

  • 일정 :

    • 11월 1일(목) D AY 1
      09:30 ~ 09:55   참가 등록
      10:00 ~ 10:10   인사말
      10:10 ~ 11:10   Android DataBinding (기초에서 고급까지) 
      11:10 ~ 12:10   MVVM with Grab architecture 
      12:10 ~ 13:30   점심시간 (별도 제공은 없습니다.) 
      13:30 ~ 14:30   디자인 1도 모르는 개발자, UX디자인 시작하기
      14:30 ~ 15:30   Material Design의 철학과 적용 사례
      15:30 ~ 16:30   Android Kotlin을 통한 개발 전략 
      16:30 ~ 17:30   Obfuscation 101: 난독화, 프로가드, R8, 트랜스포머 API
      17:30   마무리
  • 11월 2일(금) DAY 2
       09:30 ~ 09:55  참가 등록
       10:00 ~ 11:00  변화의 시대: 안드로이드 앱 어떻게 개발할 것인가?
       11:00 ~ 12:00  Efficient and Testable MVVM pattern(with using AAC, Rx, Koin)
       12:00 ~ 13:30  점심시간 (별도 제공은 없습니다.)
       13:30 ~ 14:30  내가 사랑한 개발자들
       14:30 ~ 15:30  안드로이드 웹뷰의 모든것 
       15:30 ~ 16:30  안드로이드에서 코루틴은 어떻게 적용할 수 있을까?
       16:30 ~ 17:30  자동화, 계륵에 살 붙이기
       17:30  마무리 

현장


전리품

01. 인사말

900명이 넘는 사람이 신청했으나, 어쩔 수 없이 추천으로 초청하게 됨.

네이버 내부 사내 개발자 역량 강화를 위해 다양한 행사를 진행함.

외부 개발자 초빙하여 부정기적으로 다양한 주제의 테크톡을 진행함.

내부적으로는 주제별로 사내 밋업을 진행하며 가장 활발한 그룹이 자바스크립트 프런트엔드 개발, 안드로이드, iOS 그룹이 활발함.

사내 내외부 교류와 네트워킹을 위해 준비하며, 프런트엔드 그룹은 이미 진행하고 있으며, 이번에 안드로이드 그룹도 진행하게 됨.

안드로이드 단말 나온지 10년이 되는데 여러 노하우를 공유했으면 함.


02. Android DataBinding (기초에서 고급까지)

PRISM Live Studio 앱에서 데이터바인딩을 전면적으로 사용 중.

DataBinding이란?

XML(Screen) <- Java/Kotlin(Data/Logic) 인 부분을***Binding.java가 연결함.

이 부분은 런타임시가 아닌 XML 빌드시 생성됨.

XML에 기존대비 <Layout> 태그 추가 필요.

activity_main.xml -> ActivityMain.xml -> ActivityMainBinding.java

기존 레이아웃을 setContentView 사용하던 방식이 아니라 DataBindingUtil을 이용해 레이아웃을 통해 DataBinding 클래스(예. ActivityMainDataBinding)를 사용.

Activity, Fragment, View(ViewHolder) 등에서 사용 가능

XML을 통해 DataBinding 생성시 그 안의 View들에 대한 참조가 가능함.

Actvitiy 등에서 그 View들을 참조하여 사용이 가능하나 참조를 제거하는 방향으로 하고자 함.

XML에서 DataBinding 사용시 data 변수 추가 필요.

Gradle 3.2.0 미만에는 DataBinding 클래스 내에 구현이 있으나, 이 후부터는 DataBinding 클래스가 abstract 클래스이고 DataBindingImple 클래스에 구현이 들어감.

<layout>
    <data>
        <variable
                  name="model"
                  type="com.test.blabla.SampleModel" />
    </data>
    <LinearLayout
                  ... >
        <TextView
                  ...
                  android:text="@{model.title}" />
    </LinearLayout>
</layout>

데이터바인딩 이루어지는 규칙 (실행 우선 순위 순)

  • BindingAdapter (사용자 지정 Setter)
  • BindingMethod (이름이 바뀐 Setter)
  • Set Method (자동 Setter)

Setter 예제

<TextView
          android:id="@+id/title"
          ...
          android:enabled="@{true}" />

위와 같은 xml 빌드시 ***Binding.java가 아래처럼 생성됨.

this.title.setEnabled(true)

커스텀뷰의 추가된 메소드 등을 위와 같이 사용 가능.

BindingAdapter 예제

바인딩 어댑터를 사용시 애노테이션 사용하면 public static 필수임.

@BindingAdapter(value={"naver"})
public static void naverBindingAdapter(TextView, boolean isNaver) {
    ...
}

위 바인딩 어댑터를 사용하는 xml

<TextView
          android:id="@+id/title"
          ...
          app:naver="@{true}" />

위 xml 빌드시 생기는 ***Binding.java

SampleBindingAdapter.naverBindingAdater(this.title, true);

BindingAdapter 애노테이션 선언부

@Target(ElementType.METHOD)
public @interface BindingAdapter {
    String[] value();
    boolean requireAll() default true;
}
  • value : XML Attribute Name List, 다수 개일 경우 메소드 파라미터 순서와 매칭이 되어야 함.
  • requireAll : value()의 Attribute가 모두 존재할 때만 처리할지 여부. false일 경우 int/double/float/... 등의 타입의 Attribute가 없을 경우는 값은 0, Object 타입의 Attribute가 없을 경우는 null로 처리됨.

발표자께서는 requireAll=false 을 사용하였었으나, 다수 개의 Attribute에서 어떤 값만 옵셔널하게 처리가 안되어 아래와 같이 오버로딩하면서 쓰고 있음.

@BindingAdapter(value={"android:visibility", "animType", "animDuration"})
public static void newAnimationBindingMethod(View view, boolean visibility, @AnimType int animType, int animDuration) { ... }

@BindingAdapter(value={"android:visibility", "animType"})
public static void newAnimationBindingMethod(View view, boolean visibility, @AnimType int animType) { ... }

Observable

XML(Screen) <- ***Binding.java <- Java/Kotlin(Data/Logic)

Java/Kotlin 등에서 변경시 XML에 알려주길 위해 Observable 사용.

(DataBinding이 아니라면 LiveData해도 됨.)

Observable 인터페이스 있으나, 구글에서 사용하기 편하게 BaseObservable 제공함.

public static class SampleModel extends BaseObservalbe {
    private String title;
    public SampleMode(String title) {
        this.title = title;
    }
    public void setTitle(String title) {
        this.title = title;
        notifyPropertyChanged(BR.title);
    }
    @Bindable
    public String getTitlt() {
        return title;
    }
}

위에서 BR은 빌드시 생성이 됨.

위 SampleModel 객체 생성 후 setTitle 메소드 사용시 notifyPropertyChanged()를 통해 ***Binding.java에 변경이 전달 됨.

***Binding.java에서는 getTitle()을 통해 바뀐 값을 전달받음.

그래도 불편하므로 구글에서는 아래와 같은 것들을 제공함

  • ObservableBoolean
  • ObservableByte
  • ObservableChar
  • ...
  • ObservableArrayList
  • ObservableArrayMap
  • ObservableParcelabe
  • ObservableField
    • ObservableField<String>
    • ObservableField<CustomMode>

SampleModel을 바꿔보자.

public static class SampleModel extends BaseObservalbe {
    public final ObservableFiedl<String> title;
    public SampleMode(String title) {
        this.title = new ObservableField<>(title);
    }
}

Listener의 Binding

  • Object 전달

    <Button
            ...
            android:onClick="@{model.clickListener}" />

    위와 같이 사용시 BindingMethod 사용이 필요함

    @BindingMethod(type=View.class, attribute="android:onClick", method="setOnClickListener")
  • Method 직접 연결

    <Button
            ...
            android:onClick="@{model:clickListener}" />
    <Button
            ...
            android:onClick="@{(view)->model.clickListener(view)}" />

    위와 같이 사용시 아래와 같이 사용함.

    public class MainActivity extend AppCompatActivity {
        public void onClicButton(View button) {
            //선언부의 view button은 람다에서 제거 가능
        }
    }

CustomView + Custom Listener

public class CustomTextView extends AppCompatTextView {
    public interface OnCustomEventListener {
        void onEvent();
    }
}
@BindingAdapter("onCustomEvent")
public void setOnCustomEventListener(CustomTextView view, CustomTextView.OnCustomEventListener listener) {
    view.setOnCustomEventListener(listener);
}

//또는 

@BindingMethod({
    @BindingMethod(type=CustomTextView.class, attribute="onCustomEvent", method="setOnCustomEventListener")
})
<com.blabla.CustomTextView
                           ...
                           app:onCustomEvent="@{()->activity.onCustomEvent()}"

리스너 바인딩 사용시 주의점

대부분 리스너들은 return이 void 형식이나 onLongClick 일경우 return이 boolean형식이라 잘못 쓸 경우 이상한 오류 발생함. 아직 데이터 바인딩에 대한 오류 지원은 미흡함으로 주의해야 함.

Two-way Binding

  • Binding : UI <- Model
  • InverseBinding : UI -> Model
  • Two-way Binding : 둘다
public class MainActivity {
    public void onClickDone() {
        binding.getModel().text.set("이렇게 초기화가 됩니다.");
    }
}
public class TwowayBindingModel {
    public final ObservableField<String> text = new ObservalbeField<>("");
}
<layout>
    <data>
        <variable
                  name="activity"
                  type="com.test.blabla.MainActivity" />
        <variable
                  name="model"
                  type="com.test.blabla.TwowayBindingModel" />
    </data>
    <LinearLayout
                  ... >
        <Button android:onClick="@{()->activity.onClickDone()}" />
        <EditText
                  android:text="@={model.text}" />
        <TextView
                  android:text="@{model.text}" />
    </LinearLayout>
</layout>

양방향 바인딩 : @={model.title}

단방향 바인딩 : @{model.title}

EditText는 양방향 바인딩이라 텍스트 수정시 InverseBinding이 이루어지며, 이 후 변경된 값으로 Binding이 이루어짐.

  • Binding

    @BindingAdapter("android:text")
    public static void setText(TextView textView, String text) {
        tetView.setText(text)
    }
  • InverseBinding

    @InverseBindingAdapter(attribute={"android:text"})
    public static String getText(TextView textView) {
        return tetView.getText().toString();
    }

InverseBinding 선언부

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface InverseBindingAdapter {
    String attribute();
    String event() default "";
}

InverseBinding에서 event 사용시

@InverseBindingAdapter(attribute={"android:text", event="textEvent"})
public static String getText(TextView textView) {
    return tetView.getText().toString();
}

@BindingAdapter("textEvent")
public static void setTextEvent(TextView textView, final InverseBindingListener listener) {
    textView.addTextChangedListener(new TextWatcher() {
        @Overrride
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            listener.onChange();
        }
    });
}

위 구현의 동작 흐름

  1. EditText에 텍스트 변경
  2. @BindingAdapter("textEvent")에서 텍스트 변경으로 InverseBindingListener의 onChange() 호출
  3. @InverseBindingAdapter(attribute={"android:text", event="textEvent"}) 에서 변경된 텍스트 반환
  4. TwowayBindingModel의 ObservableField인 text에서 값이 변경됨을 알림.
  5. @BindingAdapter("android:text") 으로 EditText와 TextView에 변경된 값을 설정함.

하지만 위와 같이 처리시 5번에서 다시 1번이 발생하게 되어 계속 반복하게 됨.

구글에서 이에 대한 직접 로직을 추가하여 막아야 한다고 함. (TextViewBindingAdpater 참조)

TextViewBindingAdpater 에서는 이전과 변경되는 텍스트 값을 비교하여 예외처리를 추가함.

<include>와 <ViewStub>

네이버 프리즘라이브의 경우 Activity가 pause 되면 안되는 상태로 설계가 되었고, 하나의 Activity에 많은 View를 추가하는 형태임.

  • 수많은 View들
  • 개발자들 사이의 분할(분담)
  • 기능들의 확장성
  • 변경의 용이성

(architecture나 패턴에 대한 부분은 제외하고 DataBinding과 View 관점에서만 논하기로 함)

main.xml -> include1.xml

​ -> viewstub1.xml

​ -> viewstub2.xml

메인에서 하위로 데이터를 전달해야 하므로 데이터도 동일하게 뎁스를 만들어서 사용함.

MainBindingModel -> IncludeBindingModel

xml에서 하위로 모델 넘길 경우

<!-- main.xml -->
<layout>
    <data>
        <variable
                  name="model"
                  type="MainBindingModel" />
    </data>
    <include
             layout="..."
             app:mode2="@{model.includeModel}" />
</layout>
<!-- main.xml -->
<layout>
    <data>
        <variable
                  name="model2"
                  type="IncludeBindingModel" />
    </data>
    <TextView
             app:mode2="@{model2.title}" />
</layout>

프리즘은 각 View별로 ViewModel 1:1 매핑하여 개발함.

ViewStub 바인딩시 include보다 까다로움.

ViewStub도 View 상속하다보니 일반적인 BindingAdapter를 사용가능하나,

ViewStub 특성을 살리는 부분은 ViewStub를 파라미터로 받는 BindingAdpater로 구현해야 함.

하지만 이는 Gradle 3.1.0이상부터 되는 것으로 보여 그 이하의 환경에서는 편법을 써야 함.

ViewStub를 DataBinding시에 ***Binding.java에는 ViewStubProxy가 사용됨.

그 ViewStubProxy 안에 ViewStub이 있음.

ViewStub을 사용시에는 반드시 android:id 가 있어야 함. (없을 경우 에러로그가 딱히 안나옴)

최초에는 inflate 필요함. ViewStub의 경우 ViewStubProxy에서 inflat시에 다시 바인딩(rebinding)을 하게 함.

위의 이유로 애니메이션 동작 등이 오동작할 수 있음.

다시 바인딩되는 범위는 ViewStub을 싸고 있는 부모뷰까지이므로 편법으로 ViewStub을 include로 싸면 되긴 함.

(대신 아름답지는 않음)

Q&A

Q. 협업을 위해 바인딩 어답터 오버로딩한다고 하셨는데, 바인딩어답터에서 바인딩어답터를 호출할 수 있습니까?

넵! 이미 BindingAdapter로 넘어오면 그 시점부터는 Java Method라고 보셔도 무방합니다. 즉… 필요한 BindingAdapter의 Method를 호출해주면 됩니다..!

Q. 바인딩 문법 틀렸을때 자바처럼 잘 디버깅해주지않던데 쉽게 문법오류 잡는 팁 있을까요?

안타깝게도… 이건 좋은 방법이 있진 않아요. 좋은 방법이라면… 수없이 많이 맞아보는 것…?ㅎㅎ…

Q. 동적으로 ui위치를 변경하고자할때 데이터바인딩을 사용하고 싶은데 뷰의 속성변경 말고 뷰 객체 자체를 받을 수 있나요?

결론적으로… 저라면 동적으로 UI위치를 변경하고자 한다면 예를들면 이렇게 작성할 것 같아요..

@BindingAdapter](https://github.com/BindingAdapter)( {"positionX", "positionY"} ) public static void moveView(View view, float positionX, positionY) { view.setTranslationX(positionX); view.setTranslationY(positionY); }

Q. recyclerView의 스크롤 이벤트 같은것도 데이터 바인딩으로 받을 수 있을까요? (스크롤 위치에 따라서 이벤트 처리를 하고 싶은 경우에)

해보지는 않았는데요. Listener를 Setting해서 값을 가져오는 방식이라면 가능합니다. InverseBindingAdapter를 이용하면 될것 같은데요.

참고로 저의 경우에는 ViewPager의 Page 이동과 offset 이동도 InverseBinding으로 처리하고 있습니다.

Q. 데이터바인딩을 사용하게 되면서 코드 가독성이 떨어진 점은 없었나요? Textview.setText면 충분하지 않았나 싶은 생각도 들고 그러는데 데이터바인딩의 장점이 궁금합니다.

이건 취향차이기인 해요. 저는 오히려 코드 가독성이 올라가는 부분도 있다라고 생각합니다. View에 대한 로직은 모두 xml에서 볼 수 있다라고 생각할 수 있으니까요. 로직이 복잡해지면 xml도, 코드에서도 복잡하긴 한건 매한가지 이긴 하니까…?

사실. 이 DataBinding은 코드의 가독성을 높인다. 개발 생산성을 높인다.의 이야기와는 맞진 않다고 생각합니다. 정확하게는 Java/코틀린 코드에서 View에 대한 참조를 제거하는 도구이다. 라고 보시는 쪽이 맞긴 해요. 또한… 이런저런 장점들이 있기는 한데… 가장 크게 예를 들면 Image Loading 같은 경우에요. 그냥 코드로 작성하게 되는경우 Image를 Load하는 모든 지점에서 자바/코틀린으로 Loading 로직을 작성해주셔야 하는데 Binding을 이용한다면 이런식으로 작성하면 끝! 할수도 있거든요

막상 열심히 써보면 편해요. 굉장히 편합니다. View를 사용할 때 thread 걱정도 사라지고요. 얘가 NullPointer도 잡아주고요… 내 손으로 작성하는 코드의 양을 줄여서 실수를 줄여주는 부분도 있습니다. 이제 저는… Binding 없이는 코딩이 좀 어렵다. 생각이 들 정도로 적어도 제게는 정말 편리한 도구입니다




점심에 명인등심에 가서 곰탕을 먹어보았습니다.
일행 중에 육회비빔밥 드신 분들도 계시고요.
곰탕은 무난한 맛이었습니다.
추운 시기에 한 그릇하면 든든하겠죠 ㅋ
삼성동에서 곰탕 생각나신다면 추천합니다~


강남역 주변 프라이드프라이드를 다녀왔습니다.
프라이드포크라는 낯설은 표현을 쓰는 이 곳에서 돼지고기를 튀겨먹는 경험을 했네요.
여러가지 부위를 튀겨서 나오고 맛있습니다.
사실 튀겨서 왠만해선 맛없기도 힘들다곤 하지요.
가성비는 그리 좋은 편은 아니네요.
그래도 좋은 사람들과 자리하기엔 색다르고 재미있는 곳 같습니다.

앱쇼 코리아 2018

행사 정보

  • URL : http://app-show.co.kr/
  • 행사명 : 제5회 앱쇼코리아 / The 5th AppShow Korea
  • 주제 : 콘텐츠, Ai · IoT · VR/AR · 빅데이터 · 블록체인과 연결되다
  • 기간 : 2018년 12월 20일(목) ~ 12월 22일(토), 3일간
  • 장소 : Coex Hall B1 (지하 1층 아님)

참가 업체

부스번호업체전시품목홈페이지
A01그린휠㈜전기자전거, 접이식전기자전거, 미니벨로전기자전거, 전기자전거 키트www.greenwheel.kr
A02헤드블락블록체인 활용한 채용 no-show 해결www.headblock.io
A03알파콘 네트워크 파운데이션유전자검사키트, 맞춤영양제 등www.alphacon.io/
A04에스크락투자자 리스크를 최소화한 ICO 참여 금융 모델www.esc-lock.com
A05한국M&A센터선순환 투자구조 마련을 위한 M&A/투자유치 전문 플랫폼 회사www.mnacenter.com
A06(주)히즈윌컴즈블록체인 마케팅 홍보www.coinistar.com
A07주식회사 엘라마체인앱/웹 기반 암호화폐 결제 플랫폼(ELA PAY)www.elamachain.io
A08주식회사 브리지REMOFIT
A09㈜크립토레드인터내셔널Coin Monster, Nix paywww.nixblock.com
A10㈜제미타스마트 펀칭 게임기www.zemita.com
A11주식회사 락인컴퍼니LIAPP(Mobile App Protector)www.lockincomp.com
A12주식회사 블루디지털사이니지, 광고 메뉴보드, 키오스크, 안드로이드 동영상 재생기www.signmall.kr
A13주식회사 이브이스마트 헬스 자판기
A14(주)아이씨쥐LED 전광판 전시차량, LED 전시작품www.trinled.com
B01성균관대학교 산학협력단영상정보를 이용한 건강 측정(스트레스, 혈량, 우울증, 호흡, 혈액점도, 맥박, 체온)www.skku.edu
B02크레아트봇㈜허밍버드 로봇 키트(허밍버드 듀오, 허밍버드 비트, 핀치로봇)http://www.creartbot.com/
B03(주)엉클샘산타클로스365http://santa365.unclessam.com/
B04엑스오자가충전 IoT 위치추적기www.xoco.kr
B05케이디자인미디어AR스티커https://kdm.pe.kr
B06(주)휴네이처IoT App, IoT 무선모듈www.hunature.net
B07주식회사 솔투온교육용 클라우드 시스템 - 스터디 버튼www.soul2on.com
B08스토리앤브라더스㈜성향분석 기반 AI 매칭 팀빌딩 플랫폼, "사피언스"https://sapiensteam.com
B09토비테크놀로지코리아 주식회사시선추적(Eye tracking) 솔루션www.tobiipro.com/ko/
B10주식회사 뮬리즈뮬리즈(Muilyzz)https://www.muilyzz.com
B11스마트드림3초만에 숨어있는 핸드폰 찾기! 스마트버튼 'PopPop'www.poppopbutton.com
B12(사)한국스마트융합산업협회콘텐츠 디자인 기반 융합형 실무인력 양성 아카데미 교육생 포트폴리오 / 회원사 보유 제품 및 서비스http://kscia.kr
B13(주)트랜스박스TransBox App, API 등www.transbox.xyz
B14디사인Display + VMV contens creation Solution
B15미래야 놀자엑스 토네이도, 엑스 팡팡www.barovr.com
B16(주)쓰리디뱅크3D 리얼플러스, IoT 3D 홀로그램www.3dbank.xyz
B17주식회사 글로핸즈전자계약 시스템https://www.glosign.co.kr/index
B18페이게이트세이퍼트 블록체인 멀티시그 월렛http://www.paygate.net
B19주식회사 태명월팜www.prb.co.kr
B20㈜위닝아이비접촉 모바일 생체(지문, 장문) 인식 솔루션www.winningi.com
B21화민테크3초세이프티(자동차용 2차사고방지, LED 튜브안전표시판)www.fwamin.com
C01코너스톤 비지진 및 재난 관련 안부확인 시스템(Safetylink24)www.cornerstone-b.com
C02일본 IT 솔루션 비즈니스 매칭
C03세종학당재단한국어 모바일 학습 앱(세종한국어 어휘/세종한국어 문법/세종한국어 회화, 발음)https://www.ksif.or.kr/index.do
C04(재)한국과학창의재단사이언스레벨업 콘텐츠(가상현실 및 증강현실 기반의 실감체험형 교육콘텐츠 앱)https://www.kofac.re.kr
C05웹스톰NORI2APPhttp://nori2app.com/
C06에듀템하루 10분 중국어와 친해지는 시간 "보라구중국어"www.edutem.net
C07㈜삼우이머션IMMERUTION TRAINING 선박엔진 실습 VR 교구재 /VARLOS Smart Factory AR -Realwearwww.samwooim.com
C08㈜요트북스마트 마리나 플랫폼http://www.yachtbook.co.kr/
C09(주)아파트너아파트너www.aptner.com
C10㈜씨앤에스솔루션카드전표 어플리케이션http://www.cad.co.kr/cloud
C11㈜리나소프트열공시간 (APP), 열공시간 스터디 플래너www.rinasoft.co.kr
C12주식회사 비틀종이와크레파스 / 360VR체험관beetle-lab.com
C13와이즈모바일㈜위치기반 날씨앱, 오픈웨더(Open Weather) 및 주차비 아끼는 앱, 파킹박(Parking Park)www.wisemobile.co.kr
C14㈜딥비전스에어체커(Air-Checker), 미세찰칵http://deepvisions.co.kr
C15㈜알스피릿NowMoment Company – 상장기업 주가예측/외내부 영향지표 분석 콘텐츠 서비스www.rspirit.co.kr
C16유한회사 나노웨더초고해상도 기상기후 복원데이터 기술 알파멧(AlphaMet)www.nano-weather.com
C17㈜에스엠에스보안소프트웨어/패스볼트, 블랙매직, 아이세이퍼www.smsinfo.co.kr
C18페이업 주식회사블록체인 기반의 판매자를 위한 간편결제 시스템 ‘Payup 서비스’www.payup.co.kr
C19주식회사 애드잇스마트 병해충 검색 시스템http://www.additcorp.com
C20주식회사 옷딜패션중계 앱 서비스www.otdeal.io
C21(주)소프트파워SW자동화저작도구/스마트메이커www.smartmaker.com
C22주식회사 라베디자인멀티미디어 콘텐츠http://labae14.wixsite.com/labae
C23더테라피심리상담플랫폼 & 스마트미러 마인드코디thetherapy.co.kr
C24㈜씨브이티일렉트로닉스코리아Interactive White Board (터치디스플레이, 전자칠판)www.cvtelectronics.co.kr
C25공컴네트워크아두이노 DIY 피아노 키트 / 피노키트gongcom.kr
C26푸디온투어앱(Application) / 푸디온(foodieon)www.foodieontours.com
C27ViolinMusueM서비스/앱,웹.게임/그림책 - 동편제판소리 에니메이션 앱www.violinmuseum.com
C28㈜리디쉬친환경, 친에너지, 친경제적, 저탄소형 배달음식 그릇 순환 서비스www.redish.co.kr
C29클라우드포유AWS를 그려서 만들고 관리하는 VisCAtwww.cloud4u.io
C30주)제이제이기술햅틱 전자펜 & 필링펜과 함께하는 오링가 (미술 컨텐츠)www.feelingpen.com
C31인포소닉www.infosonic.net
C32㈜넷솔루션액션캠www.netsolution.kr
C33굿모닝코리아자산관리NH농협연금저축상품
D01제주특별자치도관광협회제주 지능형관광콘텐츠 (스토리플래닛, 브이디에스, 반딧불공작소, 웨이플러스, 에이투젯)www.visitjeju.or.kr
D023D 상상3D 프린터 제품 및 출력물www.3dsangsang.com
D03주식회사 한국표준장례문화원대장정 앱https://click9545.modoo.at/
D04D LABS미니드론축구경기장
D05페어네비전기시획 어플리케이션
D06㈜쓰리디코리아컬러 3D 프린터 GoodBoT 시리즈 , 필라멘트(PLA, Flexible, ABS, 향기 필라멘트 등)www.3dk.or.kr
D07이플랩㈜보행자용 증강현실 네비게이션 & O2O 마케팅www.Witchew.com
D08㈜유익소프트APP 토탈케어 서비스 '컨택'www.yooic.com
D09(주)엠카탈로그모바일 콘텐츠 디자인/반응 분석 솔루션 '메이크뷰'http://www.makevu.com
D10씨피디그룹캠지(CAM.G)www.cpdgroup.kr
D11㈜쿨투라칸차무등산애비뉴(Mudeungsan Avenue)www.MudeungsanAvenue.com
D12㈜유니컴태블릿용, 노트북용 충전보관함www.unicom.co.kr
D13아트맨미세빅(미세먼지 빅데이터) 모바일 어플리케이션www.misebig.com
D14주식회사 스타핑인공지능 모바일 이미지 검색쇼핑www.staping.co.kr
D16㈜나루애드영상배너www.naruad.com
D20㈜아이씨쥐LED 전광판 전시차량, LED 전시작품www.trinled.com
E01박스페이스랩토이와 결합한 아두이노 교육용 키트www.boxfacelab.com
E02틴소프트 주식회사온라인 수학 마춤학습 솔루션 '메타매쓰' 블록체인 기반 인공지능 능동형 교육플랫폼 '스터비'www.metamaths.com
E03틴메이저청소년을 위한 대학생 전공&입시 멘토링 플랫폼www.teenmajor.com
E04주식회사 모야커뮤니케이션분양권거래소' 아파트 분양권 정보 및 실제 매물현황을 한눈에 볼 수 있는 웹, 앱서비스를 제공www.buyhouse.co,kr
E05젠덕쇼보드(SHOWBOARD)' 부동산의 매물광고를 온오프라인 통합관리 하는 플랫폼www.genduck.com
E06쉐어멜론그저 이쁜 로고가 아닌 기업을 그대로 대변하는 브랜딩을 만들어보세요. 단 7분만 투자하시면 기업 브랜딩 컨설팅을 무료로 받아보실 수 있습니다. 전문가들의 다양한 디자인 연계 서비스도 만나 보세요.www.sharemelon.com
E07트립엔픽'"커스터마이징 로컬여행 맞춤 서비스" 트립엔픽www.tripnpick.com
E08다이어트치킨다이어트레시피&요리법와 식단을 제공하는 어플리케이션http://bit.ly/2tdyOFN
E09뷰자데GPS연동 위치기반 공간큐레이션/엔터테인먼트 모바일 앱서비스 'VUJADE(뷰자데)'https://play.google.com/store/apps/details?id=com.officialvujade.mobile&hl=ko
E10(주)콜미코펫택시 콜 중개 플랫폼 앱서비스 ‘펫츠’http://www.petts.co.kr
E11유한회사 동이AR/VR 기능을 활용하여 가상 전시를 통한 미술품 거래/대여 플랫폼 '아트가온(ARTGAON)'http://www.dongyiauction.com/
E12엘튜브특허 검색 및 동향 자동화 플랫폼http://Ltube.co.kr
E13아름다운 동행Beautiful Companion
E14주식회사 첸트랄눈 건강 VR헤드셋, VRight(브라이트)www.zentral.co.kr
E15페이리더스테이블오더' 고객이 본인의 스마트폰으로 주문/결제(더치페이) 할 수 있는 서비스 플랫폼www.tableorder.co.kr
E16주식회사 뉴코애드윈드음식과 함께 광고까지 배달하는 스마트 디디박스www.newkod.com
E17주식회사 두바여성 파트타임 일자리정보제공 어플 '이모'www.doobar.kr
E18㈜플레이브이알VR, AR 컨텐츠www.playvr.kr
E19캐링솔루션Longship360 VR Camera, Longship eNotewww.longship.kr
C34TVCC. Co. ltdTVCC 생방송 데일리 암호화폐 캐스팅 방송 ‘블록체인 투데이’ 라이브 방송 진행 블록체인 전문 미디어사 TVCC 소개 및 2019년도 방송진행 방향소개http://tvccnews.co.kr
D15XTOCKXTOCK 생태계를 유지하고 활성화하기 위한 프로토콜 소개, Global OTC Market 소개https://xtock.io/
D17Big CBIgC플랫폼 생태계 구성 및 미스터리 블록, BIGC COIN 소개http://www.bigccoin.com
D18BIEX2019년 상반기 글로벌 오프라인 거래소 론칭 레이어 발표 바이블코인 생태계 소개http://biblefintech.com/
D19Coinbit완성형 거래소 코인 DEX 상장, 강력 다중보안 메커니즘 소개https://www.coinbit.co.kr

행사장 가는 길

코엑스 홀 B1 이라고 쓰여 있어서 지하로 헷갈리기도 했습니다.

1층에 있는 B1 위치로 찾아가면 됩니다.

멀리서 바라본 행사장 입구입니다.

행사장 앞에는 부스 설명과 세미나 안내가 있고 한쪽에는 안내데스크가 있어 입장권을 받을 수 있습니다.

행사장 내부

행사장 초입부터 부스는 시작됩니다.

케이디자인미디어

AR 스티커를 활용하여 아이들 컨텐츠를 제공하는 업체였습니다.

AR 스티커가 어떻게 나오는지는 확인을 못해보았네요.

솔투온

학습용 질의응답 보조 기기로 보였습니다.

학생들이 BLE 기기로 선생님을 폰을 서버 삼아 퀴즈 답을 제출하고 그를 통해 학습률에 대한 통계 등을 지원한다고 하네요.

단 퀴즈 문제마다 답을 제출시 자기가 어떤 답을 제출한지 화면에 자기 번호가 나타나지만, 실제 맞춘 것인지에 대한 리액션은 따로 없었습니다.

선생님을 위한 통계 등의 화면에서만 확인이 가능하다고 들었던 것 같네요.

그래도 아이들의 적극적인 참여를 유도할 수 있는 서비스 같았습니다.

토비테크놀로지코리아

아이트래킹을 제공해주는 업체 부스였습니다.

사용자의 시선을 측정하여 데이터를 제공하는 것으로 보였습니다.

착용형과 설치형으로 아이트래킹이 가능하다고 하였습니다.

착용형은 마네킹의 안경이나 VR 기기 등으로 가능하였고, 설치형은 모니터 아래 카메라 등으로 측정이 가능하다고 하더군요.

흥미가는 아이템이나 실제 어떤 서비스에서 어떻게 활용될지는 궁금한 부분이었습니다.

실제 사용 중인 업체들로 코카콜라나 기타 큰 업체들을 설명해주셨으나, 정확히 어떤 사례에서 쓰이는지는 추가 설명을 듣진 못하였습니다.

스마트드림

폰을 찾기 위한 간단한 아이디어용 제품이었습니다.

폰이 어디있는지 모를 때 버튼을 누를 경우 폰에 설치된 앱에서 화면 및 소리로 알림을 주는 형태였습니다.

역시 BLE를 사용한 기술로 추가 기능들이 필요하지 않을까 싶은 서비스였습니다.

REMOFIT

골프 교정용 서비스 같았습니다.

간단히 시연 영상 등을 보았을 때 스윙 각도, 속도 등 여러 정보를 제공하는 것으로 보였습니다.

실제 어떻게 사용자의 스윙 등을 측정하는지는 살펴보지 못했네요.

제미타

나름 재미있어 보이는 체험형 게임이었습니다.

일반 게임의 버튼들을 운동기구 처럼 구성하여 게임 컨트롤을 위해 움직이게 만드는 서비스였습니다.

타격감도 확실히 느낄 수는 있고 맞춰서 게임 컨텐츠도 잘 준비된 느낌이었습니다.

다만 개인들이 하기엔 덩치들이 큰 장비들이고, 아이들 운동용으로 학원 등에서 활용하기엔 좋아 보였습니다.

미래야놀자

이런 전시장의 이젠 단골소재가 된 VR 기반 체험형 게임으로 보였습니다.

점심시간인지라 부스에 사람이 없어 체험은 못했네요.

아마 이번 전시장에선 그나마 인기 좀 끌 부스 같았습니다.

글로싸인

모든 계약을 전자 계약서로 만들고 보관 및 관리를 해주는 서비스였습니다.

블록체인 기술을 접목하여 관리를 해주며, 근로계약서나 일반 임대차 계약서 등의 개인 서비스 및 B2B용 계약서 등을 위한 회사용 서비스 등이 있어보였습니다.

향후 앱으로도 지원 예정이라네요.

역시나 블록체인

블록체인 기반 서비스도 한쪽 면을 가득 채울 정도로 많았습니다.

개인적으로 관심이 없는 쪽이라 자세히는 못봤지만, 게임형태도 있고 다양한 접목 사례들을 들고 나온 듯 했네요.

화민테크

앱과는 어떤 연관이 있는지는 모르겠지만, 자동차 사고시 표식 기능을 하는 장비도 있었습니다.

기존 고장난 차량 뒤에 적당한 거리를 두고 삼각대를 설치해야 되는데, 이건 차 위에 올리기만 하면 된다네요.

사용시에만 저 위험한 풍선이 튀어나온답니다.

아이씨쥐

이렇게 대형 LED 제품들을 전시해 놓은 부스도 있었습니다.

다양하고 부스가 거대하였죠.

빠질수 없는 드론

이렇게 미니 드론도 판매 중입니다.

특가라고 하지만... 저는 잘 모릅니다..

위닝아이

손바닥으로 인증을 해주는 서비스였습니다.

어떤 방식인지 궁금하였지만, 아쉽게도 점심시간이라 부스에 아무도 없었네요.

고객사 라인업으로 봐서 어느정도 상용화도 진행 중인 서비스 같네요.

인포소닉

비가청 음파를 이용한 데이터 전송 기술인 소닉 코드를 개발한 곳이라고 하네요.

안내 문구에 QR과 바코드를 대체할 서비스처럼 쓰여있긴 하였는데요.

실제로는 좀더 조심스럽게 써야하는 서비스들에 필요한 기술 같았습니다.

QR이나 바코드처럼 접근성이 좋은 것은 아니지만 1:N 통신 등에서는 유리한 점들도 많아 보였습니다.

실제 이 기술을 활용하기 위한 접근들이 이루어지고 있다고 하니 조만간 실제 활용한 서비스들도 볼 수 있지 않을까 싶었습니다.

레디쉬

나름 참신한 서비스 같은 부스였습니다.

배달 그릇을 수거 및 세척 등의 관리를 해주는 서비스였습니다.

최근 대두되는 환경 문제 등의 주제 의식과 우리나라에서 흔한 배달 서비스의 수거비용에 대한 걱정을 파고든 서비스 같네요.

공컴네트워크

아두이노를 활용한 DIY 피아노 키트로 코딩 교육을 진행하는 서비스였습니다.

현재 유료 커리큘럼으로는 파이썬 및 스크레치 등을 진행하고 있다네요.

스토리앤브라더스

AI 를 통한 팀 매칭 서비스 및 커뮤니케이션, 프로젝트 관리 등을 지원하는 서비스입니다.

스타트업이나 신규 팀 셋업이 필요한 쪽에서 한번 고려해볼만 한 서비스였습니다.

크레아트봇

허밍버드? 라는 보드와 모터 등을 이용해 DIY 장난감 등을 만들 수 있는 서비스였습니다.

스크레치 등을 통해 프로그래밍 교육을 하는 것으로 보였습니다.

아파트너

아파트 앱에서도 부스에 나오셨네요.

아파트 관련 관리 및 커뮤니케이션 지원 등을 제공하는 것 같네요.

요트북

전시장에 여행 관련 서비스들도 꽤 있었는데요.

그 중 하나였던 요트를 타고 여행하는 서비스였습니다.

특이해보여서 찍어봤네요.

와이즈모바일

파킹박이라는 주차장 중계 서비스였습니다.

주차장에는 관리시스템 및 차단기 기기 등을 통해 고객 유치 및 출입 제어를 제공하였고,

(차단기는 옵션인 듯 했습니다.)

사용자에게는 미리 주차장 일일권 등을 선결제 후 사용이 가능하게 하는 서비스였습니다.

대략 서울경기 등에 300여곳의 제휴를 맺고 있고, 강남에도 많은 곳과 제휴 중이라네요.

리나소프트

공부도 관리해주는 스터디 플래너 서비스입니다.

시간 관리 등을 제공하는 것 같네요.

딥비전스

딥러닝과 이미지 프로세싱 기반으로 미세먼지 측정 솔루션을 제공하는 부스였습니다.

장비들도 있고 사용 시나리오가 궁금했지만... 역시 점심시간인지라.....

유익소프트

앱호스팅 서비스라고 하는데요.

실제 앱을 호스팅 하는 건 아니고 앱을 템플릿화 하여 그에 맞춰 제작 및 서버 호스팅을 제공하는 거 같았습니다.

앱을 실제 앱스토어에 올리거나 관리는 직접 해야된다는 것 같네요.

영세한 자영업 쪽의 수요가 있을지 궁금한 서비스였습니다.

더테라피

심리상담플랫폼이라는데요.

그림치료 같은 것들도 준비해 두신것 같고....

뭔가 중요한 작업 중이신 것 같아 자세히 못 물어봤네요.

푸디온투어

또 하나의 여행 서비스였습니다.

여행시 해당 지역의 집밥? 가정식? 등을 연결해주는 서비스 같았습니다.

요식업 식당들이 아니라 가정집을 연결해 주는 것으로 보이는데요.

서비스가 런칭된다면 향후 관리가 참 중요할 서비스 같았습니다.

BIEX

좀 특이한 컨셉의 블록체인 부스였습니다.

부스 설명에는 바이블코인 생태계를 소개한다고 하는데요.

기독교 기반 금융 서비스 같네요. 종교 기반의 서비스 부스는 처음 접해본 것 같네요.

캐링솔루션

전자노트를 전시하고 있어 구경했습니다.

일반적인 스크린이 아니라 전력소모가 적고 감압식으로 노트가 가능한 제품이었습니다.

대신 저장이 불가하여 폰에 캠스캐너 등의 앱을 깔아 캡쳐하여 저장을 대신하다고 하네요.

간단한 메모 용으로는 괜찮아 보였습니다.

뉴코드애드윈드

배달 오토바이 박스에 광고를 유치할 수 있는 제품입니다.

3 면에 모니터와 스피커를 통해 영상 및 음성 광고를 지원하는 듯 했습니다.

실제 상용화에는 내구성 등이 문제가 되지 않을까 싶네요.

페이리더스

식당 등에서 손님들의 폰을 통한 직접 주문이 가능한 앱 서비스입니다.

식당 측에는 관리 시스템을 지원해 주문 관리가 가능한 것으로 보이네요.

기존 서비스들이 있는 것으로 아는데요. 앱을 퍼트리는 것이 관건이 될 것 같네요.

콜미코

펫츠라는 반려동물 택시 중계 서비스입니다.

반려동물 계의 카카오 택시를 노리는 서비스 같네요.

트립엔픽

맞춤형 여행 서비스입니다.

여러 옵션 등을 통해 자신에게 맞는 현지 여행 일정을 잡아주는 서비스 같았습니다.

후기

작년도 그랬고, 올해도 기술에 대한 부분보다는 다른 곳에서는 어떤 비즈니스를 먹거리로 보고 있나라는 참고를 할 수 있는 행사였던 것 같습니다.

다소 아쉬운 점도 많지만 그래도 앱을 통한 서비스를 하는 사람들이라면 한번 구경해볼만 한 것 같네요.

사전 예약의 경우 무료이니, 코엑스 근처에 갈 일이 있다면 부담없이 둘러 볼 수가 있을 것 같습니다.


좀 지난 내용이지만...
점심에 참치정식을 먹고 왔었습니다.
만오천원의 저렴한 가격 대신 리필은 안되었죠.
참치가 나오기까지 시간도 오래 걸리는 편이었습니다.
하지만 샐러드바같이 셀프로 가져다 먹을 음식들이 많더군요.
개인적으로 다 괜찮았고요.
회는 좋아하시는 분들 평으론 좋은 편은 아니다 하셨지만.. 전 막입이라 회도 맛있었어요 ㅠㅠ
그리고 매운탕이 나오는데 맛있더라고요.
꼭 회가 아니라 탕 먹으러 갈만할 거 같았어요.
저한테 나름 맛있는 집이었습니다.


점심에 아웃백 코엑스 점을 다녀왔습니다.
초입부터 토마호크를 적극적으로 홍보를 해주셨지만...
토마호크는 거대하고... 비싸요..
그래서 런치메뉴 위주로 주문하였답니다 ㅋ
주문이 꼬이고 결제도 꼬이는 등 저희도 직원분들도 당황스런 일들이 파란만장하게 펼쳐졌지만..
그래도 맛있게 잘 먹고 왔네요.
그리고 이런 곳을 갈때마다 느끼지만...
주문은 정말 어려운 일 같네요;;;

+ Recent posts