J.D.샐린저, 호밀밭의 파수꾼

정말 좋아하는 사람이 빌려준 책.

난 책을 추천받는 것을 좋아한다. 그 사람이 느꼈던 것을 나도 느끼고 있을까 하는 또다른 설렘이 주어지니까.

엄마도 이 책을 굉장히 좋아하신다.

그만큼 기대하며 이 책을 읽기 시작하였다.

p. 134

서니가 떠나고 난 후, 난 의자에 앉아 담배를 몇 대 피웠다. 날이 점점 밝아오고 있었다. 비참한 기분이었다. 얼마나 우울했는지는 말로 다 할 수 없을 정도였다.

난 앨리에게 큰소리로 말을 걸었다. 가끔씩 너무나도  기분이 울적할 때면 이렇게 했다. 집에 가서 자전거를 가지고 와서, 보비 팰론의 집 앞에서 만나자고. 보비 팰론은 메인 주에 있을 때 바로 옆집에 살던 친구였다. 정말 오래전 일이다. 실제로 어느 날인가 나는 보비와 함께 자전거를 타고 세데리고 호수까지 가기로 했던 적이 있다. 도시락을 싸서, 공기총도 가지고서. 그때만 해도 우린 어렸고, 공기총으로도 뭔가 잡을 수 있을 거라고 생각하고 있었다. 우리가 하는 얘기를 앨리가 듣고는 자기도 같이 가고 싶다고 했다. 난 그때 앨리에게 너무 어리다면서 데리고 갈 수 없다고 말했었다. 그래서 지금처럼 기분이 많이 울적해질 때면 앨리에게 이렇게 중얼거리는 것이다. “좋아, 집에 가서 자전거를 가지고 보비 집 앞으로 와. 빨리 갔다 와. 어서” 그렇다고 그때 내가 앨리를 아무 데도 데리고 다니지 않았던 건 아니다. 도리어 늘 데리고 다녔었다. 그런데 그날만은 데리고 가지 않았따. 같이 가지 못했다고 앨리도 화를 내지는 않았다. 그 애는 어떤 일에도 화를 내는 법이라고는 없었으니까. 그런데도 이렇게 우울할 때면 그 생각이 나곤 하는 것이다.

나는 왜 이걸 다 쓰고 있었을까. 생각보다 많이 기네. 하지만 쓰고 싶었다.

은유의 종말

은유의 종말

2013/09/19 by wangsy | 5 Comments

내가 맥을 처음 접했을 때가 대략 89년쯤인데, 맥을 처음 키면, Macintosh Guide라는 애플리케이션이 실행되었다. 그리고 기본적인 개념을 가르쳐 주었는데, 가장 먼저 시작하는 것이 마우스 사용의 개념을 익히는 것이었다. 3가지 개념을 가르치는데, Point, Click, Drag & Drop 이다. 이것을 실습하기 위해서, 어항이 있는 책상을 보여주었다. 그리고 Point 를 통해서 마우스를 가져다 대면 반응을 하고, Click 을 통해서 선택을 하고, Drag & Drop 으로 하나의 대상을 다른 대상으로 이동을 하여 무언가 액션을 할 수 있는 것을 가르쳐 주었다.

여기서 파일, 폴더, 휴지통, 데스크탑으로 비유를 확장하고, Point, Click, Drag & Drop 의 사용자 액션을 통해서 사용자가 컴퓨터에 원하는 의도를 전달할 수 있는 형식이었다. 책상위에 있는 문서를 Drag & Drop 으로 책상 서랍의 폴더에 옮겨 넣는 연습을 한다. 완벽한 은유였다. 그리고 이 은유는 생각보다 넓게 확장되었다.

그리고, Macintosh Human Interface Guideline 을 보게 되었는데, 3가지를 가르쳤다. 직관성, 일관성,  허용성. 직관성은 은유를 통해서 배우지 않아도 맥을 사용할 수 있었고, 일관성은 한번 알게 된 내용은 항상 동일한 의미로 사용되기 때문에 매번 배우지 않고도 인지할 수 있게 한다. 그리고 허용성은  사용자는 맘 편하게, 직관적으로 사용해 볼 수 있고, 혹시 잘못 추측했더라도 다시 번복할 수 있도록 허용하는 것이다. 그를 통해서 더더욱 빠르게 배울 수 있게 된다. 나는 이 철학에 탄복하였고, 지금껏 살아오는 내내, 내가 무언가를 만든다고 할때 생각의 기본 틀로 사용하였다. (물론 남이 만든 것을 무시하는 도구로 더 많이 사용하였다)

