2018년 12월 11일 화요일

[javascript][prototype] 자바스크립트 프로토타입 맛보기 -02

function Car() {
  this.wheel = 4;
  this.beep = "BEEP";
}

Car.prototype.go = function () {
alert(this.beep);
  };

function Truck() {
  this.wheel = 6;
  this.beep = "TRUCK!!";
}

Truck.prototype = new Car();

function SUV() {
  this.beep = "SUV!!";
}
SUV.prototype = new Car();

var truck = new Truck(),
suv = new SUV();

console.log(truck.wheel);  // 6
console.log(suv.wheel);  // 4
console.log(truck.beep);  // TRUCK!!
console.log(suv.beep);  // SUV!!
Car라는 객체를 프로토타입에 넣어보니
Truck과 Suv 는 go라는 함수를 공통으로 사용할 수 있으며, 특히 SUV의 경우 wheel을 정의하지 않았지만
Car에 정의되어 있는 wheel = 4로 바퀴갯수 프로퍼티를 가질 수 있게 되었다.

[js] Object.create을 사용한 자바스크립트 상속 - 01

// 실제로는 Object.create 이라는 함수가 있다. 더글라스 크락포드가 주장했던 함수형태

Object.my_create = function(o) {
  function F() {};
  F.prototype = o;  // O는 처음부터 prototype역할을 하는 녀석일 것이다.
  return new F(); 
}

function Person(name) {
  this.name = name;
}

Person.prototype = {
  yell: function() {
    alert("My name is " + this.name);
  }
};

var u = Object.my_create(Person.prototype); // prototype을 넘기는 것을 주의하자.

u.name = "U";
u.yell();  // alert
/*
이렇게 Object.create 함수를 통해 객체를 생성하면 
개발자가 new 키워드를 사용하지 않고 함수 호출로 객체가 생성된다.

new 키워드를 사용할 때와는 달리 전체적으로 소스에 생성자의 개념이 사라지고 (new가 없으니까)
객체의 인스턴스와 인스턴스 간의 상속을 강조하는 것이 Object.create의 특징 (???)
*/

[js] 자바스크립트 상속기존의 자바스크립트 상속과 그 이면 - 00

function Person() {
  this.name = "anomymous";
  this.sayHello = function() {
    console.log(this.name + "!!");
  };
}

function Nam() {
  this.name = "Nam";
}
Nam.prototype = new Person();

var nam = new Nam();
nam.sayHello();
console.log(nam instanceof Nam);  // true
console.log(nam instanceof Person);  // true

console.log(nam.constructor);  // ?? Nam이 아니라 Person!!
/*
생성자 속성은 객체가 가지고 있는 것이 아니라. 프로토타입이 가지고 있다.
객체는 내부 링크로 프로토타엡에 있는 생성자 속성을 참조한다.

지금 Nam프로토타입은 
그런데 new Person()으로 원래 객체(여기선 Nam)의 생성자를 가지고 있는 프로토타입을 덮어씌우면
Nam의 생성자는 연결고리를 잃는다. (원래 Nam의 생성자는 function Nam() {...} 을 가리키고 있어야 한다.)

따라서 nam.constructor를 실행하면 [Function: Person] 이 나온다.
뭐 잘 작동하기는 하지만 연결이 끊어진다는 것은 좋은 것이 아니다.
*/


괜찮은 링크.
https://medium.com/@bluesh55/javascript-prototype-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-f8e67c286b67

2018년 11월 6일 화요일

[java][thread][unsafe] 자바가 숨겨놓은 악마의 열매 sun.misc.Unsafe - 1

sun.misc.Unsafe

이름부터 강력함을 뽐내는 이 클래스는 아무나 쓸 수 없는 녀석이다.
사실 이 강력함은 우리를 다치게 할 수 있다. 그 어떤 강력한 것도 항상 제물이 필요하다.

열정을 더 불태우기 위해 내 몸을 불 속에 몸을 던지는 행위와 같이
이 세상 모든 뜨거운 것에는 장작이 필요하다.

Unsafe가 그러하다. 자바를 더욱 핫하게 만들어줄 이 녀석은 사실 우리는 쓰지 못하도록 되어 있다.
이 강력한 힘은 사용자가 쓰지는 못하도록 만든 것이다.
더 나아가, 필자의 Eclipse에서는 아예 존재하지 않는 것처럼 보인다.

