개발하다보면 내 환경은 잘되는데 성능이 느린 환경은 어떨까 궁금할 때가 있다. 그럴 때 사용하는  대표적인 도구 [WebPageTest] 가 있다.


다만, WebPageTest는 초기 로딩 성능을 주로 하고, 테스트 하는데 시간도 오래 걸리기 때문에 자주 실행해보는건 적당하지 않다. 가끔 확인이나 할 뿐. (물론 도구와 연결해서 주기적으로 할 수 있지만 바로 바로 확인해보고 싶은 경우가 많아서..)


근데 얼마 전에 크롬에서 Network throttling이란 기능이 생겼다. Network 탭에 가면 아래와 같이 Network을 조절할 수 있는 기능이 추가됐다.



거의 WebPageTest와 다르지 않게 많이 쓸 것 같은 대역폭과 레이턴시들이 존재하고 직접 상황에 맞는 설정을 추가할 수 있다.



물론 실제 환경이 아니지만 거의 비슷한 느낌을 받기 때문에 빠르게 네크워크가 안좋은 환경에서는 어떨까 확인하고 싶다면 확인해보는 것도 괜찮을 것 같다. 그리고 후진 폰에서는 인터랙션이 어떻게 동작할까? 이런 생각을 할 수 있는데 이걸 후진폰에서 직접 확인하는 방법이 좋긴 하지만, 귀찮기도 하고 빠르게 확인하기란 적절하지 않다.



이것도 최근에 크롬에서 CPU throttling이란 기능이 추가됐다. 현재는 바로 쓸 수 있는건 아니고  Setting > Experiments 에 가서 아래와 같이 활성화을 해야 한다.



그리고 타임라인 탭에 가면 Network와 같이 CPU로 throttling 할 수 있다.



직접 기기에서 보는 것과 다르긴 하지만, 써보니깐 편하게 느린 기기를 체험할 수 있다. 물론, 실제 기기랑 느린거랑은 좀 다르다.


실제 환경에서 확인하는게 더 정확하긴 하다. 하지만, 빠르게 확인하는 방법으로 이 두 기능은 꽤 괜찮은 방법이다.






Posted by 전용우
,

크롬 개발자 도구에서 스크립트 디버깅을 하다보면 breakpoint 사용이 가끔 불편할 때가 있다. 대표적으로 breakpoint에서 멈출때 특정 위치로 점프하고 싶다면, 원하는 위치에 breakpoint을 설정하고 next을 눌러 이동하는 경우이다.


이게 생각보다 불편한다. 대부분 임시로 breakpoint을 설정한 경우라 그대로 두면 엄청 많아져서 관리도 안되기 때문에 나중에 원하지 않아도 계속 걸려 귀찮다. 그래서 다시 해제해야 하는데 이것도 귀찮다.


이 때, 사용하는 기능이 아래 링크에서 설명하는   "continue to here" 다. 이 기능을 사용하면 breakpoint을 설정하지 않고 원하는 위치로 이동하기 때문에 breakpoint가 많아지지 않고 다시 해제할 필요가 없다.


https://twitter.com/kaycebasques/status/755817600249044992




만약, 이 기능을 사용해보지 않았다면, 한번쯤 사용해보면 좋은 기능임을 알게될 것이다. 



[깨알팁 시리즈]

Posted by 전용우
,

한 2년 전인가 구글 개발자들이 회사에 온 적이 있는데 당시에 내가 했던 질문이 "DOM/Event Listener Breakpoint는 유용한 기능인데 항상 라이브러리에서 멈추기 때문에 활용도가 떨어지는데 개선할 계획이 있냐?" 였다.

그 때 paul irish가 "아. 그거 조만간 나올 예정이다"라고 했다.

그리고 나서 작년 겨울인가 디버깅하다가 갑자기 생각나서 그 기능 개발되었나 하고 찾아보니 적용이 되어 있어서 사용하고 있는데 생각보다 사람들이 이 기능을 몰라서 잠깐 설명할까 한다.


예를 들어, 어느날 서비스를 담당하는 개발자가 휴가를 갔다. 근데 버그가 발견되어서 내가 대신 처리해야 하는 상황이다.

버그는 특정 버튼을 누를 때 레이아웃이 이상하게 된다고 가정하자.

이런 상황에서 일반적으로 내가 해당 코드를 모르기 때문에 js을 바로 찾진 못하고 버튼 엘리먼트의 아이디, 클래스, 이벤트명등의 단서를 가지고 js파일을 찾는다. 그리고 거기에 debugger을 걸면서 해당 이벤트가 발생하는 시점을 확인하면서 디버깅을 한다.

