샤브의 블로그 RSS 태그 관리 글쓰기 방명록
최적화 (1)
2013-10-17 17:07:29

출처 : http://www.xpressengine.com/tip/22330022


1. HTTP 요청 최소화
tag: content
End-user 응답시간의 80%는 초기 로딩부분에서 소요된다. 그 중 대부분의 시간은 모든 페이지 구성요소(이미지, 스타일시트, 스크립트, 플래시 등)의 다운로딩에 소요된다. 차례로 구성요소의 수를 줄이면 페이지를 구성하는데 필요한 HTTP 요청 수를 줄일 수 있다. 이것이 페이지의 속도를 빠르게 만드는 핵심요소이다.
페이지의 구성요소를 줄이기 위한 한 가지 방법은 페이지의 디자인을 단순화하는 것이다. 여기에 빠른 응답시간을 유지하면서 풍부한 구성요소가 포함된 페이지를 구축할 몇 가지 방법이 있다.

- Combined files(파일결합)은 HTTP 요청 수를 줄이기 위한 하나의 방법이다. (ex. 모든 scripts를 하나의 script로 결합시키고 모든 CSS를 하나의 stylesheet로 결합하는 것) 

- Scripts와 stylesheets가 모든 페이지에 걸쳐 다양하게 있다면 파일결합은 더욱 어려운 작업이 되겠지만 해당 부분을 수정한다면 분명 응답시간을 향상시켜줄 것이다.

- CSS Sprites는 이미지 요청 수를 줄이기 위해 선호되는 방법이다. 배경 이미지들을 하나의 이미지로 결합하고 이미지를 표현하는 속성인 CSS background-image 또는 background-position을 사용하는 것이다. 

- Image maps는 여러 개의 이미지를 하나의 이미지로 결합시키는 방법이다. 전체 크기는 동일하지만, HTTP 요청 수를 줄이는 것은 페이지의 속도를 향상시켜주기 때문이다. Image maps는 메뉴바(navigation bar)와 같이 페이지에서 이미지들이 인접할 때에만 효과적이다. 하지만 Image maps의 좌표처리방법은 표현법이 지루하고 오류가 발생하기 쉽다. 또한 메뉴바에 대한 Image maps사용은 접근성이 떨어지므로 그렇게 권장하지는 않는다.

- Inline images는 실제 페이지에서 이미지 데이터를 포함시키기 위한 데이터(URL 체계)를 사용하는 방법이다. 이것은 HTML 문서의 크기를 증가시킬 수 있다. Inline image들을 stylesheets(cached)에 결합하는 것은 HTTP 요청을 줄이고 페이지 크기의 증가를 피할 수 있는 하나의 방법이다. 현재 Inline image들은 모든 주요 browsers에서 지원되지 않는다.

위에 열거한 방법이 페이지의 HTTP 요청 수를 줄이는 것은 가장 기본적인 단계이다. 이것은 첫 방문자에게 성능개선을 제공하기 위한 가장 중요한 지침이다. Tenni Theurer의 블로그에 포스팅된 ‘Browser Cache Usage-Exposed!’(브라우저 캐시 사용)과 마찬가지로, 40-60%의 일일 사이트 방문자들은 비어있는 cache의 상태로 사이트를 방문한다. 이렇게 첫 방문자를 위해 페이지의 속도를 빠르게 만드는 것은 더 나은 사용자 경험(UX)을 제공하기 위한 핵심요소이다.
2. CDN(Content Delivery Network)의 사용
 
tag: server
웹서버에 대한 사용자의 접근성은 응답시간이 가장 중요하다. 지리적으로 분산된 서버에 contents를 배포하면 사용자의 관점에서 빠르게 페이지를 읽어올 수 있을 것이다.

- 지리적으로 분산된 서버에 content를 구현하기 위한 첫 번째 단계는 분산 아키텍처에서 작동시키기 위해 웹 응용프로그램을 재설계하면 안 된다. 응용프로그램에 따라 아키텍처를 변경하면 서버위치를 통해 실시간 동기화되는 세션상태와 database transactions을 복제하는 힘든 작업도 포함시킬 수 있다. 사용자와 content 사이의 거리를 줄이기 위한 시도는 이 단계에서 작업지연 및 실패로 이어질 수 있다.

- 사용자 응답시간의 80-90%는 페이지의 모든 구성요소(images, syltesheets, scripts, Flash 등)를 다운로딩 하는데 소요된다. 이것은 모든 작업에 있어 황금률이다. 응용프로그램 아키텍처를 재설계하는 어려운 작업보다 정적 content를 분산시키는 것이 더 효과적이다. 이것이 응답시간을 크게 감소시키고 CDN(content delivery networks)의 구성을 더 쉽게 만들기 때문이다.

- CDN은 사용자에게 보다 효율적으로 content를 제공하기 위해 여러 지역에 걸쳐 분산된 웹서버의 집합체이다. 특정 사용자에게 content를 전달하기 위해 일반적으로 고객의 네트워크에서 가장 가까운 서버를 측정하여 선택된다. 예를 들어,고객이 요청 시에 가장 적은 네트워크 홉(network hops)과 가장 빠른 응답시간의 서버가 선택된다.

일부 대형 인터넷 업체들은 자체 CDN 서비스를 소유하지만, CDN 서비스를 전문적으로 제공하는 업체를 이용하는 것은 비용 면에서 효과적이다. 벤처기업이나 개인 웹사이트의 경우, CDN 서비스 비용은 매우 비싸지만 타겟 고객이 점점 더 커지고 글로벌화 되어감에 따라 CDN 서비스는 빠른 응답시간을 제공하기 위해 반드시 필요한 부분이다. CDN으로의 전환은 웹사이트의 속도를 급격히 향상시킬 수 있는 비교적 쉬운 방법이라고 할 수 있다.
3. Expires 혹은 Cache-Control Header의 추가
 
tag: server
이 규칙에는 두 가지 관점이 존재한다.
- 정적 components: Expires header의 미래 설정 시점까지의 “Never expire” 정책 수행
- 동적 components: 조건적 요청의 브라우저를 수행하기 위한 적절한 Cache-Control header의 사용
페이지에서 더 많은 scripts, stylesheets, images, Flash를 사용하는 것은 웹페이지 디자인을 더욱 더 풍부하게 만들 것이다. 페이지를 처음 방문하는 사람이 얼마나 많은 HTTP 요청들을 수행해야 할지 모르지만 Expires header를 사용함에 따라 임시저장 가능한 구성요소(components cacheable)를 만들 수 있다. 이것은 이후 페이지뷰에 대한 불필요한 HTTP 요청을 방지한다. Expires headers는 대부분 이미지와 함께 사용하지만, scripts, stylesheets, Flash 등의 모든 components에 사용되어야 한다.
Browsers는 웹 페이지 로딩속도를 빠르게 하고 HTTP 요청 수 및 크기를 줄이기 위해 cache를 사용한다. 웹서버는 고객에게 component를 얼마나 오래 cache에 담아둘 것인지를 알려주기 위해 HTTP 응답에 Expires header를 사용한다. 다음은 이 응답이 2010년 4월 15일까지 유효한 browser를 알리는 미래 시점의 Expires header이다.
Expires: Thu, 15 Apr 2010 20:00:00 GMT
만약 서버가 Apache라면, 현재 날짜를 기준으로 만료일을 설정하는 ExpiresDefault 지시어를 사용하여라. 다음 예제는 요청시간으로부터 10년을 만료일로 설정해준다.
ExpiresDefault “access plus 1 years”
미래시점의 Expires header를 사용하면 사용자가 이미 사이트를 방문한 후에만 페이지뷰에 영향을 끼친다. 사용자가 처음 사이트를 방문하여 browser의 cache가 비어있는 경우에는 HTTP 요청개수에 영향을 주지 않는다. 따라서 이 성능향상은 사용자가 얼마나 자주 준비된 cache(클라이언트 캐쉬)를 가지고 페이지를 열람하는가에 따라 달라진다. 미래시점의 Expires header를 사용함으로써, 사용자의 인터넷 접속을 통한 단일바이트의 전송 없이 browser에 의해 cache되며 이후 페이지방문 시 재사용된 components 수를 증가시킬 수 있다.
4. Gzip Components (Gzip 구성요소들)
 
