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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리

Sencha Touch 2 Tutorial - MVC -

2012. 4. 14. 20:44 | Posted by 솔웅


반응형

Managing Dependencies with MVC

센차터치 2 앱에서는 종속적인 관계가 정의될 수 있는 곳이 두 군데 있습니다. 한군데는 application 이고요 다른 곳은 application class 입니다. 이 가이드에서는 앱내에서 어디에 어떻게 종속적인 관계를 정의하는지에 대해 설명 드리겠습니다.

Application Dependencies

MVC 어플리케이션을 생성할 때 Ext.application 에 손쉽게 models, views, controllers, stores, profiles 를 지정할 수 있도록 해 줍니다. 아래 예제가 있습니다.

Ext.application({
    name: 'MyApp',

    views: ['Login'],
    models: ['User'],
    controllers: ['Users'],
    stores: ['Products'],
    profiles: ['Phone', 'Tablet']
});


위 예제에 있는 5개의 configuration option 들은 애플리케이션이 주로 models, views, controllers, stores, profiles 로 구성되는데요 그 각각을 별도의 파일로 만들고 그 만든 파일을 로드할 수 있도록 해 줍니다. 위 예제를 실행하면 센차터치는 아래 경로의 파일들을 로드하게 될 겁니다.

app/view/Login.js
app/model/User.js
app/controller/Users.js
app/store/Products.js
app/profile/Phone.js
app/profile/Tablet.js


위 예제는 아래처럼 Ext.requre를 해서 로드할 수도 있습니다.

Ext.require([
    'MyApp.view.Login',
    'MyApp.model.User',
    'MyApp.controller.Users',
    'MyApp.store.Products',
    'MyApp.profile.Phone',
    'MyApp.profile.Tablet'
]);


애플리케이션에 클래스가 추가되면 추가될 수록 처음의 configurations 방법이 전체 클래스이름을 쓸 필요 없이 파일 이름만 쓰면 되므로 점점 더 효율적이 될 겁니다. 이 방법은 단지 파일을 로딩하는 것 이외에 아래와 같은 일도 추가적으로 하게 됩니다.

* profiles - 각 프로파일들의 instantiate 과 active 여부 판별. active 여부가 판별 되면 해당 프로파일을 로드 함
* controllers - 로딩 후 각 Controller instantiate 함
* stores - 각 Store들 instantiate 하고 아무것도 지정된 것이 없으면 디폴트 store ID 를 세팅함


위 기능들을 이용하기 원하시면 첫번째 configuration options 를 사용하시면 좋습니다.





Profile-specific Dependencies

Device Profile을 사용한다면 특정 디바이스에서만 사용되는 clsss 들이 있을겁니다. 예를 들어 태블릿에서는 폰 보다는 좀 더 많은 기능이 들어갈 겁니다. 그 얘기는 곧 태블릿쪽이 좀 더 많은 클래스를 로드해야 한다는 것이죠. 이 필요한 클래스들은 각각의 프로파일 내에서 정의할 수 있습니다.

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

    config: {
        views: ['SpecialView'],
        controllers: ['Main'],
        models: ['MyApp.model.SuperUser']
    },

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


이렇게 하면 위 프로파일이 active 되면 config에서 설정한 클래스들이 로드되게 됩니다. 위 태블릿 프로파일이 아니라 폰 프로파일이 active 되면 이 클래스들은 로드되지 않고 폰 프로파일에서 설정한 config에 있는 클래스들이 로드 되겠죠.

이렇게 각 디바이스 별로 프로파일을 만들고 그 프로파일 내에서 필요한 클래스들을 로드 하도록 함으로서 여러분들이 만든 애플리케이션이 특정한 디바이스가 아니라 여러 디바이스에서 사용할 수 있게 됩니다. 앱이 시작할 때 각 프로파일을 체크하고 그 프로파일에 필요한 클래스를 로드하기 때문이죠.

만약 앱의 용량이 아주 클 경우에는 이 방법을 사용해서 처음 앱이 실행될 때 그 앱이 실행된 디바이스에 필요한 클래스들만 다운로드 하도록 만들어서 용량을 줄일 수도 있을겁니다.

Nested Dependencies

규모가 큰 앱에서는 models, views, controllers를 subfolder들로 분리해서 프로젝트를 organize 하는것이 일반적입니다. 특히 views 부분이 더 그런데요. 큰 규모의 앱에서는 수백개의 view 클래스가 있는 것이 흔한일입니다. 그래서 그 클래스들을 더 간단하게 관리할 수 있도록 폴더별로 관리하는 것 입니다.

subfolders로 관리하게 되면 코드상에서 그 경로를 . 로 연결해서 사용하면 됩니다.

Ext.application({
    name: 'MyApp',

    controllers: ['Users', 'nested.MyController'],
    views: ['products.Show', 'products.Edit', 'user.Login']
});


이 5개의 파일들은 아래와 같은 경로에서 로드될 겁니다.

app/controller/Users.js
app/controller/nested/MyController.js
app/view/products/Show.js
app/view/products/Edit.js
app/view/user/Login.js


여기서 각각의 configuration 에서 서로 혼합하거나 match 할 수 있습니다. model, view, controller, profile, store 에 대해 클래스 이름의 마지막 부분을 사용하거나(directory convention을 따르고 있다면) 또느 전체 클래스 이름을 사용할 수 있습니다.

External Dependencies