만약에 click이 발생하는 시점에 호출되는 함수를 알 수 있다면 아마 좀 더 쉽게 디버깅을 할 수 있을 것이다.

이게 바로 source tab에 있는 Event Listener Breakpoints다.


위와 같이 click은 선택하면 click이벤트가 발생했을때 해당 함수에 break point가 걸린다.

근데 문제는 대부분이 라이브러리를 사용하기 때문에 아래와 같이 라이브러리 코드에서 멈춘다.



그러면 다음 다음을 누르면서 해당 함수를 찾아가야 하니 생각보다 편하지 않다.

이때, 사용하는게 "Blackbox JavaScript Source Files"다.

크롬 개발자 도구에서 "설정 -> General -> Sources"에 가면 아래와 같이 "Manage framework blackboxing..."을 눌러 라이브러리를 등록한다.



그리고 나서 다시 실행하면 아까와는 다르게 아래와 같이 내가 작성한 코드에서 break point가 걸린다.


이제 부터 "Event Listener Breakpoints"는 너무 편해진다.

그리고 디버깅할 때 등록한 라이브러리 코드는 디버깅 대상에서 제외된다. 이것도 완전 편하다. 항상 다음 함수로 넘어가기를 누르면 라이브러리 코드로 가서 들어갔다 나왔다를 반복해야 하는데 이런 문제도 없다. 

이 기능은 정말 디버깅할 때 강추한다.

내가 사용해보니 좀 노하우가 생겼는데 그 중 하나가 라이브러리 코드 뿐 아니라 의존성을 가지는 파일 중에 보지 않아도 되는 파일이 있다면 해당 파일을 등록하면 좀 더 디버깅이 간단해진다.


ps. 참. 아쉽게도 DOM break point은 black box을 사용할 수 없다.

[깨알팁 시리즈]

Posted by 전용우
,

[저번]에 이어 이번에는 크롬개발자 깨알팁 

가끔 아래와 같이 찍힌 로그를 복사하고 싶을 때가 있다.


이럴 때 보통 그냥 drag해서 선택한 다음에 ctrl + c , ctrl + v로 하는데 이러면 나중에 정리해야 하고 불편하다. 그 때는 copy라는 메서드를 쓰면 객체가 클립보드에 저장된다.

copy(obj);

근데 문제는 변수에 담기지 않은 상태 즉, 위에 처럼 이미 로깅된 객체를 어떻게 copy메서드를 쓴단 말인가? -_-;

이 때. 알고 있으면 도움되는 깨알팁.

내가 저장하고 싶은 객체에 오른쪽 마우스를 클릭하면 아래(Store as Global Variable)처럼 나옴.

이를 선택하면 global영역에 임시 변수로 저장된다.


그리고 나서 copy(temp1); 하면 됨.


[깨알팁 시리즈]


Posted by 전용우
,

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


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

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


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



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

Posted by 전용우
,

몇 년 전이더라...

사내에서 한참 교육을 할 때 테크니컬 라이팅 교육을 수강한 적이 있다.

그 때 하나의 주제로 글을 쓰는거였는데 마침 디버깅 관련한 문서가 없어서 디버깅을 주제로 글을 썼다. 그리고 나서 테스트을 추가로 써서 책으로 만들면 어떨까하고 알아봤는데 마침 인사이트 사장님이 좋게 봐주셔서 쓰기 시작했다.

이게 2011년 1월이다. -_-;

모두 그렇겠지만 처음에 한 6개월 생각했다. 근데 쓸 당시에 총각이였는데 지금은 2살배기 아이의 아빠가 됐다... 정말 틈틈히 쓰다보니 거의 3년이 지난 시점에 책이 나왔다.

쓰고 나서도 너무 아쉬움이 많이 남는다.

IE11이 나온 시점에 이 책에서는 IE9이 마지막이라 좀 아쉽고 크롬도 좀 더 다양한 기능들이 추가됐다.

이렇게 타이밍이나 지면상 다루지 못했던 다양한 얘기는 여기를 통해서 다룰 예정이다.

어쨌든 속 시원하네.



확대찜하기

[예약판매]자바스크립트 테스트와 디버깅

가격
22,500원
판매몰
gmarket
카테고리
-
구매하기


Posted by 전용우
,

크롬 카나리 버전을 보니 메모리 힙을 리코딩하는 기능이 나왔다.

기존에는 메모리 프로파일은 스냅샵을 찍는거라 찍는 순간에 메모리의 상황이나 스냅샷끼리의 변화 밖에 알 수 없었다. 하지만 크롬 카나리 버전에는 메모리 힙을 리코딩 하는 기능이 추가되어 메모리 힙의 상황을 시간에 흐름에 따라 확인 할 수 있어 프로파일링 하는데 좋아졌다.