tag: server
네트워크를 통해 HTTP 요청과 응답을 전송하는데 걸리는 시간은 초반 로딩을 설계하는 엔지니어의 결정에 의해 크게 줄일 수 있다. 고객의 대역폭 속도, ISP(Internet service provider), peering 교환(ISP간의 트래픽 교환 방식) 지점과의 접근성 등은 개발팀의 통제를 벗어난 요소들이다. 하지만 응답시간에 영향을 주는 다른 변수들이 있다. 그 중 하나인 압축은 HTTP 응답의 크기를 줄임으로써 응답시간을 줄일 수 있는 하나의 방법이다.
HTTP/1.1로 시작하는 웹클라이언트는 HTTP 요청에서 Accept-Encoding header를 가진 압축지원을 나타낸다.
Accept-Encoding: gzip, deflate
만약 웹서버가 요청에서 이 header를 본다면, 고객에 의해 작성된 방법 중 하나를 사용하여 응답을 압축할 수 있을지도 모른다. 웹서버는 요청에서 Content-Encoding header를 통해 웹클라이언트에게 알려준다.
Content-Encoding: gzip
Gzip은 현재 가장 대중적이고 효과적인 압축방법이다. 이것은 GNU 프로젝트와 RFC 1952에 의해 표준화된 개발법이며 유일한 다른 압축형식은 deflate이지만, 이것은 덜 대중적이고 효과적이지 못하다.
일반적으로 gzipping은 약 70%까지의 응답크기를 줄일 수 있다. 오늘날 인터넷 트래픽의 약 90%는 gzip을 지원하는 browsers를 통해 이동되며 만약 Apache를 사용한다면 gzip에 설정된 module은 서버의 버전에 따라 결정되기도 한다. 예를 들어 Apache 2.x는 mod_deflate를 사용하지만 Apache 1.3은 mod_gzip을 사용한다.
browsers와 proxies에 관해 알려진 몇 가지 문제점은 browser가 예상한 것과 압축된 content와 관련해 받은 무언가에서 불일치를 야기할 수도 있다는 것이다. 다행히도 이런 문제는 오래된 browsers 사용이 감소함에 따라 줄어들고 있다. 또한 Apache modules은 적절하고 다양하게 응답하는 headers들을 자동적으로 추가해서 도움이 될 수 있다.
서버는 파일유형에 따라 압축대상을 선택할 수 있지만 일반적으로 이 결정에는 많은 제약이 따른다. 대부분의 웹사이트들은 자신들의 HTML 문서를 압축한다. 그 압축툴은 scripts와 stylesheets를 압축하는 데에도 매우 유용한 것들이지만 많은 웹사이트들은 이 기회를 놓치고 있다. 이미지와 PDF 파일은 이미 압축이 되어있기 때문에 압축할 필요가 없지만 XML이나 JSON을 포함한 텍스트 응답을 압축하는 데에는 유용하다. CPU를 낭비할 뿐 아니라 잠재적으로 파일크기를 증가시킬 수 있기 때문이다.
가능한 많은 파일 형식들을 압축하는 것은 페이지 무게를 줄이고 사용자 경험(UX)을 촉진하는 가장 쉬운 방법이다
5. Put Stylesheets at the Top (상단에 스타일시트를 넣어라)
 
tag: CSS
문서의 HEAD에 stylesheets를 이동하면 페이지 loading 속도가 빨라지는 것을 알 수 있다. 이것은 HEAD에 stylesheets를 놓는 것이 순차적으로 페이지를 로딩하도록 만들어 주기 때문이다.
성능에 관심이 있는 구성요소 엔지니어들은 점진적으로 페이지를 읽어오길 원한다. 즉, browser는 가능한 한 빨리 어떠한 content라도 표시할 수 있기를 원한다. 이것은 많은 content의 페이지와 느린 인터넷 접속 사용자에게 특히 중요하다. 사용자에게 진행률 표시기(progress indicator)와 같은 시각적 피드백 제공의 중요성은 연구와 함께 잘 입증되어 왔다. browser가 페이지를 점진적으로 읽어올 때, 상단의 header, 메뉴바(navigation bar), 로고 등은 페이지를 기다리는 사용자에게 시각적 피드백을 제공하는 역할을 하고 이것은 전반적인 사용자경험(UX)을 향상시킨다.
문서 하단에 stylesheets를 놓는 문제는 Internet Explorer를 포함한 많은 browsers에서 점진적으로 페이지를 불러오는데 악영향을 미친다. 이런 browser들은 스타일시트가 변경될 때 페이지 구성요소들을 다시 그리는 것을 막고 있다. 마치 사용자는 빈 페이지를 보는 것과 같은 것이다..
HTML 사양은 명확하게 stylesheets가 페이지의 Head에 포함된다는 것을 나타낸다. Unlike A, [LINK]는 오직 문서의 head 섹션에 나타날 수 있다. (그 태그가 여러 번 나타나더라도) 빈 화면과 unstyled(정의되지 않은) content의 flash 등 어떤 대안도 위험을 감수할 가치가 없다. 최적의 솔루션은 문서의 Head에서 HTML 사양에 따라 stylesheets를 읽어오는 것이다.
6. Put Scripts at the Bottom (하단에 스크립트를 넣어라)
 
tag: javascript
scripts로 야기될 수 있는 문제는 바로 병렬 다운로드를 방해한다는 것이다. HTTP/1.1 특징은 browsers가 host별로 두 개 이하의 components를 병렬 다운로드 하도록 구성할 것을 제시한다. 만약 여러 host에서 이미지를 제공한다면 병렬(parallel)로 발생하는 두 개 이상의 다운로드를 받을 수 있다. 그렇지만 위의 문제로 인해 script가 다운로드 되는 동안 browser는 서로 다른 hostname이라 하더라도 다운로드를 시작하지 않을 것이다.
어떤 상황에서 하단에 scripts를 이동하는 것은 쉽지 않다. 예를 들어, 만약 script가 페이지 contents의 일부를 삽입하기 위해 document.write를 사용한다면, 페이지의 하단으로 이동할 수 없다. 이것은 많은 문제점을 남기지만, 대부분의 경우 이런 상황에서의 차선책을 가지고 있다.
종종 대안으로 제시되는 것은 defer속성 scripts를 사용하는 것이다. DEFER의 속성은 script가 document.write를 포함하지 않음을 나타내고, browsers는 rendering을 계속할 수 있는 정보를 제공한다. 하지만, Firefox는 DEFER 속성을 지원하지 않는다. Internet Explorer에서 script는 defer(지연)될 수도 있지만, 만족스럽지는 않을 것이다. 만약 script가 deffered(지연)될 수 있다면, 페이지 하단으로의 이동이 가능하다. 그것은 웹페이지의 load 속도를 빠르게 만들어줄 것이다.
7. Avoid CSS Expressions (CSS의 표현을 피하라)
 
