2016년 5월 4일 수요일

Angularjs Service

angularjs에서 서비스의 역할은 서버 프로그램에서의 서비스 계층의 역할과 동일하다. 컨트롤러에서 모두 처리할 수도 있지만 다른 컨트롤러나 모듈에서 공통으로 사용되기에 중복되는 코드들이나 로직이 복잡하여 컨트롤러에 작성하면 코드가 복잡해지는 코드들을 정리해서 몰아넣기 좋은 계층이라 생각된다.

자체적으로 제공하는 내장 서비스들도 많은데 여기 서 확인할 수 있다. 서비스를 생성해서 사용할 수 도 있는데 그 방법은 factory 메서드, service메서드를 사용하는 두가지 방법이 있다.
        angular.module("myapp", []).module.factory('dateTimeService', function () { 
            var dateTimeSvc = {};
            dateTimeSvc.getDate = function () {
    return new Date().toDateString();
            } 
            dateTimeSvc.getTime = function () {
    return new Date().toTimeString();
            } 
            return  dateTimeSvc; 
        });
        angular.module("myapp", []).module.service('dateTimeService', function () { 
            this.getDate = function () {
    return new Date().toDateString();
            } 
            this.getTime = function () {
    return new Date().toTimeString();
            } 
        });
두 방법의 차이는 factory 메서드에서는 서비스 객체를 반환해야 하는 반면 service 메서드는 this 에 필요한 속성, 메서드를 바인딩하는 점이다. 생성 방법 외에는 동일하니 편한쪽을 택해 사용하면 될듯 하다.

생성된 서비스는 컨트롤러에서 사용할 수 있다. 사용방법은 아래 코드와 같다.
        angular.module("myapp", []).module.service('dateTimeService', function () { 
            this.getDate = function () {
    return new Date().toDateString();
            } 
            this.getTime = function () {
    return new Date().toTimeString();
            } 
        }).controller("myCtrl", function($scope, dateTimeService){
            $scope.time = dateTimeService.getTime();
        });
컨트롤러 메서드 함수의 인자에 사용하려는 서비스의 이름의 인자를 선언하면 해당 서비스가 할당된다. angularjs 코드에서 이 부분을 주입해 준다고 하는데 어떻게 구현을 하고 있는지는 나중에 확인해 볼 일이다.

Angularjs Filter

필터는 데이터를 표시할 때 데이터를 보여주는 형식을 설정하는 컴포넌트다. 필터를 적용해서 대소문자가 섞여있는 문자열을 전부 소문자로 표시할 수도 있고 숫자 데이터에 자릿수 구분자를 추가하거나 표시 소숫점 자릿수를 제한하는 등 표시형식을 쉽게 결정할 수 있다.
<!DOCTYPE html>
 <html>
 <head>
 <script src="js/angular.min.js"></script>
 <script>
 var app = angular.module("myapp", []);
 app.controller("MyFilterDemoCtrl", function ($scope) { 
            var someData = {
   firstName: 'awefASEWRGESRgawraswfawERGF',
            }; 
            $scope.data = someData; 
        });
 </script> 
</head>
 <body ng-app="myapp" ng-controller="MyFilterDemoCtrl"> 
<p>
    <!-- Unfiltered data -->
    <strong>First Name</strong>: {{data.firstName}}<br/>
    <strong>Surname:</strong> {{data.surname}} 
</p> 
<p>
    <!-- Filtered data -->
    <strong>First Name</strong>: {{data.firstName | lowercase}}<br/>
    <strong>Surname:</strong>{{data.surname | lowercase }}
</p>  
 </body>
</html>
위 코드를 실행해 보면 "lowercase" 필터가 적용되지 않은 firstName은 데이터 그대로 출력되는 반면 필터가 적용된 데이터는 모두 소문자로 바뀐것을 확인할 수 있다. 물론 이런 처리는 컨트롤러에서 scope에 데이터를 바인딩 하기 전에 처리할 수도 있지만 데이터를 표시하는 코드는 뷰에 두는 것이 좋다는 것을 생각해 보면 필터로 처리하는것이 좀 더 좋아 보인다. Marionette같은 경우는 뷰를 처리하는 스크립트 객체가 따로 존재해서 거기에 화면 표시에 관련된 코드를 작성했지만 Angularjs는 그와같은 객체가 따로 존재하지 않는다.