사용방법은 간단하다.

프로파일탭(profiles)에서 힙 사용량 기록하기(Record Heap Allocations)을 아래와 같이 선택하고 누른다.




그리고 적절한 시점에 기록하기를 멈추면 아래와 같이 결과를 확인할 수 있다.




결과에서 파란바는 메모리 힙에 할당된 그래프이며 회색은 해제된 그래프이다.

파란바를 확인하여 증가된 메모리를 찾아 개선할 수 없는지 확인하면 된다.

(속성에 대한 자세한 내용은 구글 개발자 도구 문서[링크]에서 확인하면 된다.)



sorce. http://slid.es/gruizdevilla/memory


ps.아마도 향후에는 타임라인쪽과 연동이 되지 않을까 생각한다.

Posted by 전용우
,

가끔씩 아래와 같이 polyfill형식으로 사용하는 경우가 있다.

(function(){
    var raf = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame|| window.msRequestAnimationFrame;
    var caf = window.cancelAnimationFrame || window.webkitCancelAnimationFrame|| window.mozCancelAnimationFrame|| window.msCancelAnimationFrame;

    if(raf&&!caf){
        var keyInfo = {};
        var oldraf = raf;
        raf = function(callback){
        function wrapCallback(){
            if(keyInfo[key]){
            callback();
            }
        }
        var key = oldraf(wrapCallback);
        keyInfo[key] = true;
        return key;
        }
        caf = function(key){
        delete keyInfo[key];
        }
        
    }else if(!(raf&&caf)){
        raf = function(callback) { return setTimeout(callback, 16); };
        caf = clearTimeout;
    }

    window.requestAnimationFrame = raf;
    window.cancelAnimationFrame = caf;
})();

이렇게 바로 실행해버리는 코드는 테스트할때 상황을 만들어야 하는데 상황을 제어하기가 어렵기 때문에 테스트가 어렵다.

예를들어, 난 아래와 같은 테스트케이스를 작성하려고 한다.


  1. requestAnimationFrame만 있는 경우
    1. cancelAnimationFrame을 호출했을 때 cancelAnimationFrame으로 정상적으로 멈추는지 테스트
  2. cancelAnimationFrame만 있는 경우
  3. requestAnimationFrame, cancelAnimationFrame 둘다 있는 경우
  4. requestAnimationFrame, cancelAnimationFrame 둘다 없는 경우
    1. cancelAnimationFrame을 호출했을 때 cancelAnimationFrame으로 정상적으로 멈추는지 테스트


(하위 목록(1-1. 4-1)에 대한 내용을 빼고 상위 목록만 얘기하자. 하위 목록에 대한 테스트를 얘기하면 길어지기 때문에 다음 기회에.)

근데 1,2,3,4의 상황이 브라우저마다 달라서 해당 로직이 정상적으로 실행되는지 테스트하려면 상황에 맞는 브라우저에서 테스트해야한다.


얼마나 귀찮고 복잡한 일인가?


어떻게 할까 고민하다가..

생각난 방법은 브라우저가 아니라 내가 직접 상황을 만들 수 있으면 가능하지 않을까 생각했다.(사실 이게 핵심인 것 같다. testability을 높이려면 개발자가 제어할 수 있는 환경(디자인..)을 만드는게 가장 중요한것 같다.)

그래서 생각한 방법은 바로 실행하는 것이 아니라 실행시점을 제어할것.

처음에는 아래와 같이 함수를 만들어서 처리했다.


function polyfillRequestAnimationFrame(){
    var raf = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame|| window.msRequestAnimationFrame;
    var caf = window.cancelAnimationFrame || window.webkitCancelAnimationFrame|| window.mozCancelAnimationFrame|| window.msCancelAnimationFrame;

    if(raf&&!caf){
        var keyInfo = {};
        var oldraf = raf;
        raf = function(callback){
        function wrapCallback(){
            if(keyInfo[key]){
            callback();
            }
        }
        var key = oldraf(wrapCallback);
        keyInfo[key] = true;
        return key;
        }
        caf = function(key){
        delete keyInfo[key];
        }
        
    }else if(!(raf&&caf)){
        raf = function(callback) { return setTimeout(callback, 16); };
        caf = clearTimeout;
    }

    window.requestAnimationFrame = raf;
    window.cancelAnimationFrame = caf;
}