tag: css
CSS expressions는 동적으로 CSS 속성을 설정하는 위험하지만 강력한 방법이다. Internet Explorer 5로 시작되는 버전은 지원되지만, Internet Explorer 8로 시작되는 버전에서는 사용하지 않을 것을 권장한다. 한 예로, 배경색상은 CSS expressions를 사용하여 매시간 다른 설정이 가능하다.
background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );
위와 같이, 표현방법은 JavaScript 방식을 사용한다. CSS 속성은 JavaScript 방식을 처리한 결과값으로 설정한다. 표현방법은 다른 browsers에 의해 무시되므로, 여러 browsers를 통해 일관된 표현 생성을 필요로 하는 Internet Explorer의 속성을 설정하는 것은 유용하다.
Expressions의 문제는 CSS가 대부분 사람들이 생각한 것보다 더 자주 사용된다는 것이다. 페이지를 읽어오거나(render) 크기를 재설정(resize) 또는 scroll 하거나 심지어 사용자가 마우스로 페이지를 이동할 때에도 사용된다. CSS expression에 카운터(counter)를 추가하면 CSS expression이 사용되는 빈도를 파악할 수 있다. 페이지 주변을 마우스로 이동하는 것으로 10,000번 이상이 사용될 수 있다.
CSS expression의 사용횟수를 감소시키는 방법 중 하나는 뚜렷한 값(CSS expression으로 대체되는)으로 스타일 속성을 설정할 수 있는 expression을 한 번 사용하는 것이다. 만약 스타일 속성을 페이지 전반에 걸쳐 동적으로 설정해야 한다면, CSS expressions 대신에 event handlers를 사용하는 것이 대안이 될 수 있다. 반드시 CSS expressions를 사용해야 한다면, 수천 번 이상 사용될 수 있으며 페이지 성능에 영향을 줄 수도 있다는 사실을 기억해야 한다.
8. Make JavaScript and CSS External
 
tag: javascript, css
실행 규칙들의 대부분은 외부 components가 어떻게 관리되는지를 다룬다. 그러나 이전에 좀 더 기본적인 질문이 필요하다. JavaScript와 CSS를 반드시 외부파일로 만들어야 하는지 또는 페이지 내에서 inline되어야 하는지 이다.
External files을 사용하면 일반적으로 빠른 페이지를 생성한다. 왜냐하면 JavaScript와 CSS 파일은 browser에 의해 cache되기 때문이다. HTML 문서에 inline된 JavaScript와 CSS는 HTML 문서가 요청될 때마다 다운로드 된다. 이것은 필요한 HTTP 요청 수를 감소시키지만 HTML 문서의 크기를 증가시킨다. 반면, external files에 있는 JavaScript와 CSS가 browser에 의해 cache된다면, HTML 문서의 크기는 HTTP 요청수의 증가 없이 감소될 것이다.
핵심요소는 external JavaScript와 CSS components가 요청된 HTML 문서 수에 비례해 cache되는 빈도이다. 이 요소는 측정하기 어렵지만, 다양한 측정방법을 사용하여 계량화할 수 있다. 만약 사용자가 사이트에서 세션당 여러 개의 페이지뷰를 갖고, 많은 페이지가 동일한 scripts와 styelsheets를 재사용한다면, cached된 external files들로부터 많은 잠재적 이익을 얻을 수 있다.
많은 웹사이트들은 이러한 측정방법으로 수치를 중간 정도로 떨어뜨린다. 이러한 사이트의 경우, 최적의 솔루션은 일반적으로 JavaScript와 CSS를 external files로서 배포(deploy)하는 것이다. Yahoo의 front 페이지와 My Yahoo!와 같이 inlining이 선호되는 홈페이지만이 예외가 된다. 세션당 페이지뷰가 없거나 혹은 한 개를 가진 홈페이지는 빠른 end-user 응답시간에서 inline된 JavaScript와 CSS 결과를 찾을 수 있을지도 모른다.
일반적으로 많은 페이지뷰의 처음에 오는 front 페이지에 대해 HTTP 요청 감소에 영향을 주는 여러 기술들이 존재한다. 그 중 한 가지는 front page에 JavaScript와 CSS를 inline하는 것이지만, 페이지 loading이 완료되면 동적으로 external files을 다운로드 한다. 후속 페이지는 이미 browser의 cache에 있어야만 하는 external files을 참조할 것이다.
9. Reduce DNS Lookups (DNS 조회를 줄여라)
 
tag: content
DNS(Domain Name System)는 마치 전화번호부가 사람이름을 전화번호로 매핑(mapping)하는 것처럼 hostnames을 IP 주소로 매핑(mapping)시킨다. browser에 www.yahoo.com을 입력하면 DNS resolver는 해당 서버의 IP주소를 반환하는 browser에 의해 접속된다. DNS는 비용이 부과된다. 일반적으로 주어진 hostnames에 대한 IP 주소를 조회하기 위해 DNS당 20-120 milliseconds(ms: 1000분의 1초)가 소요된다. Browser는 DNS 조회가 완료될 때까지 해당 hostname으로부터 어떤 것도 다운로드 할 수 없다.
DNS 조회는 성능향상을 위해 임시저장(cache)된다. 이 caching은 사용자의 ISP 또는 로컬 네트워크에 의해 유지되는 특정 caching 서버에서 발생하지만, 개인사용자의 컴퓨터에서 나타나기도 한다. DNS 정보는 운영체제의 DNS cache(Microsoft Windows의 “DNS 고객 서비스”)에 남겨진다. 대부분의 browser는 운영체제의 cache와는 별도로 자신의 cache를 소유한다. Browser가 DNS 기록을 자신의 cache에 저장하는 한, 그 기록(record)에 대한 요청을 가진 운영체제는 방해를 받지 않는다.
Internet Explorer는 DnsCacheTimeout 등록 설정을 기본으로 30분 동안 DNS 조회를 저장(cache)한다. Firefox는 1분 동안 DNS 조회를 저장(cache)하고, network.dnsCacheExpiration 환경설정에 의해 제어된다. (Fasterfox는 이것을 1시간으로 변경한다)
고객의 DNS cache가 비어있을 때(browser와 운영체제에 대해), DNS 조회 수는 웹페이지의 고유한 hostnames의 수와 동일하다. 이것은 page URL, images, script files, stylesheets, Flash 개체 등을 포함한다. 고유의 hostnames의 수를 줄이는 것은 DNS 조회 수를 감소시킨다.
고유의 hostnames의 수를 줄이는 것은 페이지에 발생하는 parallel downloading의 양을 줄일 수도 있다. DNS 조회를 피하는 것은 응답시간을 줄일 수 있지만, parallel downloads를 줄이는 것은 응답시간을 증가시킬지도 모른다. 따라서 이 components를 적어도 2개(hostnames이 4개를 넘으면 안됨)로 분리시킬 것을 권장한다. 이것은 DNS 조회를 줄이는 것과 높은 수준의 parallel downloads를 허용하는 것 사이에 적당한 절충안을 만들어줄 것이다.
10. Minify JavaScript and CSS (JavaScript와 CSS를 축소해라)
 
tag: javascript, css
축소화(minification)는 JavaScript와 CSS의 사이즈를 줄이기 위해 로드(load)시간을 개선함으로써 code에서 불필요한 문자들(characters)을 제거하는 방법이다. Code가 축소될 때, 불필요한 공백문자(공백, 줄 바꿈, tab)뿐 아니라 모든 코멘트 역시 제거된다.
JavaScript의 경우, 다운로드 파일의 크기가 줄어들기 때문에 축소화(minification)는 응답시간의 성능을 개선시킨다. Javascript를 축소하는 2가지 대중적인 툴(tools)은 JSMin과 YUI 압축기이다. YUI 압축기는 CSS도 축소할 수 있다.
Obfuscation(난독화 또는 우회기법)은 소스코드(source code)에 적용될 수 있는 획기적인 최적화 방안이다. 이것은 축소화(minification)보다 복잡하며 obfuscation 단계의 결과로 오류(bug)를 생성할 가능성이 높다. 미국 웹사이트 상위 10위권의 설문조사 결과에 따르면, obfuscation이 25%의 크기를 감소시키는 것과 비교하여 minification은 21%의 감소가 가능한 것으로 알려진다. Javascript Obfuscation은 높은 수치의 감소를 가져오지만, JavaScript Minification으로 축소하는 것이 위험이 적다.
external scripts와 styles을 축소하는 것 외에도, inlined <script>와 <style> blocks역시 축소가 가능하다. scripts와 styles을 압축(gzip)하더라도 그것들을 minifying하면 5%이상의 크기를 더 줄일 수 있다. JavaScript와 CSS의 사용이 증가함에 따라 code를 축소하는 것은 많은 절감을 가져올 것이다.
11. Avoid Redirects (재전송을 피해라)
 
