반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함


오늘 다룰 주제는 Sencha Touch 2 어플리케이션에 대한 기본적인 구조와 개념들을 다룰겁니다.
이론적인 부분이라서 약간 지루할 수는 있을텐데요. 이런 기본 개념들을 잘 이해하고 넘어가면 실제 코딩할 때 많은 도움이 됩니다.

오늘 글은 Sencha Touch Beta 2에서 제공하는 Tutorial 중 All about Application을 정리 했습니다.

====== o ====== o ====== o ======= o ======= o ======

Intro to Applications with Sencha Touch 2

Sencha Touch 2 는 다양한 플랫폼에서 동작하는 어플리케이션을 만들 수 있도록 제작됐습니다.
Sencha Touch 2는 어플리케이션을 최대한 간단하게 만들도록 하기 위해 간단하면서도 강력한 어플리케이션 아키텍쳐를 제공합니다.
이 아키텍쳐는 MVC(Model View Controller) 패턴에 맞게 만들어 졌습니다.

이 패턴은 가독성 있고 테스트하기 쉽고 유지보수 하기 쉬운 코딩을 지원합니다.
이 외에 다음과 같은 기능들을 제공합니다.

- History Support : 앱 내에서 full back button을 지원하고 어느 위치에서든지 link가 걸릴수 있도록 합니다.
- Deep Linking : 앱의 어떤 화면에서도 deep link들을 공유할 수 있습니다. 그냥 웹 페이지에 링크 걸듯이 하면 됩니다.
- Device Profiles : 어플리케이션의 UI를 phone, 태블릿 기타 디바이스의 종류에 맞게 쉽게 customizing할 수 있도록 지원합니다.

Anatomy of an Application

어플리케이션은 Model,View,Controller,Store,Profile과 아이콘, launch screen 이미지 등 추가적인 metadata들의 조합입니다.




- Models : 앱에서 객체의 타입을 표시합니다. 예를 들어 e-커머스 앱의 경우 유저, 제품, 주문과 관련한 모델이 필요합니다.
- View : 객체나 데이터들을 display하는 것을 다루는 부분입니다.
- Controllers : 어플리케이션 내의 상호 작용을 다룹니다. 어떤 이벤트를 listening하고 핸들링 하는 것도 콘트롤러에서 하게 됩니다.
- Store : 앱에 데이터를 로딩하는 일을 책임 집니다. 리스트나 데이타뷰 같은 컴포넌트들도 다룹니다.
- Profile : 앱의 UI를 디바이스 종류별로 쉽게 customizing 할 수 있도록 도와 줍니다.

어플리케이션은 우선 Sencha Touch 어플리케이션이란 것을 선언하면서 시작합니다.
코드는 대개 아래와 같습니다.

Ext.application({
    name: 'MyApp',
    models: ['User', 'Product', 'nested.Order'],
    views: ['OrderList', 'OrderDetail', 'Main'],
    controllers: ['Orders'],

    launch: function() {
        Ext.create('MyApp.view.Main');
    }
});

name은 전체 어플리케이션을 대표하는 글로벌 namespace입니다. 여기에는 model,view,controller 그리고 다른 클래스들이 다 포함돼 있습니다.
예를 들어 name이 MyApp이라면 이에 따른 클래스들인 MyApp.model.User, MyApp.controller.Users, MyApp.view.Main 등이 포함 돼 있을 겁니다.
애플리케이션은 models, views, controllers 라는 사전 정의 된 configuration을 자동적으로 로딩해서 사용합니다.
이것을 기초로 효율적인 file구조를 만들 수 있습니다. 예를 들어 app/model 폴더나 app/controller 폴더를 만들 수 있고 그 안에 관련된 파일들을 넣을 수 있습니다.
custom dependency에 대해서는  Dependencies section of the Ext.app.Application docs 를 참조하세요.

Controllers

콘트롤러는 어플리케이션을 서로 연결시켜 주는 역할을 합니다. 콘트롤러는 이벤트를 리스닝(예를 들어 button을  tap 하는 이벤트 등)하고 어떤 이벤트가 발생하면 이에 대한 핸들링을 합니다.
이렇게 함으로서 코드를 보기 좋게 작성할 수 있고 view 로직과 control 로직을 구분해서 코딩 할 수 있습니다.
예를 들어 유저가 로그인 폼을 통해 로그인하려고 하는 경우. View에서는 필드나 버튼 같은 form을 작성할 겁니다.
controller는 겉으로 드러나는 부분은 미미하지만 그 역할을 아주 중요합니다. 그리고 몇가지 규칙이 있습니다. 여러분 앱에 있는 각각의 콘트롤러는 모두 Ext.app.Controller의 subclass 입니다. 콘트롤러는 MyApp.controller.* namespace에 존재합니다. 예를 들어 세션 콘트롤러가 있다면 그것은 MyApp.controller.Sessions 라고 불려질겁니다. 그리고 app/controller/Sessions.js 라는 파일로 존재할 겁니다.

