angular

프로그래밍 2015. 4. 14. 23:43

angular는 아주 옛날에 우연히 알게됐다. 그 당시에 자바스크립트 테스트에 엄청 관심이 많았던 때인데 google test blog에서 [공개]된 [jstestdriver]라는 도구를 보고 신선해 하며 좋아했다.[당시 사용기]

그래서 당시 개발자인 [misko]의 블로그를 보며 많은 도움을 받았다. 블로그 내용이 대부분은 테스트에 대한 내용이고 일부분은 흔하지 않은 FE Test에 대한 내용들이라 많은 인사이트를 얻곤 했다.

그러던 중 misko는 angular라는 자바스크립트 라이브러리를 만들었다며 [공개]를 했다. 지금은 해당 동영상이 없지만, 기억을 더듬어서 생각해보면 한 10분(?)만에 자바스크립트 없어 마크업과 속성으로만 자동완성(or TODO List)을 완성하는 동영상이였다. 지금 생각해보면 현재의 [directive]였던 것 같다.

그때 솔직한 느낌은 "이걸 누가 쓰지?"라는 생각을 했다. 

그 이유는 당시의 상황은 IE6을 지원했던 시절이고, mail, calender..와 같이 나름 복잡한 UI들이 들어 있는 서비스를 개발하는 상황에서 단순히 프로그래밍 없이 속성으로 개발을 한다는 건 뭔가 현실을 알지 못하는 개발자가 만든 느낌이였다.

(참고로 예전 만큼은 아니지만, 아직도 angular을 좋아하는 편은 아니다)

한참이 지난 지금 시점에서 보면 angular는 전세계에서 손꼽히는 프레임워크가 됐다. 그래서 한편으론 어느 정도는 "misko가 정말 시대를 앞선 사람이였구나?.."라는 생각을 한다. 

그리고 많은 사람들이 angular을 높게 평가하는 기능이 2 way binding인데 개인적으론 이 기능보다 misko의 백그라운드에서 나온 특징이라고 생각하는데.. DI을 통해 mocking하여 testability을 높여 주는 설계를 할 수 있게 해준걸 높게 평가한다.


이렇게 주저리 주저리 쓰게 된 계기가 지난 주말에 잠깐 angular 2을 보면서 "한번 더 뭔가 변하는구나.."는 생각이 들어 옛날 생각이 나서... 정리하게 됐다. ㅎㅎ


ps. backbone에 대한 추억이 있는데 언제 한번 정리해야겠다.





Posted by 전용우
,

this에 대한 글들이 너무 많아서 굳이 설명하지 않아도 되는데 오늘 글을 읽다가 이상한 내용이 있어서 정리도 할 겸해서 글을 쓴다.

전에 함수형 자바스크립트[링크] 봤는데 최근에 보고 싶은 부분이 있어서 다시 보다가 잘못된 부분을 발견했다. 나의 책을 습관 중에 하나가 안다고 생각하는 부분을 건너 읽는데 이번에 자세히 보다가 발견. -_-;

어쨌든, 59 page에 보면 아래와 같은 글이 있다.

var bFunc = function(){return this};
var b = {name : "b", fun : bFunc};

b.fun(); //=> Window 같은 어떤 객체

"의도치 않은 일이 발생했다. 객체 인스턴스 외부에서 함수를 만들었다면 this는 전역 객체를 가리킨다. 따라서 나중에 bFunc를 b.fun필드로 바인딩해도 this객체는 b자신을 가르키지 않는다."


이건 완전 잘못된 설명이다. 처음에 번역이 잘못됐나하고 원서를 봤는데 역시 잘못되어있다. 그래서 재미있게 읽고 있는데 약간의 실망감이 들었다.


일단 많은 사람들이 this가 저자처럼 만들어 질 때 결정된다고 생각하는데 절대 아니다. this는 호출할 때 결정된다. 그래서 같은 함수는 어떻게 호출하냐에 따라 this가 결정되고 this는 실행환경에서는 변경되지 않는다.