사용법은 위 코드에서 보듯이 데이터 바인딩 대상 뒤에 파이프와 사용할 필터를 적어주면 된다. 필터 중에는 별도의 인자를 받는것들도 있다. 필터에 인자를 전달하기 위해서는 콜론을 사용한다.
{{ "12345" | currency : "\\" : 3}}
위 코드는 내장 필터인 currency 필터를 적용한 코드이다. 콜론 이후에 추가 인자를 전달하는 것을 확인할 수 있다.
빌드인 필터에 적합한 기능을 가지는 필터가 없으면 직접 만들어 사용할 수 있다. 필터를 만들때는 module객체의 filter 메서드를 사용한다. 아래는 필터 작성 예시 코드이다.
angular.module("myapp", []).filter("removeHyphen", function(){
    return function(txt, arg1, arg2, ...) {
        return txt.replace(/-/g, "");
    }
});
작성한 필터는 문자열에서 하이픈을 모두 제거하는 코드다. filter 메서드의 첫번째 인자는 필터의 이름이고 두번째 함수는 실제 실행될 함수를 리턴하는 함수를 제공해야된다. 이 함수에 의해 반환되는 함수의 인자는 첫번째는 필터 적용의 대상이 될 문자열이고 두번째 부터는 필터에 추가적으로 제공될 인자값이 순서대로 들어온다.

영어 이력서 쓰는데 참고되는 문서들

웹 검색을 하다 영어 이력서 작성에 대한 글을 몇가지 찾게 됐다. 링크를 저장해 두고 나중에 천천히 읽어봐야 겠다.

10초 안에 채용 담당자를 사로잡는 영문 이력서 쓰기
당신의 이력서가 채택되지 않는 이유 – 단어 선정
영문 이력서 작성을 위한 8가지 팁
영어이력서 동사표현의 예

2016년 5월 3일 화요일

Angularjs module, controller

  1. module
    angularjs에서 module은 Marionette에서의 Application과 Module을 합쳐놓은 느낌이다. Marionette의 Application 처럼 페이지당 하나의 module을 할당하는 것이 기본이고 controller나 directive, filter의 집합이 module에 정의되는것은 Marionette의 module 의 특성을 닮았다. 우선 module을 정의하는 코드를 보자
    // module을 정의하고 동시에 생성된 module에 대한 참조를 module 변수에 할당한다.
    var constructingModule = angular.module("myapp", []);
    // 이미 생성된 module을 생성시에 지정한 이름으로 로딩한다.
    var constructedModule = angular.module("myapp");
    
    위 코드에서 보듯이 모듈의 생성과 로딩은 동일하게 angular.module 메서드를 사용한다. 차이점이라면 메서드에 건네는 인자의 갯수인데 모듈 로딩은 정의된 모듈의 이름만 인자로 넘기고 모듈의 생성은 모듈의 이름과 모듈이 필요한 모듈의 목록배열을 넘긴다. 위 예제에서는 모듈에서 추가로 필요한 모듈의 목록을 정의하지 않았다.

    어떤 경우에는 한 페이지에 모듈이 두개 이상 로딩하여 사용할 필요가 있을 수 있다. angularjs는 모듈이 여러개 정의가 되어 있으면 가장 처음 정의된 ng-app 속성의 모듈만 로딩한다. 추가로 정의된 모듈들을 로딩하려면 아래 코드가 추가로 필요하다.
    // 모듈을 두개 생성한다.
    var module = angular.module("myapp", []);
    var module2 = angular.module("myapp2", []);
    // 페이지 로딩이 끝난 시점에서 두개의 모듈을 로딩한다.
    angular.element(document).ready(function() {
      angular.bootstrap(document, ['myapp', 'myapp2']);
    });
    
    angular.element(document).ready 는 $(document).ready와 동일하게 페이지 로딩이 끝난 시점에 호출되는 함수를 지정한다. 위 코드는 페이지 로딩이 끝난 시점에 angular.bootstrap 메서드로 미리 정의된 두개의 모듈을 로딩하는 코드다. 페이지에서 사용해야될 모듈만큼 배열의 갯수는 늘어난다.
  2. controller
    일반 자바객체 또는 Object 클래스를 상속받아 정의하는 Marionette의 컨트롤러와는 달리 angular에서의 컨트롤러는 module에 딸려있는 부속 중 하나이다. module에 딸려있는 부속이기 때문에 정의하는 방법도 별도로 정해져 있는데 그 방법은 아래와 같다.
    var module = angular.module("myapp", []);
    module.controller("MyController", function($scope){
     $scope.clickHandler = function(){
      alert("test");
     }
    });
    // 위 코드는 아래 코드와 동일하다
    angular.module("myapp", []).controller("MyController", function($scope){
     $scope.clickHandler = function(){
      alert("test");
     }
    });
    
    module객체의 controller 함수를 호출해 컨트롤러 이름과 컨트롤러 핸들러를 인자로 넘기면 생성되는 모양이다. 핸들러 함수에서 첫번째 인자로 $scope를 받고있는데 이 $scope는 컨트롤러가 제어하는 영역 내에서 공유하는 변수이다. 이름 그대로 컨트롤러 영역 내의 네임스페이스 정도로 이해하면 될거 같다. 이렇게 정의한 코드는 html에서 사용하는 방법은 아래와 같다.
    ng-controller 속성에 컨트롤러의 이름을 정의하고 있다. 이렇게 정의하면 div 태그 내부는 MyController의 영역이 된다. div 내부의 button 태그에 ng-click속성으로 $scope에 할당한 clickHandler 함수를 호출하고 있다. html 기본 속성과 달리 함수의 호출을 의미하는 괄호까지 붙여줘야 핸들러가 호출이 된다.