각각의 콘트롤러들이 Ext.app.Controller의 subclass 임에도 이 콘트롤러들은 Application 이 처음 로드 될 때 한번 초기화 됩니다. 모든 콘트롤러는 각각 한개의 인스턴스만 있습니다. 그리고 이 콘트롤러 인스턴스 세트는 어플리케이션에 의해 내부적으로 manage 됩니다. 위 예제와 같이 어플리케이션의 콘트롤러 config를 사용하면 모든 콘트롤러와 인스턴스들은 자동적으로 로딩되게 됩니다.

A simple example

아래에 세션 컨트롤러와 관련한 예제가 있습니다. 이 예제에는 2개의 콘트롤러 configuration이 있습니다. (refs,control). Refs는 이 앱의 컴포넌트를 쉽게 찾을 수 있도록 도와 줍니다. 아래 예제의 경우는 formpanel 이라는 xtype과 매치되는 모든 콘트롤러를 검색하고 첫번재로 찾은 컴포넌트에 loginForm 프로퍼티를 할당하게 됩니다. 이 프로퍼티는 나중에 doLogin 함수에서 사용할 겁니다.

두번째는 control configuration입니다. refs처럼 이 configuration은 그 안에 버튼이 있는 formpanel을 찾기 위한 ComponentQuery selector를 사용합니다. 예를 들어 이 콘트롤러는 login form의 submit button을 찾을 겁니다. 유저가 이 버튼을 tap하면 컨트롤러의 doLogin 함수가 불려질 겁니다.

Ext.define('MyApp.controller.Sessions', {
    extend: 'Ext.app.Controller',

    config: {
        refs: {
            loginForm: 'formpanel'
        },
        control: {
            'formpanel button': {
                tap: 'doLogin'
            }
        }
    },

    doLogin: function() {
        var form   = this.getLoginForm(),
            values = form.getValues();

        MyApp.authenticate(values);
    }
});

doLogin은 간단할 겁니다. 왜냐하면 위 예제에서 loginForm ref를 정의해서 Controller가 자동적으로 getLoginForm을 작동시키고 match 되는 formpanel을 리턴합니다. 이 form reference를 가지게 되면 유저 네임과 패스워드 값을 가져와서 이를 검증하는 함수에 전달할 겁니다. 이러한 작업이 컨트롤러가 하는 작업입니다. 이벤트가 발생하는지를 listening 하고 어떤 작업을 하게 됩니다. 이 경우에는 아이디,패스워드 검증을 하는것이죠.

컨트롤러에 대해 좀 더 자세히 알고 싶으시면 여기 controllers guide를 참조하세요.

Stores

store는 데이타를 다루는 매우 중요한 부분입니다. 반면에 그 사용법은 간단합니다. Store는 Model 인스턴스의 배열일 뿐입니다. Data-bound 컴포넌트는 DataView리스트 같이 Store의 각 Model 인스턴스에서 한 item을 render 합니다. Model 인스턴스가 추가되거나 삭제되는 store 이벤트가 발생하면 이 data-bound 컴포넌트가 listening 해서 update를 해 주게 됩니다.

Store가 무엇이고 이것을 앱에서 컴포넌트와 같이 어떻게 사용할 것인가에 대해 더 자세히 아시려면 store guide 부분을 참조하세요. 몇가지 꼭 알아 두셔야 할 부분들이 있으니 꼭 보세요.

Device Profiles

Sencha Touch는 성능이나 해상도가 다른 다양한 device들에서 사용할 수 있도록 해 줍니다. 태블릿에 맞게 작업하면 폰에 안 맞거나 그 반대의 경우가 있을 수 있습니다. 그래서 이런 서로 다른 device에는 그에 맞는 각각의 view들을 만들어야 합니다. 하지만 단지 다른 UI를 보여주가 위해 어플리케이션을 여러개 만들 필요는 없습니다. Sencha Touch는 이 경우에 가능한 많은 code를 서로 share 할 수 있도록 해 줍니다.

Device Profile은 서로 다른 device에 여러분의 앱이 제대로 보여지고 동작할 수 있도록 해 주는 간단한 클래스입니다. 처음에는 이 profile 없이 앱을 개발하실 겁니다. 그리고 이 profile은 나중에 추가 되게 됩니다. 그 앱이 특정 디바이스에서만 동작하는 앱이라면 profile은 작업을 할 필요가 없겠죠. 그리고 특정 디바이스일 경우에 추가적인 model,view,controller 등이 로드 되게 할 수 도 있습니다.