위의 예를 들면, bFunc()을 호출하면 저자가 말한 것 처럼 global이다. node.js는 global, 브라우저는 window다.  근데 b.fun();을 호출하면 b객체를 가르킨다. 그럼 b.fun과 bFunc가 다른가? 똑같다. 즉, 호출하는 방법에 따라 this가 결정된다.


그럼 어떻게 결정될까?


복잡하게 설명하면 복잡한데 기본적으로 호출하는 메서드의 "."앞이 this고 없으면 global이다.

즉, b.fun()은 .앞에 b이기 때문에 this가 b이고, bFunc()는 없기 때문에 global(window)가 된다. 이것만 알아도 this을 이해하는데 대부분은 이해된다.


요약하면,

호출할 때 method의 "."앞부분이 this이고 없으면 global이다. this는 실행될 때 결정되고 실행 환경속에서는 변경할 수 없다.

Posted by 전용우
,

EcmaScript 2015

프로그래밍 2015. 3. 25. 13:42

언제부터 정리해야지 정리해야지 하다가. W3CKIG에서 발표를 하게 되어서 꾸역 꾸역 정리했다. -_-;

사실 이미 많은 사람들이 정리해서 내용은 크게 차이는 없는데 내가 좀 흥미롭게 본 부분은 EcmaScript 2015의 goals 중 하나가 타언어가 변환하는데 EcmaScript로 잘 쓸 수 있도록 지원하는 부분이다.

이걸 보면서 EcmaScript가 플랫폼에 가까운 모습으로 가지 않나라는 생각이 든다.

어쨌든 아래는 정리한 내용.

----

이런 공개한 줄 알았는데 안했네. 

Posted by 전용우
,

내가 느끼기에 FE성능은 크게 로딩 성능과 인터랙션 성능으로 구분되는데 어디에 포인트를 주고 할 것 인가에 따라 과정이나 결과물이 완전 다르다. 그래서 개선작업을 할 때 어떤 부분을 포인트를 주고 할 것 인지 설정한 후 진행하는게 좋다.


기본적으로 포인트의 키워드를 보면 로딩 성능의 핵심은 요청 횟수이고 인터랙션 성능의 핵심은 DOM이다.

자세히 들어가면 다양한 테크닉과 도구의 사용법이 있는데 이는 너무 잘 정리된 아티클이나 책에서 많이 나와있어 굳이 설명하자 않아도 많을 것 같다.


두 성능 중 인터랙션 성능은 비교적 전문 FE개발자가 아니면 쉽게 접근하기 힘든 부분인데 이 부분을 잘 정리한 글이 있어서 공유한다. 이 아티클은 모바일웹의 인터랙션 성능을 튜닝하고 싶다면 반드시 한번쯤 따라해보면 갑자기 고수가 되는 경험을 하게 될 정도로 잘정리되어 있다.



https://docs.google.com/document/d/1K-mKOqiUiSjgZTEscBLjtjd6E67oiK8H2ztOiq5tigk/pub

Posted by 전용우
,

Prototyping

프로그래밍 2015. 3. 18. 01:08

가끔 특정 분야의 경험이 다른 분야에서 재인(recongnition)이 되는 순간들이 종종있다. 그럴 때마다 나름 통찰을 얻게 되는데 이러한 경험을 최근에 한 적이 있어 정리를 하면 좋을 것 같아 정리를 한다.

요즘 사용자 경험 스케치[링크]라는 책을 보고 있는데 여기서는 빠르게 스케치를 하여 괜찮은 스케치들을 프로토타이핑 해보고 사용자 경험을 구체화하는 것이 괜찮은 방법이라고 조언한다.

스케치/프로토타이핑의 장점은 여러가지가 있겠지만, 내가 생각하는 장점은 쉽고 빠르게 만들고, 편히 버릴 수 있는 것이다. 또한 다른 시각에서 보는게 가능하다. 이는 한참 만들고 삽집하는 비용을 줄일 수 있다.