tag: content
재전송(redirects)은 301 및 302 status codes를 가지고 확인할 수 있다. 다음은 301 응답의 HTTP headers의 예이다.
HTTP/1.1 301 Moved Permanently
Location: http://example.com/newuri
Content-Type: text/html

Browser는 자동으로 경로속성에 지정된 URL의 사용자에게 넘어간다. 재전송(redirect)에 대한 모든 정보는 headers에 있다. 응답한 본문은 일반적으로 비어있지만 301과 302 응답 모두 실제로 cache되지 않는다. (Expires나 Cache-Control과 같은 추가 headers 제외) meta refresh tag와 JavaScript는 다른 URL로 사용자에게 전송되는 다른 방법이다. 그래도 반드시 재전송(redirect)을 해야 한다면, 먼저 뒤로 가기(back) 버튼이 제대로 작동하는지 확인한 후에 표준 3xx HTTP 상태 코드(codes)를 사용할 것을 권장한다.
가장 중요하게 기억해야 할 것은 재전송(redirects)은 사용자경험(UX)을 느리게 만든다는 것이다. 사용자와 HTML 문서 사이에 redirect를 삽입하는 것은 페이지에 있는 모든 것들을 지연시킨다. 그 이유는 HTML 문서가 도착하기 전까지는 페이지의 아무것도 출력되지 않을 수 있으며, 어떤 components도 다운로드를 시작할 수 없기 때문이다. 가장 치명적인 redirects는 자주 일어나지만 웹 개발자들은 일반적으로 그것을 인식하지 못한다는데 있다. 그것은 trailing slash(/)가 URL(반드시 1개를 가져야만 하는)로부터 빠져있을 때 발생한다. 예를 들어,http://astrology.yahoo.com/astrology/ (trailing slash 추가)로 redirect를 포함하는 301 응답에서 http://astrology.yahoo.com/astrology의 결과로 이동해 보자. 이것은 Alias, mod_rewrite, DirectorySlash 지시어를 사용함으로써 Apache에서 해결된다. (Apache handlers를 사용하는 경우)
오래된 웹사이트에서 새로운 웹사이트로의 접속은 redirects에 대한 일반적 사용이다. 이 외에도 웹사이트의 서로 다른 부분들을 연결하는 것이나 특정조건(browser 유형, 사용자 계정 유형 등)에 따라 사용자에게 전송하는 것도 포함된다. 두 개의 웹사이트를 연결하기 위해 redirect를 사용하는 것은 간단하면서도 추가 coding을 요구하지 않는다. Redirect는 개발자들에게 복잡성을 줄일 수 있지만, 사용자경험(UX)을 감소시킨다. Redirects 사용에 대한 다른 대안은 두 code 경로가 같은 서버에 host되는 경우, Alias와 mod-rewrite를 사용하는 것이다. 도메인 이름변경을 위해 redirects를 사용한다면 Alias 또는 mod_write를 결합하여 CNAME(DNS record: 하나의 도메인 이름을 다른 것으로 가리키는 별칭도메인을 생성)를 생성하면 된다.
12. Remove Duplicate Scripts (중복 Scripts를 제거하라)
 
tag: javascript
한 페이지에 동일한 JavaScript 파일을 두 번 포함시키는 것은 성능에 영향을 미친다. 이것은 생각만큼 특별한 경우가 아니다. 미국 웹사이트 상위 10위권의 조사결과에 따르면, 그 중 두 개가 중복 script를 포함한다는 것을 보여준다. 두 가지(team 크기와 scripts의 수) 주요 요소는 단일 웹페이지에서 script 복제가능성을 증가시킨다. 그런 일이 생기면, 복제 scripts는 불필요한 HTTP 요청과 JavaScript 실행의 생성으로 인해 성능에 영향을 준다.
불필요한 HTTP 요청 수는 Internet Explorer에서 발생하지만 Firefox에서는 일어나지 않는다. Internet Explorer에서, external script가 두 번 포함되고 임시저장(cacheable)되지 않는다면, 그것은 페이지로딩(loading)을 하는 동안 두 개의 HTTP 요청을 생성한다. 비록 script가 캐쉬에 있더라도 사용자가 페이지를 reload할 때 추가 HTTP 요청은 일어난다.
불필요한 HTTP 요청의 추가 생성은 script를 여러 번 읽도록 시간을 낭비한다. 이 중복된 JavaScript의 실행은 script의 cacheable 가능 여부에 관계없이 Firefox와 Internet 모두에서 발생한다.
같은 script를 두 번 포함하지 않게 하려면 templating 시스템에서 script 관리 모듈을 실행하는 것이다. script를 넣기 위한 일반적인 방법은 HTML 페이지에 SCRIPT 태그를 사용하는 것이다.
<script type="text/javascript" src="menu_1.0.17.js"></script>
PHP에서의 대안은 insertScript라는 함수를 작성하는 것이다.
<?php insertScript("menu.js") ?>
여러 번 삽입되는 동일한 script를 예방하는 것 외에도, 이 함수는 scripts와 함께 다른 문제(미래 시점의 Expires header 지원을 위한 script 파일이름에 버전 번호를 추가하는 것 및 의존성 검사와 같은)를 처리할 수 있을 것이다.
13. Configure ETags (ETags 설정)
 
tag: server
Entity tags(ETags)는 browser의 cache에 있는 component가 원본 서버에 있는 component와 일치하는지 여부를 확인하기 위해 웹서버와 browsers가 사용하는 메커니즘이다. (“entity”는 “component”의 다른 단어이다: images, scripts, stylesheets 등) ETags는 마지막 수정날짜보다 더 유동적인 검증기관들에 대한 메커니즘을 제공하기 위해 추가된다. ETag는 유일하게 component의 특정 버전을 식별하는 문자열이다. 유일한 형식 제약은 문자열을 이용하는 것이다. 원본 서버는 ETag 응답 header를 사용하여 component의 ETag를 지정한다.
HTTP/1.1 200 OK
Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
ETag: "10c24bc-4ab-457e1c1f"
Content-Length: 12195
나중에 browser가 component를 확인해야만 한다면, 원본서버에서 ETag를 통과시키기 위해 If-None-Match header를 사용해라. 만약 ETags가 일치한다면, 다음 아래 예로 304 status code는 12195 bytes로 응답을 줄이고 반환된다.
GET /i/yahoo.gif HTTP/1.1
Host: us.yimg.com
If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT
If-None-Match: "10c24bc-4ab-457e1c1f"
HTTP/1.1 304 Not Modified
ETags는 사이트를 호스팅하는 특정서버에서만 보여지도록 만들어진 속성을 사용하도록 설계되었기 때문에 browser가 한 서버로부터 원본 component를 얻고 나중에 다른 서버에서 해당 component를 확인하려고 할 때 일치하지 않는다는 문제점이 있다. 웹사이트가 요청을 처리하기 위해서는 서버를 클러스터 구성으로 하는 것이 일반적이다. 기본적으로 Apache와 IIS 모두 여러 대의 서버를 이용하여 웹 사이트의 계속되는 유효성 테스트를 획기적으로 줄일 수 있도록 ETag에 데이터를 삽입한다. Apache 1.3과 2.x에 대한 ETag 형식은 inode_size_timestamp이다. 비록 특정 파일이 여러 서버에 를 통해 동일한 디렉토리에 상주하고, 동일한 파일크기, 권한, timestamp 등을 가지더라도, 그 파일의 inode는 서버마다 다르다.
IIS 5.0 및 6.0은 ETags와 유사한 문제를 가지고 있다. IIS에서 ETags에 대한 형식은 Filetimestamp:ChangeNumber이다. ChangeNumber는 IIS 구성변경을 추적하는 데 사용하는 counter이며, 웹사이트 뒤에 위치한 모든 IIS 서버들은 다른 ChangeNumber를 가지고 있다.
완벽히 동일한 component에 대해서, Apache 및 IIS에 의해 생성된 ETags는 서버마다 일치하지 않을 것이라는 최종결과를 보여준다. 만약 ETags가 일치하지 않는다면, 사용자는 효율적인(작고 빠른) 304 응답(ETags에 의해 설계된)을 받지 않는다. 대신에 사용자는 component에 대한 모든 데이터 외에 일반적인 200 응답을 받을 것이다. 오직 한 서버에서 웹사이트를 호스트하는 경우는 문제가 되지 않지만 여러 서버에서 웹사이트를 호스팅 한다면, ETag 설정을 기본으로 Apache나 IIS을 사용해야 할 것이다. 또한 사용자의 페이지는 점점 느려지고 서버의 부하가 높아지며, 보다 큰 대역폭을 소모할 뿐 아니라, proxies는 contents를 효율적으로 caching하지 못할 것이다. 비록 component가 먼 미래시점의 Expires header를 가지더라도 사용자가 Reload(재로드) 또는 Refresh(새로고침)을 누를 때마다 조건부의 GET 요청은 계속 이루어진다. 만약 ETags가 제공하는 유연한 검증 모델을 활용하지 않는다면, ETag를 완전히 제거하는 편이 낫다. 마지막으로 수정된 header는 component의 timestamp에 따라 확인된다. 그리고 ETag를 제거하면 응답과 후속 요청 모두에서 HTTP header 크기를 줄일 수 있다. 이 Microsoft Support article은 ETags를 어떻게 제거하는지 설명하고 있다. Apache에서의 ETags 제거는 설정 파일에 간단히 다음 줄을 추가함으로써 이루어진다.
FileETag none
14. Make Ajax Cacheable
 