너무 강력하고 위험하기 때문에, 아예 import조차 못하도록 막은 것이다. (해당 설정을 바꾸면 가능하다)

자바에서도 C와 같은 강력한 기능을 사용하려면 JNI를 이용하여 C언어 개발을 해야 할 것이다.
하지만 C를 모르고 알고 싶지도 않은 사람이 있을 것이다. 하지만 java.misc.Unsafe를 이용하면 Java API를 이용하여
low-level 프로그래밍을 할 수 있게 해준다.

일단 Unsafe를 내가 찾게 된 연유를 보자. 나는 AtomicInteger라는 녀석의 구현을 보고 싶었다.
어느때와 같이 AtomicInteger에서 숫자를 변경하는 메소드를 보았으나. 내 눈앞에 보이는건 Unsafe클래스였다.
안으로 들어가도 바이트코드만 보이는 것을 보고. 뭔가 심각한 녀석임을 눈치챘다.

녀석은 생성자가 private으로 만들어져 있다. 그리고 싱글턴 인스턴스가 private으로 존재한다. 그러므로 getUnsafe라는 녀석이 있는 것으로 봐서
녀석을 실행시키면 된다고 생각했다. 하지만 예외만 던져질 뿐이었다. 왜 그러한지 한 번 둘러보자.
public static Unsafe getUnsafe() {
  Class cc = sun.reflect.Reflection.getCallerClass(2);
  if (cc.getClassLoader() != null)
    throw new SecurityException("Unsafe");
  return theUnsafe;
}
여기서 볼 수 있듯이 일단 theUnsafe라는 녀석이 싱글턴 인스턴스다.
그리고 눈에 보이는 이상한 것들이 있는데 바로 sun.reflection.Reflection 이다.
이녀석은 현재 스레드의 메소드 스택을 확인하여 주어진 숫자 만큼 call-stack-frame 밑으로 내려가서 해당 메소드의 클래스를 리턴한다.
(이 구현을 변경될 수도 있다) 지금 숫자에는 2가 들어있으니까 콜스택의 3번째 값을 가져온다.

index 0. Reflection (getCallerClass)
index 1. Usnafe (getUnsafe)
index 2. Unsafe를 실행하는 나의 어플 내에 있는 메소드