내 경험한 바로는 처음에 스케치나 프로토타이핑의 퀄리티를 보고 웃기기도 하고 효용성에 대해 의심했는데 생각보다 얻는게 있다. 작년에 우연히 Design Thinking 수업을 청강할 일이 있었는데 이 강의에는 프로토타이핑을 role play로 했다. 프로토타이핑이라고 해서 뭔가 만들 줄 알았는데 그게 아니라 내가 만들 도구가 있다고 생각하고 사용하는 상황을 만들어 연기를 하는 것이다. 물론 어색하지만, 시각의 변화를 통해 아무것도 없이 연기만 해도 그 동안 활동을 통해 얻지 못한 아이디어들이 발견되어 신선했다. (나는 대본을 만들고 했는데 대본없이 하는 방법도 좋다고 김창준님이 조언을 줬다. 비록 해보진 않았지만 더 번뜩이는 아이디어가 많을 것 같다.)

이와 같은 느낌을 개발하면서 느꼈다. 공통 기능을 만들어 제공하는 일이 많은데 초반에는 어떻게 만들지 interface 디자인한 후 바로 개발했다. 그러다 보면 만드는 중간이나 만들고 나서 개선하거나 문제가 생기는 상황이 많았다. 그래서 추가한 방법이 interface 디자인을 하고 코드를 사용하는 상황을 만들어 내가 사용자가 되어 코드를 작성하는 것 이다. 이렇게 하면 생각하지 못했던 상황들이 종종 발견되고 리뷰, 조언을 들을 때도 상황이 있기 때문에 좀 더 의미있는 대화가 많아진다. 이때 가끔 동작하는 코드를 만들기도 하지만 동작하지 않아도 도움이 많이 된다. 또한, 이런 코드는 테스트 코드가 되어 도움을 준다.


개인적으로 뭔가를 구체적으로 만들기 전에 위와 같이 가볍게 프로토타입핑을 해보는 것을 다양하게 활용해봐야겠다.





Posted by 전용우
,

요즘 열심히 jQuery사용해보고 있는데 생각했던 것과 다르게 동작하는 것들을 정리하려고 한다.

오늘 발견한거 $.map[링크], map[링크]의 콜백의 인자 순서와 this, 반환 값이 다르다. 

// $.map
$.map(["a","b"],function(v,i){
 // v = value
 // i = index
 this;//window
 return v+"-";
});
// 반환 값 - Array

// map
$(".some").map(function(i,v){
 // i = index
 // v = value
 this;// v
 return v+"-";
});

// 반환 값 - jQuery // native map ["a","b"].map(function(v,i){ // v = value // i = index this;// window return v+"-"; }); // 반환 값 - Array

jQuery에서는  $.map은 native[링크]처럼 map은 좀 다르게 만들었다. 근데 $.map보다는 map이 native와 비슷한 구조라 헷갈린다.

아마도 map이 만들어지고 나서 $.map을 만들어진것 같다. 이후에 map이 native로 추가된 후 map의 사용법을 가져갈까? 표준 api의 사용법을 가져갈까? 고민하다 $.xx의 함수들은 표준 방법을 선택한 듯.

이런건 라이브러리를 만들면서 항상 고민되는 부분이다. 가장 깔끔한건 모두 표준과 같은 방법으로 맞추는건데 이게 쉬운 일인가? -_-;

map이면 굉장히 많이 쓰는 메서드인데 기존의 파라메터의 순서를 바꾸면 헬게이트 열림.

결국엔 기본 map은 수정할 수 없고, $.map을 map과 똑같이 하는 방법, native처럼 하는 방법 두 가지인데 사실 나였으면 지금의 jQuery방식보다는 $.map을 map처럼 바꿀 것 같다. 혹은 $.map을 지원하지 않거나.