tag: content
인용된 Ajax의 장점 중 하나는 백엔드(backend)의 웹서버로부터 정보를 비동기식으로 요청함으로써 사용자에게 즉각적인 피드백을 제공한다는 것이다. 그러나 Ajax를 사용하면 사용자는 반환을 위해 비동기의 JavaScript와 XML 응답들을 기다리며 시간을 낭비하지 않을 것이라는 것을 보장할 수 없다. 여러 애플리케이션에서 Ajax가 어떻게 사용되는지에 따라 사용자가 기다림을 지속할 것인지가 결정된다. 예를 들어, 웹기반의 이메일 클라이언트에서 사용자는 그들의 검색 기준에 일치하는 모든 이메일 메시지들을 찾기 위해 Ajax 요청들에 대한 결과값을 기다리게 될 것이다. “asynchronous(비동기의)”이란 “instantaneous(즉시 일어나는)”을 의미하지 않는다.
성능향상을 위해 이런 Ajax 응답들을 최적화하는 것은 중요하다. “Add an Expires or a Cache-Control Header”에서 다뤘듯이(앞부분 참고), Ajax 성능을 향상시키기 위한 가장 중요한 방법은 응답들이 cacheable하도록 만드는 것이다. 다른 규칙들도 Ajax에 적용된다.
Gzip Components
Reduce DNS Lookups
Minify JavaScript
Avoid Redirects
Configure ETags
예를 들어 살펴보자면, 웹 2.0 이메일 클라이언트는 자동완성(autocompletion) 기능에 대해 사용자의 주소록을 다운로드하기 위해 Ajax를 사용할지도 모른다. 만약 사용자가 이메일 웹 애플리케이션을 사용한 이후 주소록을 수정하지 않았다면, Ajax 응답이 미래 시점의 Expires 또는 Cache-Control header로 cacheable하게 만들어진 경우에 한해 이전 주소록 응답은 cache로부터 읽어올 수 있을 것이다. Brower는 언제 이전에 cache된 주소록 응답을 사용할 지, 아니면 새로운 주소록을 요청할 지 반드시 통보되어야 한다. 이것은 마지막으로 사용자가 주소록을 수정한 것을 나타내는 주소록 Ajax URL에 timestamp를 추가하여 수행할 수 있다. (ex. &t=1190241612) 만약 주소록이 마지막 다운로드 이후 수정되지 않았다면, timestamp는 동일하며 주소록은 별도의 HTTP roundtrip이 제거된 browser의 cache로부터 불러올 수 있을 것이다. 만약 사용자가 주소록을 수정했다면, timestamp는 새로운 URL이 저장(cache)된 응답과 일치하지 않는다는 것을 확신하고, browser는 업데이트된 주소록 항목을 요청할 것이다.
비록 Ajax 응답들이 동적으로 생성되고 오직 한 명의 사용자에게 적용될지라도, 그들(Ajax 응답들)은 여전히 cache될 수 있다. 이렇게 하면 웹 2.0 애플리케이션을 빠르게 만들 수 있을 것이다.
15. Use GET for AJAX Requests (AJAX 요청에 대한 GET 사용)
 
tag: server
Yahoo 메일 팀은 XMLHttpRequest를 사용할 때, POST가 browsers에서 2단계(headers를 전송하고 그 후에 데이터를 전송)의 과정으로 수행된다는 것을 발견했다. 그래서 많은 양의 cookies쿠키를 갖고 있는 경우를 제외하고 (데이터)전송을 위해 TCP 패킷 한 개만 필요로 하는 GET을 사용하는 것이 최상의 방법이다. IE에서 최대 URL의 길이는 2K이므로, 2K 이상의 데이터를 전송한다면 GET을 사용하지 못할 수도 있다.
흥미로운 부작용은 포스팅된 어떤 데이터도 갖고 있지 않은 POST는 GET처럼 행동한다는 것이다. HTTP의 사양에 따라, GET은 정보검색을 의미하므로 데이터를 전송해서 서버 측에 저장되게 하는 것과는 달리, 오직 데이터만을 요청할 때만 GET을 사용하는 것이 이치에 맞다.
16. Reduce the Number of DOM Elements (DOM 요소의 수를 줄여라)
 
tag: content
복잡한 페이지는 더 많은 바이트(bytes)를 다운로드 하는 것을 의미하고, 또한 JavaScript에서 느린 DOM 접근을 의미한다. 예를 들어, 만약 event handler를 추가하려는 페이지에 500 또는 5000 DOM 요소(elements)를 통해 루프(loop)를 돌려서 처리한다면 차이가 생긴다.
DOM 요소들(elements)의 높은 숫자는 content를 반드시 제거하지 않고 페이지의 마크업(markup)과 함께 개선되어야만 하는 무언가가 있다는 것을 말한다. 당신은 레이아웃을 위해 중첩된(nested) tables을 사용하고 있는가? 당신은 단지 레이아웃 문제를 해결하기 위해 더 많은
를 삽입하고 있는가? 아마 마크업(markup)을 할 수 있는 이론상의 보다 정확한 방법이 있을 것이다.
YUI CSS 유틸리티는 레이아웃에 큰 도움이 된다: grid.css는 전체 레이아웃에 도움이 될 수 있고, font.css와 reset.css는 browser의 기본서식을 완전히 제거하는 데 도움이 될 수 있다. 이것은 마크업(markup)에 대해 새롭게 생각해 볼 수 있는 기회이다. 예를 들어, 새로운 줄을 읽어오기(render) 때문이 아니라 이론상으로 이치에 맞을 때에만 <div>를 써라.
DOM 요소(elements)의 수는 단지 Firebug의 콘솔에 입력하는 것으로 쉽게 테스트가 가능하다.
document.getElementsByTagName('*').length
그렇다면, 얼마나 많은 것이 DOM 요소들(elements)이 많다는 것을 의미하는가? 좋은 마크업(markup)을 가진 유사한 페이지들을 확인해보자. 예를 들어, Yahoo의 홈페이지는 굉장히 바쁜 웹사이트 중 하나이지만 여전히 700 요소들(HTML tags) 이하를 가지고 있다.
17. No 404s
 