Angularjs 시작하기

뭐든 배우는데는 직접 해 보는게 제일이다. 아래 코드를 복사해서 메모장에 붙여넣은 후 "아무이름.html" 파일로 저장하고 브라우저에서 열어보자.
<html ng-app>
 <head>
  <title></title>
  <script src="js/angular.min.js"></script>
 </head>
 <body>
  {{'Hello ' + 'World'}}
 </body>
 </html>
{{'Hello' + 'World'}} 라는 텍스트가 그대로 출력될 것이다. 아직 angular.js 파일이 없어서 제대로 처리되지 않았다. 여기에 가서 angular.min.js 파일을 js폴더 안에 저장한 다음 브라우저를 새로고침 해 보자. "Hello World" 라는 텍스트가 출력되면 제대로 된 것이다. 위 코드에는 일반적인 html 코드에서 볼 수 없는 요소가 두가지 있다.
  1. ng-app
    이 속성은 이 페이지가 Angularjs 어플리케이션이라는 것을 나타낸다. Marionettejs의 Application 클래스와 비슷한 역할이다. 나중에 모듈을 여러게 만들게 되면 이 페이지에 어떤 모듈을 사용할지 ng-app 속성에 값을 지정하여 설정할 수 있다.
  2. {{'Hello ' + 'World'}}
    겹중괄호는 변수값을 출력한다. 백본 뷰의 템플릿과 같은 역할이다. 여기 코드에서는 문자열을 직접 출력했지만 Angularjs의 스코프 변수값이나 기타 변수에 할당된 값들을 출력할 수도 있다.

Angularjs vs Backbone.Marionettejs(Angularjs와 Backbone.Marionette차이점)

Angularjs를 살펴보기 전에 간단하게 기존에 알고 있던Backbone.Marionette와 비교해 보았다. 둘 다 좋은 프레임워크임에는 틀림없으니 요구사항과 선호도에 따라 선택해 사용하는데 이 비교글이 조금이나마 역할을 했으면 좋겠다.

  1. 브라우저 호환성
    브라우저 호환성 문제는 항상 IE가 문제다. 오죽하면 MS조차도 IE 버전업을 포기하고 Edge라는 새 브라우저로 바꿨을까. Angularjs는 IE9까지 지원한다. Beginning Angularjs 에 의하면 (38페이지) IE8에 대한 지원은 드롭될 거 같다고 되어있다. 그래도 스택오버플로에 IE8관련 아티클이 검색이 되고있는것을 보면 자세히 읽어보지는 않았지만 뭔가 해결책이 있는듯 하다. 반면 Marionettejs는 IE8까지 지원하고 일부 아티클을 봤을 때 IE7에서도 동작하는 것 같다. IE8이전의 구버전 브라우저를 지원해야 한다는 요구사항이 있을 때는 Angularjs는 제외하는게 현명한 듯 싶다.
  2. 필요 로딩 파일 수
    Angularjs는 기본 기능만 사용하면 Angular.js 파일 하나만 참조하면 된다. Jquery 등 필요한 기반 코드들은 Angularjs자체에 어지간하면 포함시켰기에 사용할 때 부담이 좀 덜한거 같다. 반면 Backbone.Marionette는 기본적으로 4개의 js 파일을 포함시켜야 한다. 그 목록은 아래와 같다.
    1. Jquery
    2. Underscore
    3. Backbone
    4. Marionette
    이런 차이는 Angularjs가 애초에 단독 프로젝트로 개발되었고 Marionette는 Backbone 확장 프로젝트로 개발되었기 때문이다. 실제 프로젝트를 진행할 때 페이지에 심한 경우 10개 이상의 js파일 참조가 필요했다. 작업 당시 requirejs의 필요성을 정말 실감했었다.
  3. 스타일
    Angularjs는 controller라던가 app 같은 커스텀 속성을 적극적으로 활용한다. Angularjs 개발팀이나 가이드에서는 선언적 프로그램 방법이라고 하는듯 하다. 개인적으로는 프레임워크에서 커스텀 속성을 활용한 무언가를 하는게 좋게보이지는 않는다. 하지만 몇몇 예제를 봤을 때나 약간의 코드를 접해 봤을 때는 확실이 좋은 부분도 있는 것 같았다. angularjs가 선언적이라면 Marionette는 객체지향적이라고 할 수 있을거 같다. Marionette에 선언되어있는 모든 모듈들은 자바나 C#의 클래스에 대응해 볼 수 있고 각 모듈은 extend 메서드로 상속받아 기능을 확장 가능하다. 프레임워크 자체에서 제공하는 유틸성 기능들은 상대적으로 적으나 이를 메꿀 여러 서브 프로젝트들이 있으니 그리 큰 단점은 되지 않는다.
  4. 데이터 바인딩 방법
    Marionette는 프레임워크에서 폼과 모델의 데이터를 바인딩 하지 않는다. Angularjs는 model 디렉티브를 사용하여 바인딩하면 변경된 폼의 데이터를 실시간으로 반영할 수 있다. 이것에 대해서는 검색해 보면 무수한 예제들이 있다.