우리는 앱 외부에 있는 클래스를 로드할 수도 있습니다. 이를 위해 사용하는 일반적인 방법은 여러 어플리케이션 사이에서 authentication(인증) 로직을 공유하는 방법이 있습니다. 아마 여러분의 여러개의 앱이 공동의 유저 데이터베이스에 로그할 필요가 있을 수 있을겁니다. 그럴 경우 그 앱들 사이에서 공통으로 인증 로직을 사용해서 접근하면 됩니다. 이를 위한 쉬운 방법은 폴더를 앱 폴더와 따로 만드는 것입니다. 그리고 여러분의 앱에서 이 폴더에 dependency를 주시면 됩니다.

예를 들어 login controller,유저 모델과 로그인 폼 뷰를 포함한 로그인 코드의 경우를 봅시다.  이 모든것을 어플리케이션 안에서 사용하기를 원합니다.

Ext.Loader.setPath({
    'Auth': 'Auth'
});

Ext.application({
    views: ['Auth.view.LoginForm', 'Welcome'],
    controllers: ['Auth.controller.Sessions', 'Main'],
    models: ['Auth.model.User']
});


이럴 경우 아래 파일들을 로드할 겁니다.

Auth/view/LoginForm.js
Auth/controller/Sessions.js
Auth/model/User.js
app/view/Welcome.js
app/controller/Main.js


처음 나오는 세개의 파일이 어플리케이션 밖에 있는 파일을 로드하는 것입니다. 나머지 두개는 앱 내에 있는 파일이구요. 이렇게 함으로서 어플리케이션 파일과 외부의 독립된 파일을 서로 mix하고 match 해서 사용 할 수도 있습니다.

외부 파일을 로드할 수 있도록 하려면 그 파일이 어디에 있는지를 Loader 에게 알려주면 됩니다. 이것은 위 예제에서 Ext.Loader.setPath 에서 한 일입니다. 이 경우 Auth 폴더 안의 Auth namespace로 시작되는 모든 파일을 Loader에게 찾으라고 지시하게 되는 겁니다. 이렇게 함으로서 Auth 코드를 애플리케이션 외부에 따로 떨어뜨려서 관리할 수 있고 그렇게 함으로서 전체 framework이 모든 필요한 것들을 load 하게 됩니다.

Where Each Dependency Belongs


각각의 dependency를 정의하는 장소를 정할 때의 일반적인 룰은 여러분의 클래스들을 완전하게 self-contained 하도록 유지하는 것입니다. 예를 들어 몇개의 다른 뷰를 가지고 있는 한개의 뷰가 있다고 했을 때 그 dependency들은 어플리케이션이 아니라 그 뷰 클래스 안에서 정의해야 합니다.

Ext.define('MyApp.view.Main', {
    extend: 'Ext.Container',

    requires: [
        'MyApp.view.Navigation',
        'MyApp.view.MainList'
    ],

    config: {
        items: [
            {
                xtype: 'navigation'
            },
            {
                xtype: 'mainlist'
            }
        ]
    }
});


app.js 에서는 아래와 같이 해 줍니다.

Ext.application({
    views: ['Main']
});


두가지 이유 때문에 이렇게 dependency들을 정의하는것이 가장 좋은 방법이라고 할 수 있습니다. 첫번째는 MyApp.view.Main을 불러옴으로서 여러분의 app.js 는 간단 명료하게 유지할 수 있고 이러한 dependency들을 이미 다 만족하도록 만들었다는 것을 확인 할 수 있습니다.

//this is bad
Ext.application({
    views: ['Main', 'Navigation', 'MainList']
});


간단하게 생각하면 app.js 안에는 단지 top-level 뷰들만 넣으시면 됩니다. 만약 여러분 앱에 Ext.create('MyApp.view.SomeView')를 사용한다면 그 뷰는 top-level일 겁니다. 한 뷰가 다른 뷰의 sub-view라면 (위 예제에서 MyApp.view.Navigation 과 MyApp.view.MainList 같은) 이 뷰는 app.js에 있을 필요가 없습니다.

Changes since 1.x

센차터치 1 (Sencha Touch 1)에서는 Ext.application call 과 같이 콘트롤러 안에서도 사용되어졌었습니다. 이 방법이 편리한 측면이 있지만 Controller 가 너무 뷰,모델, 스토어들을 통제하는 면이 있기도 합니다. 1.x 에서는 아래와 같이 사용할 수 있습니다.

//1.x code, deprecated
Ext.regController('SomeController', {
    views: ['Login'],
    models: ['User'],
    stores: ['Products']
});

이 방법은 Ext.application에서 뷰,모델,스토어를 정의하는 것과 동일합니다. 콘트롤러에서 이 클래스들에 접근하는데에는 편리합니다. 1.x 는 getLoginView()와 getUsermodel() 두개의 함수를 generate 합니다. 그리고 이 콘트롤러에서 정의한 Stores 에 대한 reference를 return 하는 getStore() 함수를 노출시킵니다. 2.x 에서는 이러한 함수들을 사용하지 않습니다. 두가지를 동시에 사용할 수도 잇습니다.

//creating a view - 2.x uses the standardized Ext.create
this.getLoginView().create();
Ext.create('MyApp.view.Login');

//getting a Model - just type out the Model name (it's shorter and faster)
this.getUserModel();
MyApp.model.User;

//Ext.getStore can access any Store whereas the old this.getStore only
//accessed those Stores listed in your Controller
this.getStore('Products');
Ext.getStore('Products');


이 함수들을 없애면 앱을 처음 시작할 때 로딩 시간을 줄일 수 있습니다. 왜냐하면 framework 이 각 콘트롤러에서 정의한 각 모델,뷰에 대한 함수들을 generate 할 필요가 없기 때문입니다. 또한 이러한 함수들을 사용하지 않으면 MVC 모델에 더 부합하는 설계를 할 수가 있습니다.


반응형