tag: content
HTTP 요청은 비용(시간&자원)이 발생하므로 HTTP 요청을 만들고 쓸모 없는 응답(404 Not Found)을 얻는 것은 전적으로 불필요하며 아무 이득 없이 사용자경험(UX)을 느리게 만들 것이다.
일부 사이트들은 유용한 404s(ex. “Did you mean X?”)를 가지고 있다. 이것은 사용자경험(UX)에는 도움이 되지만, 한편으로는 서버 자원(데이터베이스와 같은 기타 등등)을 낭비시키는 단점을 가진다. external JavaScript에 대한 링크가 잘못되고, 그 결과값이 404일 경우는 특히 좋지 않다. 처음에 이 다운로드는 parallel downloads를 차단할 것이다. 그 다음, browser는 마치 그것이 JavaScript 코드인 것처럼 그 안에 사용 가능한 무언가를 찾기 위해 404 응답 body를 분석할지도 모른다.
18. Reduce Cookie Size (쿠키사이즈를 줄여라)
 
tag: cookie
HTTP 쿠키들(cookies)은 인증 및 개인화와 같은 다양한 이유로 사용된다. 쿠키들에 대한 정보는 web servers와 browsers 사이의 HTTP headers에서 교환된다. 쿠키들의 크기를 가능한 한 작게 유지하는 것은 사용자의 응답시간에 미치는 영향을 최소화하기 위해 매우 중요하다.
자세한 내용은 Tenni Theurer and Patty Chi의 "When the Cookie Crumbles"를 참조해라. 이 연구의 실질적 정보는 다음과 같다:
- 불필요한 쿠키들을 제거해라
- 사용자의 응답시간에 미치는 영향을 최소화하기 위해 쿠키들의 크기를 가능한 한 작게 유지해라
- 다른 서브도메인들이 영향을 받지 않도록 적절한 도메인 수준(level)에서 쿠키설정을 주의해라.
- 적절한 만료(Expires) 날짜를 설정해라. 이른 만료날짜를 설정하거나 설정하지 않으면, 사용자의 응답시간 개선을 위해 쿠키를 즉시 제거해라.
19. Use Cookie-free Domains for Components (구성요소들에 대해 cookie-free 도메인을 사용해라)
 
tag: cookie
browser가 정적 이미지에 대한 요청을 하고 쿠키들을 함께 보낼 때, 쿠키들은 서버에서 아무런 영향을 주지 않는다. 그래서 이 쿠키들은 별다른 이유 없이 네트워크 트래픽만을 생성한다. 정적 구성요소들이 cookie-free 요청들과 함께 요구되고 있는지 반드시 확인해야 한다. 서브도메인을 생성하고 거기에 모든 정적 구성요소들을 호스트 해라.
만약 도메인이 www.example.org이라면, static.example.org에 정적 구성요소들을 호스팅 할 수 있다. 그러나 www.example.org와 반대로 만약 최상위 도메인 example.org에 이미 쿠키들을 설정했다면, static.example.org로의 모든 요청은 쿠키들을 포함할 것이다. 이 경우, 완전히 새로운 도메인을 구입할 수 있고, 거기에 정적 구성요소들을 호스트 할 수 있다. 또한 이 도메인은 cookie-free 상태로 유지될 수 있다. Yahoo는 yimg.com을 사용, YouTube는 ytimg.com을 사용하고 Amazon은 images-amazon.com 등을 사용한다.
Cookie-free 도메인에서 적정 구성요소들을 호스팅 하는 것의 또 다른 이점은 일부 proxies가 쿠키들과 함께 요청된 구성요소들을 cache하는 것을 거부할 수도 있다는 것이다. 같은 맥락으로, 홈페이지에 example.org 또는 www.example.org의 사용을 망설이고 있는 중이라면, 쿠키에 미치는 영향을 고려해라. www를 생략하는 경우는 *.example.org의 쿠키들을 작성하는 것 밖에 할 수 없지만, 성능을 위해 www 서브도메인을 사용하고 그 서브도메인에 대한 쿠키들을 작성하는 것이 최선의 방법이다.
20. Avoid AlphaImageLoader filter
tag: css
IE 소유의 AlphaImageLoader filter는 IE 7 미만 버전에서 PNGs의 반투명한 색채의 문제점을 해결하는 것을 목표로 하고 있다. 이 filter의 문제점은 이미지가 다운로드 되는 동안에 rendering을 차단하고 browser를 멈추게 만든다는 것이다. 이것은 또한 메모리 소모를 증가시키고, 이미지마다가 아닌 아닌 요소(element)마다 적용되므로 문제는 더욱 가중된다.
가장 좋은 방법은 AlphaImageLoader를 아예 사용하지 않고, 대신 선명도는 떨어지지만 IE에서 정상적으로 작동하는 PNG8()를 사용하는 것이다. 만약 AlphaImageLoader를 반드시 사용해야 한다면 IE7 이상의 사용자들에게는 적용되지 않도록 언더바 hack _filter를 사용해라.
 
21. Don't Scale Images in HTML (HTML에서 이미지의 크기를 줄이지 마라)
 
tag: images
단지 HTML의 넓이와 높이를 설정할 수 있다는 이유로, 필요한 것보다 더 큰 이미지를 사용하지 마라. 
만약 <img width="100" height="100" src="mycat.jpg" alt="My Cat" />를 원한다면 이미지(mycat.jpg)는 500X500px 크기의 이미지를 작게 해서 넣는 것보다 100X100px 크기의 이미지를 넣어야 한다.
22. Make favicon.ico Small and Cacheable (favicon.ico파일은 작고 cacheable하게 만들어라))
 
tag: images
favicon.ico는 서버의 루트(root)에 머무는 이미지이다. 당신이 신경 쓰지 않더라도 browser는 계속 그것을 요구하기 때문에 404 Not Found에 응답 하지 않는 것이 좋다.
또한 같은 서버에 있기 때문에 쿠키들은 요청 시마다 발송된다. 이 이미지는 또한 다운로드 순서를 방해한다. 예를 들어, IE에서 onload에 추가 components를 요청할 때, favicon은 해당 추가 components 이전에 다운로드 될 것이다.
Favicon.ico가 가진 단점을 보완하기 위해 다음 사항을 확인해라.
- 가능한 한 1K이하로 작게 해라.
- 변경설정 후에는 이름변경이 불가능하므로 원하는 시점의 Expires header를 설정하라. 아마 미래 시점(약 몇 달 뒤)의 Expires header를 안전하게 설정할 수 있을 것이다. 명확한 결정을 위해 현재 favicon.ico의 마지막 수정날짜 확인이 가능하다.
Imagemagick는 작은 favicon 이미지들을 생성할 수 있게 해준다.
23. Keep Components under 25K (25K이하의 구성요소들을 유지해라)
 
tag: mobile
이러한 제한은 아이폰이 25K보다 큰 구성요소를 cache하지 않는 것에 기인한다. 이것은 압축되지 않은 사이즈라는 것을 기억해라. gzip으로는 충분하지 않을 수도 있기 때문에 minification(축소)하는 것은 중요하다.
좀 더 자세한 정보를 원한다면 Wayne Shea and Tenni Theurer의 "Performance Research, Part 5: iPhone Cacheability - Making it Stick"를 참조해라.
24. Pack Components into a Multipart Document (다중문서에 구성요소들을 묶어라)
 
tag: mobile
이메일의 첨부파일과 같이 다중문서에 구성요소들을 묶는 것은 한 개의 HTTP 요청에 여러 개의 구성요소들을 불러오는데 도움이 된다. (HTTP 요청들은 비용(시간&자원)이 발생한다는 것을 명심해라) 사용자가 이 기술을 사용할 때, 사용자 에이젼트(아이폰은 지원하지 않음)가 이러한 기능을 지원하는지 먼저 확인해라.
25. Flush the Buffer Early (초기 buffer를 flush하라)
 