이게 index 2 값을 가져와서 getClassLoader를 실행시킨다. 소스 상에서는 null이어야 한다.
null 레퍼런스는 HotSpot virtual machine 위에 bootstrap class loader를 가리킨다. (이 내용은 {@link Class#getClassLoader()}에 문서화 되어 있다.

아니면 예외를 던진다. (좀 더 자세한 내용은 참고 깃허브 참고)


하지만 트릭은 언제나 존재한다.

바로 이렇게 콜스택으로 체크 하는 방식이 아주 대충 디자인 된 것이라고 한다.
바로 리플렉션의 사용을 막지 않았기 때문에 바로 가져오면 된다.
public void getUnsafe() throws Exception {
  Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
  theUnsafe.setAccessible(true);
  Unsafe unsafe = (Unsafe) theUnsafe.get(null);
  System.out.println(unsafe);
}
이렇게 하면 되지만 안드로이드에서는 Unsafe클래스의 이름이 "theUnsafe"가 아니라. THE_ONE이라는 이름으로 불린다고 하니 이런 코드는 플랫폼에 의존적이다.
다르게 가져와보자.
public Unsafe getUnsafeInstance() throws Exception {
  Constructor unsafeConstructor = Unsafe.class.getDeclaredConstructor();
  Unsafe unsafe = unsafeConstructor.newInstance();
  System.out.println(unsafe);
  return unsafe;
}

좋다. 이렇게 가져와 봤다.
이게 얼마나 위험하기에 이렇게 힘겹게(?) 가져와야 하는 것일까?

해당 내용은 다음에 만들 이야기

[java][thread][unsafe] 자바가 숨겨놓은 악마의 열매 sun.misc.Unsafe - 2

에서 확인해보자.

2018년 11월 5일 월요일

[java][thread] volatile 대체 어디서 쓸만한 걸까?

참고 사이트 (내 깃허브): https://github.com/ssisksl77/java-demo/tree/master/src/main/java/concurrent/volatile_test

volatile은 멀티스레드에서 값들을 캐시하지않고 변경된 내용을 바로바로 가져올 수 있게 해준다.
오! 그렇다면 아무 곳에나 volatile만 넣어준다면 마법처럼 동기화가 되면서 공유상태를 사용할 수 있는 것일까?
아래 소스코드와 결과를 보면 그렇제 않은 것 같다.
package volatile_test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class VolatileTest1 {
 private volatile static int counter = 0;
 
 public static void main(String[] args) {
  Runnable r1 = () -> { System.out.println(counter); counter++;};
  
  ExecutorService es = Executors.newCachedThreadPool();
  
  for(int i = 0; i < 10; i++) {
   es.execute(r1);
  }
  
  es.shutdown();
//              OUTPUT
//  0
//  0
//  0
//  3
//  4
//  5
//  6
//  7
//  8
//  9

 }
}
0이 3번이나 나왔다. 왜그럴까? 특이한 것은 결과적으로 +1이 잘 되었지만 조회가 잘 안되었다는 것인데 다시 한 번 해보자.
0
0
0
0
0
0
6
6
8
8
전혀 다른 값이 나왔다. 그 말은 값이 달라졌다는 것이다. volatile을 사용한다고 동기화가 되는 것이 아니다. 읽기-수정-쓰기 가 동기화가 되야 하는 것이다. 그렇다면 volatile은 언제 써야 할까? 아래와 같은 경우를 보자.
package volatile_test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class VolatileTest2 {
 // 아래 내용을 보자. 과연 잘 돌아가는 경우가 얼마나 있을까?
 private static boolean flag = true;
 
 public static void main(String[] args) {
  Runnable r1 = () -> { 
   while(flag) {
     // 여기에 막히게 된다. 
   }
   System.out.println("bye");
  };
  
  Runnable r2 = () -> { System.out.println("flag false start"); flag = false;};
  ExecutorService es = Executors.newCachedThreadPool();
  
  for(int i = 0; i < 10; i++) {
   es.execute(r1);
  }
  es.execute(r2);
  
  es.shutdown();

 }
}
여기서는 전혀 돌아가지는 않는다. 이것은 volatile의 부재일 수도 있지만, 컴파일러 마다 최적화를 하면서 결과값이 다르게 나올 수도 있다고 한다. 여튼 위 내용은 현재 flag를 false로 변경했지만 먹히지 않는다. 이때 volatile을 넣어보자.
package volatile_test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class VolatileTest3 {
 // 이럴때 volatile로 바꾸는 것만으로 효과가 있다.
 private volatile static boolean flag = true;
 
 public static void main(String[] args) {
  Runnable r1 = () -> { 
   while(flag) {
    // System.out.println("hi");
   }
   System.out.println("bye");
  };
  
  Runnable r2 = () -> { System.out.println("flag false start"); flag = false;};
  ExecutorService es = Executors.newCachedThreadPool();
  
  for(int i = 0; i < 10; i++) {
   es.execute(r1);
  }
  es.execute(r2);
  
  es.shutdown();

 }
}

2018년 10월 29일 월요일

[python] 월별로 난수 생성하기

파이썬에는 아쉬운게 timedelta에 month를 더하는 것이 없다. 다른 유틸을 받아서 사용하면 된다고 하는데 이렇게 해도 잘 되는 것 같다.
import random
import string
import csv
import datetime
import calendar

random_numbers = set()
for _ in range(120):
res = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(16))
random_numbers.add(res)

def add_months(sourcedate, months) -> datetime.date:
month = sourcedate.month - 1 + months
year = sourcedate.year + month // 12
month = month % 12 + 1
return datetime.date(year,month,1)


somedate = datetime.date(2018, 4, 1)
with open('random_number.txt', 'w', newline='\n') as f:
w = csv.writer(f, delimiter=' ', quoting=csv.QUOTE_NONE)
for idx, num in enumerate(random_numbers):
w.writerow([add_months(somedate, idx).strftime('%Y-%m'), num])


# print(len(random_numbers))

[codility][python] max counter

codility max counter

https://app.codility.com/demo/results/trainingUBUCBJ-RVE/

def solution(N, A):
  res = [0] * N
  max_counter = 0

  for a in A:
    if a <= N:  # N카운터 존재
      res[a-1] +=1  # 카운터 올림
      if max_counter < res[a-1]: # max_counter 보다 크면 현재 카운터를 tmp_max로 변경
        max_counter = res[a-1] 
    else: # max counter 실행
      for i in enumerate(res):  # 전부 max_counter로 덮어씌운다.
        res[i] = max_counter
  return res
빅오노테이션이 O(MxN) 인 관계로 이중포문에서 하나를 없애야 한다.
# N 카운터가 있음. 0으로 세팅
# max counter : 모든 카운터들이 아무 카운터의 최대 값으로 세팅됨.

# A[K] = X 이면, K오퍼레이션은 X를 증가시킨다.
# -> 값이 X면 X를 증가시킴 (X범위 1<=X<=N)
# A[K] = N + 1 이면 K는 max counter  (??? K가 N보다 크면 max??)
# 아아아 max counter라는 걸 실행함!!!

def solution(N, A):
  res = [0] * N
  max_counter = 0
  tmp_max = 0
  for a in A:
    if a <= N:  # N카운터 존재
      if max_counter > res[a-1]:  # 1 max_counter가 더 크면 max_counter가 갱신된 것
        res[a-1] = max_counter  # 2 max_counter 값으로 변경해준다.
      res[a-1] +=1  # 3 그리고 그 다음에 카운터 시킨다
      if tmp_max < res[a-1]:  # 4 tmp_max보다 크면 현재 카운터를 tmp_max로 변경
        tmp_max = res[a-1]

    else:  # max_counter 에 현재 tmp_max를 넣는다. (max_counter는 그때그때 실행할 것이다.)
      max_counter = tmp_max

  # 아직 max_counter가 변경 된 이후에 counter가 변경된 이력이 없으면 max_counter로 덮어씌워준다.
  # 물론 max_counter보다 작은 경우.
  for idx, _ in enumerate(res):  
    if (res[idx] < max_counter):
      res[idx] = max_counter

  return res

a = [3,4,4,6,1,4,4]
N = 5

print(solution(5, a))

[hackerrank][python]Journey to the Moon

hackerrank: Journey to the Moon


1st attempt

# Determine how many pairs of astronauts from different countries they can choose from.
# UN 연합은 달에 사람들을 보내려고 한다.
# 그들은 이 사람들이 서로 다른 나라였으면 한다.
# 당신은 두 쌍의 우주조종사 id 리스트를 받을 것이다.
# 각 쌍은 같은 나라 우주조종사 id의 두 쌍으로 이루어져 있다.
# - 얼마나 많은 조종사 쌍을 만들 수 있는지 말해라.

# n : number of astronaut
# p : the number of pairs
from collections import defaultdict

# 일단 연결된 것들을 만든다.
def dfs(graph, start):
  visited, stack = set(), [start]
  while stack:
    v = stack.pop()
    visited.add(v)
    # 해당 정점에 연결된 것들을 stack에 넣는다.
    # 방문한 것은 제외
    stack.extend(graph[v] - visited)
  # 연결된 것들을 리턴.
  return visited

def journeyToMoon(n, ast_pairs):
  graph = defaultdict(set)
  asts = set()
  # 그래프 연결...
  for a1, a2 in ast_pairs:
    graph[a1].add(a2)
    graph[a2].add(a1)
    asts.add(a1)
    asts.add(a2)
  
  # 고립된 애들이 있을 수 있나? 일단 받아놔... (있는듯...)
  iso_asts = set([i for i in range(n)]) - asts
  
  groups = []  # divied by contry
  while asts:
    ast = asts.pop()
    connected_asts = dfs(graph, ast)
    groups.append(connected_asts)
    # 한번 방문한 팀은 다시 방문하지 않는다.
    asts = asts - connected_asts
  
  for i in iso_asts:
    groups.append({i})
  
  idx1, idx2 = 0, 1
  group_sum = 0
  while idx1 < len(groups)-1:
    idx2 = idx1 + 1
    while idx2 < len(groups):
      group_sum += len(groups[idx1]) * len(groups[idx2])
      idx2 += 1
    idx1 += 1
 
  return group_sum
    
  
n, p = list(map(int, input().strip().split(' ')))
ast_pairs = []
for _ in range(p):
   astronaut = [int(a) for a in input().strip().split(' ')]
   ast_pairs.append(astronaut)
   
result = journeyToMoon(n, ast_pairs)
print(result)
def dfs(graph, start):
  visited, stack = set(), [start]
  while stack:
    v = stack.pop()
    visited.add(v)
    stack.extend(graph[v] - visited)
  return visited

def journeyToMoon(n, ast_pairs):
  graph = defaultdict(set)
  asts = set()
  for a1, a2 in ast_pairs:
    graph[a1].add(a2)
    graph[a2].add(a1)
    asts.add(a1)
    asts.add(a2)
  
  iso_asts = set([i for i in range(n)]) - asts
  
  groups = []  # divied by contry
  while asts:
    ast = asts.pop()
    connected_asts = dfs(graph, ast)
    groups.append(connected_asts)
    # 한번 방문한 팀은 다시 방문하지 않는다.
    asts = asts - connected_asts
  
  for i in iso_asts:
    groups.append({i})
  
  # 뒤에 추가된 것들을 따로 분리해야 한다. 그래야 추가된 녀석들이 만드는
  # 패턴을 알 수 있다.
  # A*B + A*C + B*C -- A*B + A*C + B*C -- A*B + (A+B)*C 
  # A*B + A*C + A*D + B*C + B*D + C*D 
  # - A*B + (A+B)*C (A+B+C)*D
  # A*B + A*C + A*D + A*E + B*C + B*D + B*E + C*D + C*E + D*E
  # - A*B + (A+B)*C + (A+B+C)*D + (A+B+C+D)*E 
  idx1, idx2 = 0, 1
  group_sum = 0
  tmp_sum = 0
  while idx1 < len(groups):
    group_sum += tmp_sum*len(groups[idx1])
    tmp_sum += len(groups[idx1])

    # group_sum += tmp_sum*(len(groups[idx1 + 1]))
    idx1 += 1
  
  return group_sum
    
  
n, p = list(map(int, input().strip().split(' ')))
ast_pairs = []
for _ in range(p):
   astronaut = [int(a) for a in input().strip().split(' ')]
   ast_pairs.append(astronaut)
   
result = journeyToMoon(n, ast_pairs)
print(result)

[javascript] 접근자 defineProperties를 이용한 생성자 설정.

function Person(name) {
this.name = name;
}
Person.prototype = {
  yell: function() {
    console.log("my name is " + this.name);
  }
}
/* 수정불가 */
var user = Object.create(Person.prototype, {
  name: {
    value: 'new name'
  }
})

/* 수정가능 */
user = Object.create(Person.prototype, {
  name : {
    value: 'new name2',
    configurable: true,
    enumerable: true,
    writable: true
  }
})

/* 접근자 활용의 예 */

Object.defineProperties(user, {
  firstName: {
    value: "Younghwan",
    writable: true
  },
  lastName: {
    value: "Yang",
    writable: true
  },
  fullName: {
    get: function() {
      return this.firstName + " " + this.lastName;
  },
  set: function(value) {
    var res = value.split(' ');
    if (res.length > 1) {
      this.firstName = res[0];
      this.lastName = res[1];
    } else {
      console.log('wrong format');
    }
  }
});

console.log(user.fullName);
user.fullName = "Hello world!";
console.log(user.firstName); // Hello
console.log(user.lastName); // World!

2018년 9월 19일 수요일

재미에 대한 고민

세상에 모든 일에는 재미가 숨어있다고 믿습니다.
저는 재미있는 일보다는 해야 하는 일을 고민하고 살아갑니다.

재미는 그 안에 찾으려 합니다. 그것 또한 하나의 재미라고 자위합니다.

하지만 대부분 찾지 못하며 그것이 우리 대부분 사람들의 현실이겠지요.
재미가 없어도 어쩝니까. 이것이 내가 해야할 일인데 말입니다.

때로 재미는 그 안이 아니라 밖에 있기도 합니다.
가족, 취미 등으로 다른 재미를 찾는 것입니다.
그것이 더 쉬운 방법이라고 생각합니다.
그러니 앞만 보지말고 주위를 둘러봐야할 것 같습니다.

그때까지 우리의 의식이 깨끗하길 바라며
당신의 선택이 옳았음을 깨닫는 알았을 때
온전히 기뻐하며, 슬퍼하며
맑은 눈물을 흘리시길 바라며

2018년 9월 18일 화요일

[리뷰] 개발자라면 한번쯤은 들어봤지만 무시했을 [처음배우는암호화]를 읽고

[처음배우는암호화]를 읽고


웹 개발자로서, 암호화에 대해 많은 생각을 할 시간은 없지만 최소한의 지식이 필요함은 항상 느끼고 있었다.
특히 TLS라는 녀석은 아는 거라곤 버전이 있다는 점.
개발을 할 때, TLS버전을 숙지하고 보내야 한다는 점 정도밖에 몰랐다.

이 책은 암호학 고수로 만들어 주진 못하지만
서냥개 3년이면 풍월읊는 정도는 되게 해준다. 완벽한 이해는 할 수 없어도 이게 뭔지 그게 뭔지 감을 느끼게 해준다.

웹 개발자로서 암호에 대해 깊게 생각할 일이 아마 남은 시간 동안 없을 지도 모른다.
아마 쓸모 없는 지식일지도 모른다.

하지만 책은 결과뿐만 아니라 과정 안에도 즐거움이 있으니, 이 책을 읽는 동안 꽤 즐거웠다.
가끔 이 책을 읽으면서 수학공식 같은 것들이 나온다.
무시해도 될 정도... 라고 생각한다. 모르면 그냥 넘어가도 된다고 생각한다.

얇고 간결한 책이며, 암호학에 대해 진지하게 공부하는 분들보단 처음 시작하는 분들 또는 암호학에 대해 어느정도 귀동냥을 하고 싶은 분들에게 추천한다.

[리뷰] 피그말리온을 읽고 (조지 버나드 쇼 지음)

피그말리온을 읽고



열린책들의 [피그말리온]을 읽었다.

피그말리온의 뜻도 모른체로 글을 읽기 시작하였는데, 그래서 더 좋았던 것 같기도 하다. 피그말리온이라는 이름을 알았다면 이 책의 내용은 초중반의 내용은 다 이해될 정도였을 것 같기도 하다.

리뷰 하기 전

피그말리온은 신화의 인물이다.
조각가라는 직업을 가지고 있던 그는 자신이 조각한 여인을 사랑하게 되어 종단에는 그 여인과 결혼을 하는 인물이다.
여기서 중요한 것은 자신의 창작물을 사랑하게 된다는 것이다.

예술에 대해 잘 모르지만, 조각가의 마음을 한 번 상상해보자면 창작을 할 때, 자신이 상상하던 것, 원하는 것을 만들어 하고 싶을 것이다.
그것은 자신이 가지고 있지 않은 무언가일 것이다. 욕망은 부족함에서 오는 것일 것이니까.
하지만 창작을 하고나서도 그것이 자신이 원하는 것인지 어떻게 알 수 있을까?

피카소는 예술이 거짓이라 말했다. 그리고 그 거짓을 이용해서 진실을 투영하게 해주는 것이며, 그 거짓을 잘 만들어서 대중을 설득시키는 것이 예술가의 일이라 하였다. (내맘대로 발번역, 레퍼런스 원문참고 요망)

플라톤의 향연에서는 "오~ 이 세상이 그 누구보다 아름다운 사랑의 신 에로스여~" 라는 말에 소크라테스가 했던 말이 어렴풋이 기억에 남는다.
사랑의 신이라는 것은 사랑을 원하는 신일 것이다.
사랑은 아름다운 것이 맞는가? 맞다면 그 반대의 추함은 원하지 않을 것이다.
아름다움은 내적 아름다움도 있고, 외적 아름다움도 아름다움이라 할 것이다.

아름다움을 추구 한다는 것은 더 아름다워지고 싶어 하거나, 지금 가진 아름다움을 계속 쟁취하기 위해 노력하는 것일 것이다.
사랑의 신 에로스는 자신이 더 아름다워지고 싶어하거나, 지금 가진 아름다움을 계속 쟁취하기 위해 노력할 것이다.
에로스는 추녀일 수도 있다?


뭐 이런 이야기 였던 것같다. 그 뒤에 내용이 기억이 잘 나지 않지만
중요한 것은 욕망은 부족함에서 오는 것이라는 것이다. 그것이 건전하건 건전하지 않건 말이다.

때로 그 욕망은 저 위의 사랑의 신처럼 끝이 없을 것이다.
도올 선생은 한 강의에서 이런 말은 했다.
단어가 있기 때문에 욕망한다. 그 단어를 원하기 때문에 끝이 없다.
예를 들어,
돈, 사랑, 믿음

이 단어를 원하는 것이다. 이 단어는 끝이 없고, 얻으면 얻을 수록 그 단어의 크기는 커져서는 처음 자신이 만들었던 단어(그 욕망)이 자신을 잠식할 것이다.
그 단어가 당신을 현혹하고, 나를 현혹하고, 결국 내가 원했던 것이 그 단어, 그 개념, 이 되는 것이다.

어쩌면 그것이 행복한 삶일까?
저 위에 있는 피그말리온의 삶이 나는 그리 좋아보이지 않는다.
결혼을 하려고 아름다운 여인을 창작하였을까? 아닐 것이다.
예술가가 저 여인 안에 갇히려고 예술을 배우진 않았을 것이다.
그는 조각가였다. 조각을 하는 자였다. 그는 피카소의 말처럼 조각이 거짓임을 알고 있어야 했다.
그는 자신의 만든 조각에 눈이 멀어, 신에게 기도하고, 그 기도 부름에 신은 여인을 살아있게 하였다.

그렇다면 여인은 무엇인가?
영혼이 있다면 어떤 영혼인가? 피그말리온이 원하는 영혼이 그 안에 들어 있을까?
피그말리온을 사랑하지 않는 여인이었다면 어땠을까?
신은 피그말리온을 사랑하는 영혼을 불어 넣었던 것일까?
아니면 그저 순종하는 여인을 만들었던 것일까?

그는 결국 그것이 조각품이었다는 것을 알아야 한다.
만약 정말 조각품이 살아숨시는 무언가를 원했다면, 그녀를 홀로 설 수 있게 해줘야 한다.
피그말리온은 그저 살아숨쉬는 조각품을 원했던 것이 아닐까?
그는 아마 이것이 그저 조각품임을 알고 있었을 것이다.
아름다운 조각품을 만드는 조각가였으니 말이다. 자신의 본분을 잃을리 없다.
하지만 현실을 부정하고 싶었을 것이다.
조각품의 이름은 갈라테아, 거품의 요정을 뜻한다.

피그말리온으로 돌아오자.

책의 리뷰로 돌아와서,
조지 버나드 쇼는 이 작은 책으로 많은 것을 담았다.

귀족 사회 비판이나, 당시 빈부의 격차라던가 그런 것들을 잘 조명했다고 한다.
그것들은 시간이 지나면 저절로 붙는 수식어일 수 있다. 오래된 소설 중에 저런 말이 적혀있지 않은 소설이 어디있는가.
분명 그는 피그말리온이라는 단어에 집중했을 것이다. 그러니 피그말리온에 집중해보자.


한 신사가 한 여인을 귀족의 세계로 오도록 만든다. 그녀에게 귀족의 말투를 알려주고, 귀족처럼 입혀준다.
그리고 그녀를 다른 귀족들에게 보여줌으로써 가르침의 결과물을 확인받는다.
신사가 생각하기에는 그 여인을 새 사람으로 만들었다고 생각했을 것이다.
그녀는 신사 헨리 히긴스의 창작물인 것이다. 그리고 헨리 히긴스는 피그말리온 일 것이다.

헨리 히긴스는 창작물을 사랑했을까? 맞다 사랑했으나, 그녀를 창작물로서 사랑하는 것이었다.
그것은 진정 그녀를 위한 것이 아니었다. 게다가 그녀는 조각품이 아니다. 인간이다. 그녀의 이름은 일라이자 이다.

결국, 그녀는 자신의 삶을 개척하기 위해 떠난다.

후일담

이후에 후일담이라는 내용이 추가되었다고 한다. 왜냐하면 이 희극이 런던에서 공연을 할 때, 일라이자가 부캐를 던지는 장면을 넣었다고 한다.
조지 버나드 쇼는 그 결말을 아주 싫어했으며 뒤에 결말을 덧붙인 것이다. (이 점에서 조지 버나드 쇼가 좀 졸렬했다고 생각한다. 자신의 창작물이 파생되어 가는 것을 거부하는 피그말리온 같은 사람 같으니라고)
대중들은 이 둘이 다시 만나기는 판타지가 이뤄지길 바랬을까?
결국 일리아지와 헨리 히긴스가 만나는 결말이 있는 영화가 만들어졌을 때, 영화는 상업적으로 대성공을 거두고, 1938년 아카데미 시상식에서 각색상(Academy Award for Best Adapted Screenplay)을 받았다고 한다.(레퍼런스 2 참고)
(요즘도 그러지 않은가? 나이많은 남자와 나이적은 여자가 이루어지는 로맨스를 욕하는가하면 그런 판타지를 원하고 본다.)


후일담에 대해서 좀 이야기 해보자. 진짜 결말을 내기 위한 변명같은 느낌이 강하다. 그럼에도 글을 아주 잘쓴다.
후일담이야 말로 조지 버나드 쇼가 생각했던 이 작품의 결말을 날것으로 보여준다.
왜 이 글을 썼는지 이해해달라고 외치는 것 같았다.

일라이자가 자신이 원하는 남자와 결혼하여 꽃집을 차리고 행복해한다는 내용이다.
하지만 안타깝게도 그녀는 자신만의 힘으로는 살아남지 못한다. 나는 그녀가 당차게 홀로 힘으로 살아남기를 바랬지만 그렇지 못했다.
못살아도 행복하기를 바랬지만 그러지 못했다.
물론 변명거리는 많다.
그녀는 천재가 아니다. 또한 하층민의 교육은 제대로 되지 않았을 것이다. 교육을 받았음에도 영어발음이 좋지 않다는 것이 그 증거 중 하나이다.
그렇기 때문에 그녀가 할 수 있는 일은 많지 않다. 그렇다고 남편이 비상한 것 또한 아니다. 멋진 교육을 받지도 못했다.

일라이자 직간접적으로 피그말리온에게 수 많은 도움을 받는다.
그녀는 계속 손을 벌려 자괴감이 든다고 써있지만, 아낌없이 주는 피그말리온이 있다는 것은 얼마나 행복한 일인가.
그가 없었으면 당장 다시 거리로 꽃을 팔았어야 할지도 모른다.
역시 못배워서 그런가 싶기도 했다. 자괴감이라니...
사람은 때때로 자신이 불쌍해져야 특별해진다고 생각하는 경향이 있다.

원래 자립은 힘든 것이다. 돈은 원래 벌기 힘든 것이다.
무일푼에서 중산층으로 가는 것은 원래 힘들었다. (그전엔 더 힘들 었을 것이지만)
결국 히긴스와 그의 동료가 없었으면, 일라이자의 자립은 상상도 못했을 것이다.

창작물을 외면할 수 없는 그들이었을 것이다.

feminism

이 글이 페미니즘을 위해 글을 읽힌다고 들었다. 그렇다. 당찬 여자는 항상 멋지다.
그녀는 꽃 한송이를 팔 때도 아주 당찼다.
하지만 그렇게 보기에는 여기 모든 것이 피그말리온의 도움이 없이는 만들어질 수 없는 것들이었다.
그녀는 더 이상 길거리에서 경찰에게 잡혀갈까봐 걱정하지 않는다.
그녀는 이제 길거리에서 꽃 한송이를 팔려고 신사들을 졸졸 따라다니는 것이 아니라 꽃집 사장이다.
이 모든 것이 피그말리온으로 인해 시작되었고 완성되었다.
나는 그녀가 좀 더 자신에게 기회를 준 이에게 예를 갖췄으면 좋겠다 싶었다.

마치며

피그말리온은 당대의 계급사회를 보기좋게 풍자했으며, 또 경쾌함을 잃지 않았다.
그는 시대가 원하는 케릭터를 만드는 척하면서 보기좋게 비꼬았다. (적어도 원작에서는...)
시간이 흘렀지만 그의 위트는 아직도 유효하다.
멋진책이다.

레퍼런스

1. picaso's quote
2. Pygmalion