그리고, iPhone 이 나왔다.

iPhone 을 처음 소개한 스티브잡스는, 음악 기능중 Cover Flow를 소개할 때, “You can touch your music” 이라고 설명 하였다. 음악을 만질 수 있어요. 음악이 추상적인 무언가가 아니라, 손끝으로 만지고 조작하고 느낄 수 있는 대상이라는 것, 그것이 iPhone 의 큰 매력이었다.

그리고, iPhone Human Interface Guideline 을 보게 되었는데, 다음과 같은 말이 나왔다. UI 를 만들 때에는 만질 수 있는 대상처럼 설계해야 한다. Direct Manipulation 라는 말이 나온다. 토글 버튼은 오른쪽 왼쪽으로 밀면 딸깍딸깍 바뀌고, 슬라이드는 죽 댕기면 따라 온다. 페이지는 밀면 넘어가고… 그렇다. 터치 인터페이스라는 것은 실제 실생활의 사물 같은 것은 화면상에 넣어놓으면 그걸 진짜 만지는 것처럼 사용하면 된다. 얼마나 직관적인가. 배울 필요가 없다.

스큐몰피즘이란 말이 나왔다. iOS 는 만질 수 있는 객체를 UI 화 하는 것의 극한으로 스큐몰피즘을 선택하였다. 최대한 실생활에 가까운 것을 화면어 넣어야지. 정말 똑같이 생기면 더더욱 실감날 것이야. 디테일의 끝은 어디일까 궁금할 정도로 가죽질감을 넣었고, 금속재질은 빛에 반사하는 느낌도 주었다.

iOS7 이 선보였다. 스큐몰피즘을 이끌었던, 스캇 포스톨이 쫒겨나고, 그 자리를 조니아이브가 꿰찾다. 마치 혁명에 승리한 권력자가 과거를 부정해 버리듯, 조니아이브가 선보인 iOS7 은 철저히 스큐몰피즘을 걷어 내었다. 최신 유행이라고 하는 플랫 디자인으로 바뀌었다. 그냥 세속적으로 보자면, 조니아이브는 참 치졸해 보인다.

은유는 어디로 갔을까? 은유를 통한 직관성은 어떻게 하나?

몇해전부터인가 작은 문제가 생겼다. 우리가 늘 사용하는 “저장”이라는 의미로 사용하는 플로피 디스크, 그냥 아무 생각없이 은유적으로 사용되어 왔었는데, 세월이 한참 지나다 보니, 이걸 모르는 사람이 더 많다는 것이다. 아마도 플로피(적어도 위 아이콘과 같은 3.5인치)를 앞서 도입한 것도 애플이었지만, 가장 먼저 퇴출시킨 것도 애플이었다. 아마 1998년 반투명 iMac 이 세상에 선보였을 즈음이다. 그 이후에 PC 를 처음 접한 사람은 플로피디스크에 저장해 본 경험이 없다. 15살쯤 처음 컴퓨터를 접한다면, 지금 30살 이전의 대부분의 사람들에게는 전혀 직관적이지 않은 은유가 되는 것이다.

좀 더 나가보자. 점점 더 많은 사람들이 아나로그 객체보다 디지털 객체를 더 먼저 접하게 된다. 진짜 라디오 버튼으로 라디오를 조작했던 사람들은 5,60대가 되었고, 진짜 라디오 버튼 보다 화면상의 라디오 버튼을 처음 접한 사람이 더 많은 시대가 되었다. 직관성을 위한 은유가 아닌 용어 자체의 어원으로써 의미 밖게 남지 않는다. 아날로그 객체를 디지털에서 형상화 하는 것은 옛날 사람의 고집인 것 뿐인 시대가 되었다. 그냥 과거의 향수 정도? 앞으로 점점더 많아지는 디지털로 시작하는 세대를 생각한다면 더더욱 그렇다.

화면에서 누를 수 있는 것은, 실생활에서 진짜 눌렀던 버튼들 모양을 가진 것 만은 아니다.