tag: server
사용자들이 페이지를 요청할 때, backend 서버와 HTML 페이지를 함께 연동하는 것은 200~500ms 사이의 시간이 걸릴 수 있다. browser는 도착하는 데이터를 기다리는 동안 작동하지 않는다. PHP는 flush() 기능을 가지고 있다. 그것은 일부 준비된 HTML 응답을 browser로 전송하는 것을 승인함으로써, browser는 backend가 HTML 페이지의 나머지와 함께 연동되는 동안 components를 불러올 수 있다. 그로 인한 이익은 주로 바쁜 backends와 한가한 frontends에서 나타난다.
head에 대한 HTML이 보통 더 쉽게 생성되기 때문에 HEAD 바로 다음에 flushing을 사용하는 것이 적합하다. 그것은 backend가 동작하는 동안, browser가 병렬로 연동하기 위해 필요한 CSS 및 JavaScript 파일들을 포함하는 것을 허락한다.
예)
... <!-- css, js -->
</head>
<?php flush(); ?>
<body>
... <!-- content -->
Yahoo search는 이 기술 사용의 이점을 증명하는 연구와 실제 사용자 테스트를 개척하였다.
26. Optimize CSS Sprites (CSS Sprites를 최적화하라)
 
tag: images
- Sprite에서의 이미지를 수직이 아니라 수평으로 정렬하면 파일사이즈가 더 작아진다.
- Sprite에서 유사한 색상을 결합하는 것은 색상 카운트(count)를 낮게 유지하는데 도움이 된다. (PNG8에 맞춰 이상적인 256 색상 이하로 설정)
- “mobile-friendly” 하며, sprite에서 이미지들 사이에 큰 간격을 두지 않는다. 이것은 파일 크기에는 별로 영향을 미치지 않지만 사용자 에이젼트(agent)에게 이미지를 픽셀 지도(pixel map)로 압축하기 위해 적은 메모리를 요구한다. 100X100 이미지가 10,000 pixels일 때, 1000X1000은 1,000,000 pixels이다.
27. Post-load Components
 
tag: content
페이지를 자세히 살펴보게 되면 “처음에 페이지를 읽어오기 위해 절대적으로 요구되는 것”이 무엇인지에 의문을 가진다. content와 components의 나머지는 기다릴 수 있다.
JavaScript는 onload event 전후의 분할을 위한 이상적인 후보이다. 예를 들어, 만약 드래그 앤 드롭(drag and drop)과 애니메이션을 실행하는 JavaScript 코드와 라이브러리(library)를 갖고 있다면, 초기 rendering 후에 페이지의 dragging 요소(elements)가 오기 때문에 그것들은 기다릴 수 있다. Post-loading에 대한 후보를 찾기 위한 또 다른 장소는 fold 아래의 숨겨진 content(사용자의 동작 이후에 나타나는 content)와 이미지들을 포함한다.
YUI Image Loader를 이용하면 fold 아래의 이미지들을 지연시킬 수 있고, YUI GET 유틸리티는 즉시 JS와 CSS를 포함하는 가장 쉬운 방법이다. Firebug의 Net Panel이 실행되는 Yahoo의 홈페이지는 좋은 예가 된다.
성능목표는 다른 웹 개발 모범사례(best practices)와 비슷할 때 가장 이상적이다. 이런 경우, 점진적 강화의 아이디어는 JavaScript를 지원받을 때 사용자경험(UX)을 향상시킬 수 있지만, 페이지가 JavaScript 없이도 작동하는지 반드시 확인해야 한다는 것을 명시한다. 그래서 페이지가 정상적으로 작동하는지 확인한 후에, 약간의 post-loaded scripts(드래그 앤 드롭 및 애니메이션과 같은 부가프로그램을 제공하는)로 그것을 향상시킬 수 있다.
28. Preload Components
 
tag: content
Preload는 post-load의 반대개념처럼 보일지 모르지만, 실제로는 다른 목적을 가지고 있다. components를 preloading함으로써 browser가 정지상태(idle)인 시간의 이점을 활용할 수 있고, 미래에 필요한 components(images, styles, scripts와 같은)를 요청할 수 있다. 이 방법은 사용자가 다음 페이지를 방문할 때, 대부분의 components를 cache에 이미 가질 수 있고, 페이지는 사용자에게 훨씬 빨리 로드(load)될 것이다.
Preloading의 몇몇 종류에 대해 알아보자.
- Unconditional(무조건적인) preload - onload가 작동되자마자, 바로 여분의 components를 가져온다. Sprite image가 onload를 어떻게 요청하는지에 대한 예로 google.com을 확인해라. 이 Sprite image는 google.com의 홈페이지에 필요한 것은 아니지만, 그것은 연속적인 검색결과 페이지에 필요하다.
- Conditional(조건부의) preload - 사용자의 작업을 기반으로 사용자가 다음에 어디를 향하고 있는지에 대한 경험에 근거한 추측을 만들고, 그에 따라 preload를 해라.
Search.yahoo.com에 가면 검색창(input box)에 입력을 시작하면, 일부 추가 components의 요청방법을 볼 수 있다.
- Anticipated(예상된) preload - redesign을 시작하기 전에 미리 preload를 해라. 그것은 종종 redesign 후 사람들이 “새로운 사이트는 멋지지만, 이전보다 느려졌어”라는 말을 들을 때 발생한다. 문제의 일부는 사용자들이 기존 사이트에 cache를 가지고 방문했지만, 새로운 사이트는 항상 비어있는 cache 상태로 방문한 것이기 때문일 수도 있다. redesign를 실행하기 전에 몇 가지 components를 preloading하여 부작용을 완화시킬 수 있다. 기존 사이트는 browser가 정지상태인 시간을 사용할 수 있고, 새로운 사이트에서 사용될 이미지들 및 scripts를 요청할 수 있다.
29. Split Components Across Domains (도메인에서 구성요소들을 분할하라)
 
tag: content
components를 분할하는 것은 parallel downloads(병렬 다운로드)를 극대화할 수 있다. DNS 조회의 penalty(불이익) 때문에 2-4개 이상의 도메인을 사용하고 있지는 않은지 확인해라. 예를 들어, www.example.org에서 HTML과 동적 content를 호스트할 수 있고, static1.example.org와 static2.example.org 사이의 정적 구성 요소를 분할할 수 있다.
자세한 내용은 Tenni Theurer와 Patty Chi의 "Maximizing Parallel Downloads in the Carpool Lane"를 참조해라.
30. Minimize the Number of iframes (iframes의 수를 최소화해라)
 
tag: content
Iframes는 HTML 문서가 상위 문서에 삽입될 수 있도록 한다. 효과적으로 사용될 수 있도록 iframes이 어떻게 작동하는지 이해하는 것은 매우 중요하다.
<iframe> 장점:
- badges나 ads와 같이 느린 third-party content를 원활하게 함
- Security sandbox (보안 sandbox)
- scripts를 병렬로 다운로드 함
<iframe> 단점:
- 비어있어도 값이 비쌈
- page onload를 차단함
- Non-semantic (비의미론적인)
31. Optimize Images (이미지를 최적화하라)
 