이 프로파일을 사용하기 위해서는 이 프로파일(device)들이 무엇인지 Application에 얘기를 해 주고 그 디바이스들을 위해 Ext.app.Profile 서브클래스를 생성하시면 됩니다.:

Ext.application({
    name: 'MyApp',
    profiles: ['Phone', 'Tablet'],

    //as before
});

위의 경우 어플리케이션은 app/profile/Phone.js와 app/profile/Tablet.js를 로드하게 될 겁니다. 아래에 Tablet에 대한 예제가 있습니다.

Ext.define('MyApp.profile.Tablet', {
    extend: 'Ext.app.Profile',

    config: {
        controllers: ['Groups'],
        views: ['GroupAdmin'],
        models: ['MyApp.model.Group']
    },

    isActive: function() {
        return Ext.os.is.Tablet;
    }
});

isActive 함수는 이 앱이 태블릿에서 작동을 할 때 true를 return 할 겁니다. 이 경우 약간 부정확 할 수도 있습니다. 왜냐하면 태블릿과 폰 사이에 무수 히 많은 모양과 size를 가진 device들이 있거든요. 태블릿인가 혹은 phone인가에 대한 확실한 구분이 사실은 없습니다. Sench Touch의 Ext.os.is.Tablet은 iPad에서 작동하면 true를 리턴하고 다른 경우엔 false를 리턴합니다. isActive에 다양한 디바이스를 넣어서 사용하시면 됩니다.

한가지 명심해야 할 것은 오직 하나의 Profile만이 isActive 함수에서 true를 리턴한 다는 것입니다. 1개 이상이 true일 경우 첫번째 매치되는 것만 true를 return 하고 나머지는 무시 될 겁니다. 그리고 이 후에 이 true로 return 된 첫번째 profile에 맞는 부분들이 실행이 될 거구요.

현재의 프로파일에 대해 추가적인 model,view,controller, store들이 있다면 이는 어플리케이션이 자동적으로 로딩을 할 겁니다. (currentProfile 에 관해서 좀 더 알고 싶으신 분은 여기를 클릭하세요.)아래와 같이 해당 파일을 로드하게 될 겁니다.

    views: ['GroupAdmin'] will load app/view/tablet/GroupAdmin.js
    controllers: ['Groups'] will load app/controller/tablet/Groups.js
    models: ['MyApp.model.Group'] will load app/model/Group.js

대부분의 경우 Profile은 특정 디바이스에 추가적인 기능이나 좀 다른 뷰나 store를 필요로 할 때 사용 될 겁니다. 좀 더 자세한 사항은 device profiles guide를 참고하세요.


Launch Process

각 어플리케이션들에는 launch 함수를 정의할 수 있다. 이 launch 함수는 앱이 로드되고 launch될 준비가 되어있을 때 실행 되는 함수 입니다. start up 로직을 넣을 최적의 장소죠. 특히 main view structure를 생성하기에 적합한 장소입니다.

launch 함수와 더불어 앱의 startup 로직을 넣을 좋은 장소가 두군데 더 있습니다. 첫번째로 각 controller에는 init 함수를 정의할 수 있습니다. 이 함수는 어플리케이션 launch 함수가 시작되기 이전에 call 됩니다. 두번째로는 Device Profile을 사용할 경우인데요. 각각의 Profile에는 나름대로의 launch 함수를 정의할 수 있습니다. 이 함수는 application launch 함수 전에 그리고 controller의 init 함수 이후에 실행 됩니다.

주의 할 것은 해당 Profile에 매치하는 Device에서만 이 Profile launch 함수가 실행된다는 겁니다. 예를 들어 Phone과 Tablet 프로파일을 정의했고 이 앱을 tablet에서 실행할 경우 tablet의 launch 함수만 call 됩니다.
앱이 시작할 때 call 되는 함수들의 순서는 아래와 같습니다.

    Controller#init functions called
    Profile#launch function called
    Application#launch function called
    Controller#launch functions called

Profile을 사용할 때 Profile launch 함수 안에 bootup 로직을 넣는 것이 일반적입니다. 왜냐하면 각 프로파일들은 startup때 실행될 필요가 있는 각기 다른 view 세트를 가지고 있기 때문입니다.

Routing and History Support

Sencha Touch 2는 Routing과 History를 support합니다. Kitchen Sink 같은 SDK 예제를 보면 각 화면별로 옮겨다니기 쉽게 history를 사용해서 지원합니다. 특히 안드로이드의 경우 유용합니다.

이 히스토리 기능을 제대로 보여주는 에제는 Kitchen sink 예제입니다. 이 예제에서는 히스토리를 위한 라우팅과 상대 restoration 과 관련한 많은 문서들이 있습니다.
~~~~~~ ~~~~~~
반응형

Comment