우리는 근래 20년동안 웹이란 것에 익숙해 져 왔다. 웹은 하이퍼텍스트로 시작했다. 화면상에서 밑줄이 쳐 있는 글자는 누르면, 관련된 다른 문서로 이동하였다. 여기서 발전해서 글과 그림이 섞여 있는 문서에서 무언가 다른 정보로 이동시킬 것 같은 텍스트 혹은 이미지 조각을 눌러보면, 더 많은 정보로 연결해 주었다. 우리는 웹을 은유의 도움이 아닌 정보의 문맥으로 웹을 사용해 왔다.

웹은 점점 발전하여 이메일을 작성해 보내는 용도로 쉽게 사용할 수 있었고, 쇼핑을 하기에도 충분하였다. 데스크탑 메타포어 같은 은유는 필요없이 문맥속의 정보만으로 충분히 사용성이 좋았다는 것을 알아버렸다.

iOS 가 시작되면서 가장 먼저 없어진 것이 파일과 폴더의 은유였다. 더이상 파일, 폴더에 대한 은유가 사라진 컴퓨팅 환경이었다. 옛날부터 컴퓨터를 사용한 사람은 혼란스러워 하지만, 머리를 깨끗히 비우고 보면, 더 쉬워진 것은 사실이다. 이제 iOS 7 이 되면서 아날로그에 대한 은유도 사라지려 한다. 옛날 사람들은 다시 또 당황하지만, 미래에서 본다면 자연스러울 수 있다고 본다.

이렇게 된 마당에 구닥다리 옛날 물건들을 최신 기기에 멋지게 옮겨 놓고 편하다라는 표현을 할 수 있을까?  이제는 정보의 문맥이 가장 직관적인 인터페이스가 되는 것인가? 물론 일관성과 허용성은 아직 유효하다. 은유가 아닌 문맥.

 

애플은 iTunes의 아이콘에서 CD 이미지를 제거했다. 더이상 CD가 음악을 상징하지 않는다. 아니 iTunes가 그렇게 만들었다.

좀 더 고민해 보자.

두려워 하지 말고.

꼭 은유가 없다고 직관적이지 않은 것은 아니다.

[일일코딩] 배너 뽑아내 정렬하기

Question

lc.Home.promotions 에 들어 있는 데이터 중 만화 홈 메인 배너들의 comicId를 알파벳 순서로 구하시오.
– 만화 홈 메인 배너는 slot == 'home_main' 조건
– jQuery 사용 금지
for, while 문 사용 금지

Answer

milooy

function compare(a, b){
if(a<b){
return -1;
} else if(a>b){
return 1;
} else {
return 0;
}
}

var hMain = lc.Home.promotions.filter(function(item) {
return (item.slot=='home_main');
});

hMain[0].items.map(function(item) {
return item.comicId;
}).sort(compare);

fallroot

이 문제를 낸 이유는 콘텐츠팀에서 입력한 데이터에 오류가 있어서 찾아야 할 때가 종종 있기 때문입니다. 그러면 홈페이지로 들어가 개발자 콘솔을 열고 현재 데이터를 찾을 때가 많은데 이 문제와 같은 검색을 할 경우가 잦아서 익숙해지시라 낸 문제입니다.

일단 compare 함수는 사용할 필요가 없어요. 만약 명시적으로 저렇게 비교하고 싶으면 아래와 같이 하면 되고요.

Array.sort(function(a, b) {
return a - b;
});

나머지는 잘 했네요. each, map, filter, reduce 등의 열거형 자료를 다루는 함수는 몸에 익숙해지는 게 좋아요.

lc.Home.promotions
.filter(function(p) {return p.slot == 'home_main'})[0]
.items.map(function(i) {return i.comicId})
.sort()
.toString()

추가로 Array#sort 함수의 기본 비교는 어떤 데이터형으로 하는 지 알아보세요. 문자열, 숫자를 비교할 때 각각 어떻게 해야 하는지도요.

자바스크립트 & 제이쿼리 (jpub) – 6장 Javascript event

이벤트 종류

웹을 탐색하는 동안 브라우저에서 발생할 수 있는 이벤트

UI Event