tag: images
디자이너가 웹페이지에 대한 이미지 생성을 완료하면, 웹서버에 이미지들을 올리기 전에(FTP) 확인할 수 있는 몇 가지 것들이 존재한다.
- GIFs를 체크하고 이미지 색상들의 숫자에 상응하는 팔레트 크기를 사용하는지 확인해라. Imagemagick를 이용하면 identify -verbose image.gif를 사용해서 확인하기가 쉽다.
팔레트에서 4가지 색상과 256 색상 슬롯(slot)을 사용하는 이미지를 보면 개선의 여지가 있다.
- GIFs를 PNGs로 변환해보고, 저장이 되었는지 확인해라. 개발자들은 종종 browsers에서의 제한된 지원으로 인해 PNGs의 사용을 망설이지만, 이것은 이미 과거의 얘기이다. 유일한 진짜 문제는 PNGs 진짜 색상의 알파투명도이지만, GIFs는 진짜 색상이 아니며 다양한 투명이미지 또한 지원하지 않는다. 그러므로 GIF가 할 수 있는 것들은, 팔레트 PNG(PNG8) 또한 할 수 있다. (애니메이션 제외). 이 간단한 imagemagick 명령은 PNGs를 안전하게 사용할 수 있게 한다.
convert image.gif image.png
우리가 말하는 것은 PiNG에게 한 번 기회를 주자는 것이다.
- 모든 PNGs에서 pngcrush(또는 최적화된 다른 PNG tool)를 실행하라
ex) pngcrush image.png -rem alla -reduce -brute result.png
- 모든 JPEGs에서 jpegtran을 실행하라. 이 도구(tool)는 회전(rotation)과 같이 손실 없는 JPEG 작업을 수행하고 최적화를 위한 사용이 가능하며, 이미지들로부터의 다른 쓸모 없는 정보(EXIF 정보와 같은)와 코멘트(commnets)를 제거할 수 있다.
jpegtran -copy none -optimize -perfect src.jpg dest.jpg
32. Minimize DOM Access (DOM 접근을 최소화해라)
 
tag: javascript
자바 스크립트로 DOM 요소들(elements)을 접근하는 것은 느리므로, 더 빠른 응답 페이지를 가지려면 다음 사항들을 반드시 실행해라.
- 접근했던 요소들(elements)에 대한 참조를 Cache해라
- 노드(nodes)들을 “offline”으로 업데이트하고 그것들을 tree에 추가하라
- JavaScipt로 레이아웃을 고정하는 것을 피해라
더 자세한 정보는 YUI theatre의 Julien Lecomte이 작성한 "High Performance Ajax Applications"를 참조해라.
33. Develop Smart Event Handlers
 
tag: javascript
가끔 페이지들은 너무 자주 실행되는 DOM tree의 서로 다른 요소들에 붙여진 너무 많은 event handlers 때문에 반응속도가 느리다고 느껴진다. 이 때, event delegation을 사용하는 것은 좋은 접근 방법이다. 만약 한 개의 div안에 10개의 버튼을 가진다면, 각 버튼마다 하나의 handler를 붙이는 대신 div 래퍼(wrapper)에 오직 하나의 event handler를 사용해라. Events는 bubble up(버블업)하므로 event를 인식할 수 있을 것이며 어떤 버튼(button)이 어디서부터 시작됐는지 알아낼 수 있을 것이다.
또한 DOM tree로 무언가를 시작하기 위해 onload event를 기다릴 필요는 없다. 주로 당신이 필요한 모든 것은 tree에서 접근(access)하기를 원하는 사용 가능한 요소(element)뿐이다. 따라서 모든 이미지들이 다운로드 되는 것을 기다리지 않아도 된다. DOMContentLoaded는 onload 대신에 사용할지도 모르는 event이지만 모든 browsers에서 사용이 가능할 때까지는 onAvailable method를 가지고 있는 YUI Event 유틸리티를 사용할 수 있다.
더 자세한 정보는 YUI theatre의 Julien Lecomte이 작성한 "High Performance Ajax Applications"를 참조해라.
34. Choose <link> over @import (@import 보다는 <link>를 선택하라)
 
tag: css
이전 모범사례 중 하나는 점진적 rendering을 위해 CSS가 페이지의 상단에 와야만 한다는 것이다. IE에서 @import는 태그를 페이지의 하단에 사용하는 것과 같으므로 최적의 사용방법이 아니다.
35. Avoid Empty Image src (빈 이미지 src를 피해라.)
 
tag: server
빈 문자열 src 속성을 가진 이미지가 하나 이상 발생할 것으로 예상되고 두 가지 형태로 나타난다.
1.straight HTML
<img src="">
2.JavaScript
var img = new Image();
img.src = "";
두 가지 양식은 동일한 효과를 불러 일으킨다: browser는 서버에 다른 요청을 만든다.
- Internet Explorer는 페이지가 위치한 directory를 요청한다.
- Safari와 Chrome은 그것들의 실제 페이지를 요청한다.
- Firefox 3와 이전 버전들은 Safari와 Chrome과 같은 동작을 수행하지만, 버전 3.5가 이 문제([bug 444931])를 다룬다. 그리고 더 이상 요청을 보내지 않는다.
- Opera는 빈 이미지 src가 발생할 때, 아무것도 수행하지 않는다.
왜 이런 동작들은 좋지 않을까?
 
1. 많은 양의 예상치 못한 트래픽(특히, 하루에 100만개의 페이지뷰를 생성하는 페이지들에 대해)을 전송함으로써 서버는 정지상태가 된다.
2. 서버는 절대 보여지지 않을 페이지를 생성하는 사이클(cycles)을 컴퓨팅 하는 것으로 낭비된다.
3. 사용자 데이터는 오류가 생길 가능성이 있다. 만약 요청이 추적상태에 있다면, 쿠키 또는 다른 방식으로 데이터를 파괴할 가능성이 있다. 비록 이미지 요청이 이미지를 반환하지 않더라도, 모든 쿠키들을 포함하는 browser에 의해 모든 header들은 읽고 수락될 수 있다. 응답의 나머지가 버려지는 동안에, 손상은 이미 완료될 지도 모른다. 이 작동의 근본 원인은 URI 해상도가 browser에서 실행되는 방식 때문이다. 이것은 RFC 3986- Uniform Resource Identifiers에 정의되어 있다. 빈 문자열이 URI로 발생되면, 그것은 상대적인 URI로 간주되며, 5.2 섹션에 정의된 알고리즘에 따라 해결된다. 구체적인 예를 들자면, 5.4 섹션에 등록된 빈 문자열이다. Internet Explorer가 부정확하게 실행되는 동안, 명백히 RFC 2396 - Uniform Resource Identifiers 사양(이것은 RFC 3986에 의해 더 이상 사용되지 않음)의 초기버전과 일맥상통하는 Firefox, Safari, 그리고 Chrome 섹션은 모두 사양마다 정확하게 빈 문자열을 해결할 것이다. 그래서 기술적으로, browsers는 상대적 URIs를 해결하기 위한 것들을 수행 중이다. 이 문맥에서의 문제는, 빈 문자열은 명확히 의도적이지 않다는 것이다.
HTML 5는 섹션 4.8.2에서 추가요청을 하지 않는 browsers를 지시하기 위해 태그의 src 속성의 설명을 추가한다:
src 속성은 반드시 존재해야 하고, 페이지 및 script되지 않으며 쌍방향이 아니고(non-interactive), 선택적으로 애니메이션(optionally animated)된 이미지 자원(image resource)을 참조하는 유효한 URL을 반드시 포함해야 한다. 만약 요소(element)의 기본 URI가 문서의 주소와 동일한 경우, src 속성값은 빈 문자열이어서는 안 된다.
browsers는 추후에 이런 문제를 가지지 않아야 하겠지만, <script src=""> 및 <link href="">에 대한 그런 조항은 갖고 있지 않다. browsers가 실수로 이 동작을 구현하지 않도록 확실히 하기 위해 그것을 조정할 수 있는 시간이 아마 있을 것이다.
이 규칙은 Yahoo의 JavaScript 전문가, Nicolas C. Zakas에 의해 창안되었다. 자세한 내용을 보려면 그의 기사 "Empty image src can destroy your site"를 참조해라.


출처 : http://www.xpressengine.com/tip/22330022

'Device & Language' 카테고리의 다른 글

C# IP 확인시...  (0) 2016.05.31
Data compression in DB2 9  (0) 2013.08.20
[java]My Math Class  (0) 2010.11.09