지금의 방식은 모든 사람이 혼란스럽지만, $.map과 map의 사용법이 같다면, native에 map이 있는지 모르고 jQuery만 사용하는 사람한데는 혼란스럽지않다.

사실 그보다는 아예 $.map을 지원하지 않는 방법을 선호한다.





Posted by 전용우
,

express을 사용할 때 보통은 장난감을 만들어서 express generator[링크]을 사용하지 않고 대충 app.js에 몰아서 했는데 이번엔 좀 크기가 있는 어플리케이션을 만들 필요가 있어 폴더 구조도 정할 겸 express generator을 사용했다.


근데 난 nodemon을 사용하는데 기본 스크립트가 nodemon을 안쓰네. 아직 익숙하지 않아서 그런지 처음에 www 스크립트에 node -> nodemon으로 바꾸고 스크립트를 실행시켰는데 알고보니[링크] 당연하게도 package.json scripts의 start를 nodemon으로 바꾸면 된다.



Posted by 전용우
,

가끔 알려주면 사람들이 놀라는 팁.

JSON.stringfy는 JSON을 문자로 바꿔주는 메서드인지 다 안다. 보통 아래와 같이 사용

JSON.stringify({"a":1,"b":2});
//{"a":1,"b":2}

근데 위와 같이 작은 객체를 보기 쉬운데 크기가 커지면 커질수록 보기 어렵다.

그래서 stringify는 세 번째 인자로 숫자등을 넣어 공백이 삽입되 읽기 쉽게 할 수 있다.

숫자를 넣으면 들여쓰기, 공백, 줄 바꿈일 때 공백이 숫자만큼 들어가고 문자가 들어가면 문자가 들어간다.

예를 들면, 아래와 같이 세 번째 인자로 2을 넣으면 공백이 두개 들어간다.

JSON.stringify({"a":1,"b":2},null,2);
/*
{
  "a": 1,
  "b": 2
}
*/

두 번째 인자는 함수인데 반환 값으로 특정 값을 제외하고 싶을 때 사용한다. 반환 값이 undefined면 안 나옴.

자세한건 [URL참고]


[깨알팁 시리즈]

Posted by 전용우
,

그냥 검색하는게 짱인듯.


https://www.computersnyou.com/3376/setup-apache-php-mysql-macosx-10-10-yosemite/

http://stackoverflow.com/questions/25250566/apache-localhost-403-error-with-yosemite

Posted by 전용우
,

Views 와 Widgets사이에 커플링을 막고자 사용함.
뷰의 상하의 간에 메시지를 주고 받고 해야 한다.
일반적인 옵저버 패턴.


Broadcasting and Listening

eventHandlerA.on('A', function(data){ alert(data.msg); });  // alerts 'ALERT!' 

eventHandlerA.emit('A', message);//trigger

emit나 trigger나 같지만, emit는 밖에서 호출할 때, trigger는 안에서 호출할 때.


Piping
이벤트를 아래로 흐르게 해준다.(like 캡처링)

eventHandlerA.pipe(eventHandlerB).pipe(eventHandlerC);
eventHandlerC.on('A', function(data){alert(data.msg)});  // alerts 'ALERT!'
eventHandlerA.emit('A', message);


Subscribing

이벤트를 위로 올려준다.(like 버블링)

eventHandlerC.subscribe(eventHandlerB);
eventHandlerB.subscribe(eventHandlerA);
eventHandlerC.on('A', function(data){alert(data.msg)});  // alerts 'ALERT!'
eventHandlerA.emit('A', message);


Filtering

이벤트를 중간에 필터링 해줌.

var myFilter = new EventFilter(function(type, data) {
    return data && (data.msg === 'ALERT!'); //true or false
});

eventHandlerA.pipe(myFilter).pipe(eventHandlerB);
eventHandlerB.on('A', function(data){
    alert('piped message: ' + data.msg);
});



Mapping 

라우팅하듯이 특정 eventHandler에 이벤트를 전달한다.(개인적으론 불필요하다고 생각)