사용자가 웹 페이지가 아닌 브라우저의 UI와 상호작용할 때 발생
– load: 페이지가 가지고 있는 모든 요소(이미지, 스크립트 및 광고)가 전부 로드되었을때만 발생. script요소를 html밑에 정의하면, DOM은 스크립트를 실행하기에 앞서 폼 요소를 먼저 로드하므로 이 경우 load이벤트의 발생을 기다릴 필요가 없다.window.addEventListener('load', setup, false);
– unload: 웹 페이지가 언로드될 때 (주로 새로운 페이지를 요청한 경우)
– error: 브라우저가 자바스크립트 오류를 만났거나 요청한 자원이 존재하지 않는 경우
– resize
– scroll: 전체 페이지 뿐만 아니라 특정 요소(스크롤바 가진 textarea)에서도 적용

Keyboard Event

  • input: input/textarea요소 값이 변경될 때
  • keydown: 사용자가 키를 처음 눌렀을 때 (키가 눌린 동안은 계속해서 발생)
  • keypress: 사용자가 눌렀던 키의 문자가 입력되었을 때
  • keyup: 키보드 키 눌렀다 뗄 때. 화면에 문자가 나타난 이후에 발생

이벤트 순서

  1. keydown – 키 누름
  2. keypress – 키 눌렀거나/누르고 있는중이라 페이지에 문자 입력되고있다.
  3. keyup – 키 뗌

Mouse Event

  • click: 마우스 버튼을 눌렀다 뗄 때
  • dblclick
  • mousedown: 마우스 버튼을 누르고 있을 때
  • mouseup: 눌렀던 마우스 버튼을 뗄 때
  • mousemove: 마우스를 움직일 때(터치스크린X)
  • mouseover: 요소 위로 마우스를 움직였을 때(터치스크린X)
  • mouseout: 요소 바깥으로 마우스를 움직였을 때(터치스크린X)

Focus Event

  • focus / focusin: 포커스를 얻었을 때
  • blur / focusout: 포커스를 잃었을 때

Form Event

  • input: 또는요소 값이나 contenteditable특성을 가진 요소 값이 변경되었을 때
  • change: 선택 상자, 체크박스, 라디오 버튼의 상태가 변경되었을 때
  • submit: 사용자가 (버튼이나 키를 이용하여) 폼을 제출할 때 – 사용자가 폼에 입력한 값을 서버로 전달하기에 앞서, 입력한 값이 올바른 것인지 검사할 때 주로 사용됨.
  • reset
  • cut: 사용자가 폼 필드의 콘텐츠를 잘라내기 했을 때
  • copy
  • paste
  • select: 사용자가 폼 필드에서 텍스트를 선택했을 때

요소에 이벤트를 바인딩하는 세 가지 방법

  1. HTML 이벤트 핸들러
    • 그다지 권장하진 않음. 예전 코드에서 종종 사용.
    • <a>
    • HTML 이벤트 핸들러 특성은 저 위 이벤트 이름과 동일하며, 앞에 on을 붙여 사용.
      • a요소는 onclick, onmouseover…, form요소는 onsubmit, input은 onkeypress, onfocus 등등
  2. 전통적인 DOM 이벤트 핸들러
    • 장점: 모든 주요 브라우저에서 지원.
    • 단점: 이벤트별로 단 하나의 함수만 바인딩 가능
function checkUsername(){
    ...
}
var el = document.getElementById('username');
element.onblur = checkUsername;//(함수이름 괄호는 생략)
- (함수를 호출할 때, 함수 이름 뒤에 괄호를 지정하면 JS해석기는 "이 코드를 지금 실행하라"란 의미로 해석.)

3. 이벤트 리스너
– 현재는 이 방법을 제일 많이 사용.
– 하나의 이벤트로 여러 개의 함수를 실행할 수 있다.
– IE8에선 지원 안함. attachEvent로 구현한다.

function checkUsername(){...}
var el = ...;
el.addEventListener('blur', checkUsername, false);  //버블링:false, 캡쳐링:true

//매개변수를 가진 이벤트 핸들러
el2.addEventListener('blur', function(){
    checkUsername(5);   //이벤트핸들러나 리스너를 지정할 때, 함수 이름 다음에 괄호를 사용할 수 없으므로 인수를 전달해야 하는 경우엔 우회 방법이 필요. - 익명함수
}, false);