추가로 window가 전역 객체라서 제어하게 되면 다른 곳에 영향을 줄지 몰라 아래와 같이 인자로 받아서 처리했다.(이 방법은 브라우저뿐만이 아니라 node.js와 같은 환경에서 테스트하기에 좋았다.)

function polyfillRequestAnimationFrame(global){
    var raf = global.requestAnimationFrame || global.webkitRequestAnimationFrame || global.mozRequestAnimationFrame|| global.msRequestAnimationFrame;
    var caf = global.cancelAnimationFrame || global.webkitCancelAnimationFrame|| global.mozCancelAnimationFrame|| global.msCancelAnimationFrame;

    if(raf&&!caf){
        var keyInfo = {};
        var oldraf = raf;
        raf = function(callback){
        function wrapCallback(){
            if(keyInfo[key]){
            callback();
            }
        }
        var key = oldraf(wrapCallback);
        keyInfo[key] = true;
        return key;
        }
        caf = function(key){
        delete keyInfo[key];
        }
        
    }else if(!(raf&&caf)){
        raf = function(callback) { return global.setTimeout(callback, 16); };
        caf = global.clearTimeout;
    }

    global.requestAnimationFrame = raf;
    global.cancelAnimationFrame = caf;
}


이렇게 만든후 난 아래와 같이 테스트케이스를 만들었다.


test("requestAnimationFrame만 있는 경우",function(){
    //Given
    var global = {
        "requestAnimationFrame":function(){}
    };

    var oldRequestAnimationFrame = global.requestAnimationFrame;
    
    //Then
    polyfillRequestAnimationFrame(global);

    //When
    notEqual(global.requestAnimationFrame,oldRequestAnimationFrame);
    equal(typeof global.cancelAnimationFrame,"function");

});

이후부터는 내가 직접 global에 적절한 상황을 만들어서 테스트할 수 있기 때문에 쉽게 테스트케이스를 작성할 수 있었다.

생각해보면 정말 단순하고 간단한 문제인데 처음에 고민을 많이 했다. -_-;


ps. 아쉬운건 requestAnimationFrame, cancelAnimationFrame이 둘다 없는 경운데 이땐 전에 쓴글(링크)처럼 clearTimeout이 정상적으로 변경되었다면 정상적이라고 판단했다.

Posted by 전용우
,

기존 자바스크립트 프로파일링은 어떤 함수가 얼마나 오래 걸렸는지 프로파일링 하기 때문에 소비 시간을 기준으로 느린 함수와 빠른 함수를 확인할 수 있었다.

하지만, 어떤 시점에 어떤 함수가 실행되고 얼마나 느린지 확인할 수 없었다.

예를 들어, 프로파일링을 실행하고 이벤트들을 수행한 다음 프로파일링을 끝내면 기존에는 프로파일링은 어떤 함수가 느린지 확인할 수 있었다면, 이벤트가 발생한 시점에 어떤 함수가 빠르고 느린지 확인할 수 없었다.

이 부분을 최근 크롬 개발자도구에서 프레임차트(Frame Chart)의 기능을 이용하여 시간의 흐름에 따라 함수의 실행시간을 확인할 수 있다.

즉, 특정 시점에 어떤 함수가 느린지 확인하고 싶을때 프레임 차트를 사용하면 유용하다.


프레임차트의 사용법은 기존과 같이 JavaScript CPU 프로파일 수집하기(Collect JavaScript CPU Profile)을 실행한 후 결과화면에서 아래와 같이 프레임차트(Frame chart)을 선택하면 된다.





아래와 같은 화면을 볼 수 있다.





여기서 확인할 수 있는 데이터는 5가지이다.


이름(Name) : 함수의 이름

실행 시간(Self time) : 호출된 함수를 제외하고 자신이 실행한 시간

전체 시간(Total time) : 함수가 실행된 전체 시간

실행 시간 합계(Aggregated self time) : 함수의 실행 시간(Self time)의 합

전체 시간 합계(Aggregated self time) : 함수의 전체 시간(Total time)의 합


이 5가지 데이터를 가지고 개선작업을 하면 된다.


ps. 크롬 개발자 도구는 정말 좋다.

Posted by 전용우
,

파일 열기

크롬 개발자 도구를 열고(윈도우 F12, 맥킨토시 command + shift + i) Resource탭으로 이동후 ctrl + o을 누르면 원하는 파일을 열 수 있음. 



함수 찾기

열린 파일에서 ctrl + shift + o을 누르면 원하는 함수를 찾을 수 있음,



맥킨토시는 ctrl대신 command로 변경하면 됨.

source. https://vine.co/v/hzIpZLY5TpU

Posted by 전용우
,