var myMapper = new EventMapper(function(type, data) { return (data && (data.direction === 'x')) ? eventHandlerB : eventHandlerC; });

eventHandlerA.pipe(myMapper); eventHandlerB.on('A', function(data){ alert('B direction : ' + data.direction); }); eventHandlerC.on('A', function(data){ alert('C direction : ' + data.direction); }); eventHandlerA.trigger('A', {direction : 'x'}); // pipes to eventHandlerB eventHandlerA.trigger('A', {direction : 'y'}); // pipes to eventHandlerC

pipe만 가능하다.(당연한다 subscribe가 되려면 mapping에서 이벤트를 받아야 함)


Arbitration

Mapping하고 비슷한 느낌인데 mode별로 이벤트를 등록할 수 있다.
한번에 하나의 모드만 가능하고 setMode로 하면 해당 모드만 동작.
이것도 왜 있어야 하는지 모르겠다.


var eventArbiter = new EventArbiter();

eventArbiter.forMode('routeA').on('A', function(data){
    alert('subscribed message: ' + data.msg);
});
eventArbiter.forMode('routeB').on('B', function(data){
    alert('subscribed message: ' + data.msg);
});

eventArbiter.setMode('routeA');

eventArbiter.forMode('routeA').emit('A', message); // alerts 'ALERT!'
eventArbiter.forMode('routeB').emit('B', message); // does nothing. Mode is not set.

eventArbiter.setMode('routeB');

eventArbiter.forMode('routeA').emit('A', message); // does nothing. Mode is not set.
eventArbiter.forMode('routeB').emit('B', message); // alerts 'ALERT!'


Event Handling Inside a Widget

자체적으로 몇가지 룰이 있다.

External to a Widget:

widget.trigger : the interface to talk to a widget

widget.on : the interface to listen to a widget

widget.pipe : the interface to pipe from a widget

widget.subscribe : the interface to subscribe from a widget


Internal to a Widget:

receive events via widget.eventInput

broadcast events via widget.eventOutput

widget.emit는 없음.


//아래와 같이 인풋 핸들러를 등록.

EventHandler.setInputHandler(widget, eventHandlerA);
eventHandlerA.on('B', function(data){alert(data.msg)});
widget.trigger('B', message);


Listening

setInputHandler으로 등록한 놈이 받음

// Child widget
function Child(){
    // setup input and output handlers
    this.eventOutput = new EventHandler();
    this.eventInput = new EventHandler();
    EventHandler.setInputHandler(this, this.eventInput);
    EventHandler.setOutputHandler(this, this.eventOutput);

    this.eventInput.on('hires tutor', function(){
        alert('Accepted to Harvard');
    }.bind(this));
}



// Parent widget
function Parent(){
    // setup input and output handlers
    this.eventOutput = new EventHandler();
    this.eventInput = new EventHandler();
    EventHandler.setInputHandler(this, this.eventInput);
    EventHandler.setOutputHandler(this, this.eventOutput);

    this.child = new Child();
    this.eventInput.on('bad report card', function(){
        this.child.trigger('hires tutor');
    }.bind(this));
}

var parent = new Parent();
parent.trigger('bad report card');


Broadcasting

setOutputHandler으로 등록한 얘가 전달.

EventHandler.setInputHandler(widget, eventHandlerA);
eventHandlerA.on('B', function(data){alert(data.msg)});
widget.trigger('B', message);



보면서 느낀건 전체적으로 과한 느낌이 있다.

너무 많다. 이런 경우 나중에 이벤트로만 넣으면 데이터가 흘러갈 때 문제가 있을 것 같다.
특히 mapping은 불필요. 데이터가 deep copy되지 않기 때문에 중간에 값을 바꾸면 디버깅의 거의 불가능하고 경험상 이벤트 종류는 너무 할 정도로 간단하게 가야 한다. 복잡하게 되면 나중에 엄청 고생함.

Posted by 전용우
,