이벤트 객체

  • 이벤트 객체는 이벤트가 발생할 떄마다 해당 이벤트에 대한 유용한 정보를 제공.
    • 이벤트를 발생시킨 요소
    • keypress 이벤트가 어떤 키에 의해 발생했느지에 대한 정보
    • 사용자가 뷰포트 내의 어떤 요소를 클릭해서 click이벤트가 발생했는지에 대한 정보
  • 이벤트 객체는 이벤트 핸들러나 리스너로 지정된 함수에 전달된다. 전달받기 위한 함수의 매개변수 이름은 보통 e를 사용한다. (일부 개발자들은 error객체 참조할때도 e라 한다. 헷갈 ㄴㄴ)
function checkUsername(e){
    var target = e.target; //이벤트가 발생한 요소를 가져옴.
}
el.addEventListener('blur', checkUsername, false);

function checkUsername2(e, minLength){  //매개변수 가짐
    var target = e.target;
}
el2.addEventListener('blur', function(e){
    checkUsername(e, 5);
}, false);

//IE 5~8 대응하기
function checkUsername3(e, minLength) {
    var el, elMsg;
    if(!e){
        e = window.event;
    }
    el = e.target || e.srcElement;
    elMsg = el.nextSibling;

    if(el.value.length이벤트 핸들러 함수 호출될때 어떤 요소에서 이벤트 발생했는지 알아내는 최고의 방법은 event객체의 target속성 참조하는 방법이다. 근데 this로도 참조 가능.

- `this.value.length` 처럼 받아올 수 있다.
- 근데 함수에 매개변수를 전달하지 않는(그래서 익명 함수에 의해 호출되는 것이 아닌) 경우에만 제대로 동작.

# focus, blur
```javascript
function checkUsername(){
    var username = el.value;
    if(username.length<5){
        elMsg.className = 'warning';
        elMsg.textContent = "이름이 너무 짧습니다.";
    } else {
        elMsg.textContent = "";
    }
}

function tipUsername() {
    elMsg.className = 'tip';
    elMsg.innerHTML = '이름은 다섯 글자 이상이어야 합니다.'
}

//username입력 필드가 포커스를 받거나 잃으면 위의 함수를 호출하도록 한다.
el.addEventListener('focus', tipUsername, false);
el.addEventListener('blur', checkUsername, false);

이벤트가 발생한 지점

  1. 스크린
    • screenX, screenY
    • 모니터 화면 전체를 대상
    • (브라우저가 아닌)화면의 왼쪽 상단 모서리를 기준으로 현재 커서 위치 알려줌
  2. 페이지
    • pageX, pageY
    • 전체 페이지를 기준으로 현재 커서 위치
    • 페이지 최상단은 viewport를 벗어나 있을 수 있기 때문에 커서가 같은 위치에 있다 하더라도 페이지 좌표와 클라이언트 좌표가 다를 수 있다.
  3. 클라이언트
    • clientX, clientY
    • 브라우저 뷰포트 기준으로 커서 위치 알려줌
    • 스크롤 해서 상단 안보이더라도 클라 좌표는 영향 안받음

변형 이벤트

  • DOMNodeInserted: 돔트리에 노드 추가될때. (appendChild(), replaeChild(), insertBefore()메서드를 호출하면 발생한다.)
  • DOMNodeRemoved: 제거될때
  • DOMSubtreeModified: 변경되면
  • DOMNodeInsertedIntoDocument
  • DOMNodeRemovedFromDocument

HTML5 이벤트

  • DOMContentLoaded: 돔트리가 형성될때.더 빠르게 로드되는 것처럼 보일 수 있다. 그러나 스크립트 로딩이 완료되기를 기다리지 않아 미처 로딩되지 않은 스크립트에 의해 생성되는 요소들이 DOM트리에 반영되지 않을 수 있다(window나 document객체 통해 처리)
  • hashchange: URL의 해시가 변경될 때(전체 창이 새로 고쳐지는 것이 아니라)발생. ajax이용해 콘텐츠 로드하는 경우에도 사용.
  • beforeunload: window객체에서 발생. 페이지가 언로드 되기 전에 발생.(ex. 사용자가 폼 데이터를 변경한 상태에서 저장 않고 다른 페이지로 이동하려는 경우에 알림)