Backbone.Marionette에 비해 Angularjs가 어떤 기능을 구현할 때 작성해야 하는 코드는 적은것을 느꼈다. 차후 포스트에서 예제와 함께 구체적인 사례를 알아보도록 하자.

2016년 5월 2일 월요일

SPA(Single Page Application)

팀 버너스 리 옹이 웹을 만든 이후 웹 기술은 많은 변화를 거쳐왔다. 내가 처음 웹을 접한것이 중학생 시절이던 1998~9년경 당시 유행하던 불법 게임 및 음악파일 다운로드 사이트들을 통해서였으니 나름 꽤 초기부터 접하고 있었던 것 같다. 당시만 해도 동적 DHTML이 신기술이니 브라우저가 익스플로러보다는 넷스케이프가 좋니 하던 시절이었으니 말이다. 그 시절에 브라우저 전쟁의 산물인 자바스크립트가 지금처럼 퍼지게 될 줄은 상상도 못했다. 당시에 자바스크립트는 브라우저 위에서만 실행되었고 브라우저 성능도 초기버전들이라 좋지 않았다. 그러던 것이 익스플로러 6, 7, 8 버전을 거치고 파이어폭스, 구글 크롬이 등장하면서 현재에 이르고 있다.

자바스크립트의 역사에 있어 가장 중요한 브라우저는 구글 크롬이라고 생각한다. 구글 크롬에 탑재된 V8 엔진은 스크립트 코드의 실행 속도를 혁신적으로 향상시켰다. 크롬 출시 초기 스크립트의 실행 속도를 다른 브라우저들과 비교해 봤을 때 개인적인 느낌으로는 타 브라우저에서는 10초 걸리는 코드가 크롬은 1초 걸리는 정도의 차이를 느낄 정도였으니 말이다. 이 V8 엔진 덕에 현재의 Nodejs 프로젝트도 나오게 되었고 지금 말하려고 하는 SPA도 가능했다라고 한다면 좀 비약일려나...


  1. 기존 방식과 차이점
  2. 기존의 웹 구현 방식은 각 페이지 마다 한번의 요청이 필요했다. HTML 코드는 모두 서버에서 계산되어 브라우제어 텍스트로 전달되며 브라우저는 전달받은 html 텍스트를 토대로 화면을 렌더링하여 보여주면 역할은 끝이었다. 물론 2005년 즈음에 소개된 Ajax기술을 통해 SPA가 아니더라도 한 페이지에서 서버에 여러번의 요청을 할 수 있었지만 말이다. SPA는 방금 언급한 Ajax를 좀 더 적극적으로 사용한다. 기존에는 Ajax를 사용하지 않거나 페이지의 일부를 조작하기 위해서 사용했다면 SPA에 와서는 아예 페이지 전체를 구성하기 위해 자바스크립트와 Ajax를 사용한다. 페이지 요청은 최초 페이지가 로딩될 때 한번 뿐이며 표시해야할 데이터는 물론 데이터를 표시하기 위한 태그, 페이지 이동까지도 자바스크립트로 구현한다.

    이 방식의 장점은 우선 사이트의 전체 트래픽이 감소한다. 기존방식은 페이지 이동시 마다 갱신하지 않아도 되는 부분까지 서버에서 다시 전달받아야 하지만 SPA구현에서는 변경되는 부분에 대한 코드만 받으면 되기 때문이다.

    두번째로 구현과 변경이 편하다. SPA 방식으로 사이트를 구현하게 되면 사이트 구현 코드가 전체적으로 서버쪽 코드와 브라우저쪽 코드로 분리가 되기 때문에 인원이 많으면 각각의 역할을 분리하여 구현하면 된다. 또 자연스럽게 데이터와 뷰가 분리가 되는 효과가 있기 때문에 화면 구성이 변경될 때도 상대적으로 쉽게 대응이 가능하다.

    이런 장점에 반대급부로 단점도 존재한다. 내가 생각하는 단점은 다음과 같다.

    우선 검색엔진에 등록이 되지 않는다. SPA 내의 각 페이지는 스크립트의 실행 결과이지 별도의 독립된 URL이 없기 때문에 검색엔진에 의해 인덱싱이 되더라도 해당 페이지로 바로 접근할 방법이 없다. SPA를 구현한 프레임워크들은 fragment나 route를 통해 각 페이지에 독립적인 url을 제공할 방법이 있다. 하지만 이것은 선택사항일 뿐더러 route를 구현했다 하더라도 검색엔진에서 지원하지 않으면 소용이 없다. 구글은 페이지 내의 스크립트 코드까지 실행시켜 페이지를 인덱싱하는데 국내 검색엔진은 그렇게 하지 않는다고 한다. (불확실한 부분입니다. 자세한 내용을 아시는 분은 알려주세요.)

    둘째로 다국어 구현이 애매하다. 브라우저에서 실행되는 스크립트로 사이트를 구현하기 때문에 일반적인 서버사이드 스크립트들(ASP.net, JSP, php...)에서 제공하는 다국어 변환 기술을 적용하기가 애매하다. 스크립트 단에서 다국어를 따로 구현할 수도 있는데 이렇게 되면 서버쪽 다국어, 스크립트쪽 다국어로 나뉘게 되어 중복해서 관리해야 하는 부담이 있다. 아예 템플릿을 내려줄 때 서버쪽에서 다국어를 적용시켜 전달할 수 도 있을듯 한데 아무래도 귀찮지 싶다.

  3. 구현 프레임워크
  4. SPA를 구현할 수 있게 지원하는 프레임워크들은 많이 나와있다. Knockout이라던가 회사 프로젝트에서 사용했던 Backbone과 Marionette, 한창 대세인 구글의 Angularjs 등등. 그밖에도 일일이 열거하지 힘들 정도로 많은 프레임워크들이 있는것으로 알고 있지만 가장 많이 언급되는건 위에 나열한 정도지 않나 싶다.
  5. 그래서?
  6. SPA는 서버를 데이터 저장소 처럼 사용하는 느낌이 있다. 요 몇년 새 RESTFUL한 API 구현 방식이 소개가 되고 유행을 타면서 서버는 그냥 브라우저에 데이터를 제공하는 Database 같은 역할??? 각설하고 위에 언급한 장단점 외에 더 많은 장단점이 있을거고 항상 어떤 솔루션이나 방법론이 모든 경우에서 정답이 될 수 없다는것은 다들 경험을 통해 알고 있으리라 생각된다. 프로젝트에 SPA를 적용할 지 안할지는 상황에 맞게 요구사항에 맞게 결정해야 할 문제다. 지난 몇년간 프로젝트는 항상 긴급하게 요구사항도 결정나지 않은 채로 일단 시작하고 보는 식으로 진행이 됐었고 예상하겠지만 프로젝트가 끝날 때 까지 일단위 심지어는 시간단위로 요구사항이 변경되었다. 이런 환경에서 일을 진행시키기 위해 의도치는 않았지만 Backbone.Marionette를 사용하기로 결정했던 것은 정말 잘 한 일이었던 것 같다. (하지만 어딜 가든 Angularjs 할줄 아는 사람만 찾는 것은 함정. Backbone.Marionette는 정말 없다. 다른 프레임워크 다 마찬가지겠지만.) 이후 포스트는 Angularjs에 대해 공부한 것에 대해 포스트 할 거 같다. 덤으로 생각이 난다면 Marionette와 의 비교도 곁들여서...

제로센 다큐멘터리