React 시작하기

React Create App 설치하기

1
npm install -g create-react-app

React Create App 을 통해 프로젝트 생성하기

1
create-react-app react_boot_template --scripts-version=react-scripts-ts

개발 의존 모듈 설치하기

1
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react react-hot-loader webpack webpack-dev-server

글로벌 모듈 설치하기

1
sudo npm install -g babel-cli

필요 디렉토리 만들기

1
mkdir server server/routes && touch public/index.html server/main.js server/routes/posts.js src/App.js src/index.js webpack.dev.config.js

webpack 설정하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module.exports = {
// 가장 처음 읽을 스크립트파일
// 여기서부터 import 되어있는 다른 스크립트를 불러온다.
entry: './src/index.js',

// 파일을 합치고 ./public/bundle.js 에 저장한다.
output: {
path: __dirname + '/public',
filename: 'bundle.js'
},

// ES6 문법과 JSX 문법을 사용한다
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/,
query: {
cacheDirectory: true,
presets: ['es2015', 'react']
}
}
]
}
};

Functional Programming with Javascript

What is the functional programming

함수형 프로그래밍은 자료 처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임의 하나이다. 명령형 프로그래밍에서는 상태를 바꾸는 것을 강조하는 것과는 달리, 함수형 프로그래밍은 함수의 응용을 강조한다.

수학적 함수와 명령형 프로그래밍에서 사용되는 함수는 차이가 있는데, 명령형의 함수는 프로그램의 상태의 값을 바꿀 수 있는 부작용이 생길 수 있다. 이 때문에 명령형 함수는 참조 투명성이 없고, 같은 코드라도 실행되는 프로그램의 상태에 따라 다른 결과값을 낼 수 있다. 반대로 함수형 코드에서는 함수의 출력값은 그 함수에 입력된 인수에만 의존하므로 인수 x에 같은 값을 넣고 함수 f를 호출하면 항상 f(x)라는 결과가 나온다. 부작용을 제거하면 프로그램의 동작을 이해하고 예측하기가 훨씬 쉽게 된다. 이것이 함수형 프로그래밍으로 개발하려는 핵심 동기중 하나이다.

여기서 가장 중요한 개념 중 하나인 pure function 이란 부작용이 없는 함수 즉, 함수의 실행이 외부에 영향을 끼치지 않는 함수를 의미한다. 때문에 pure function 은 병렬적인 연산이 가능하고, 스레드에 안전하다.

이러한 pure 함수는 언제나 같은 값을 반환함이 보장되기 때문에 아무런 제약없이 사용되어도 안전하며, 때문에 이러한 pure function 들은 다른 함수의 input 으로 제공되어도 안전하다. 이렇게 함수형 프로그래밍 에서는 함수 자체가 변수처럼 선언되고 input 으로 사용되는 등 변수와 같이 취급되는 fist class citizen이다.

이렇게 함수를 인자로 받는 함수를 higher order function 이라고 한다.

선언형 프로그래밍과 명령형 프로그래밍

example of imperative programming

1
2
3
4
5
6
7
var string = "This is the midday show with Cheryl Waters"; var urlFriendly = "";
for (var i=0; i<string.length; i++) { if (string[i] === " ") {
urlFriendly += "-"; }else{
urlFriendly += string[i];
}
}
console.log(urlFriendly);

example of declarative programming

1
2
const string = "This is the mid day show with Cheryl Waters" const urlFriendly = string.replace(/ /g, "-")
console.log(urlFriendly)

위 예제와 같이 선언형 프로그래밍에서는 모든 작업이 replace라는 선언아래 감추어져 있고, 개발자가 코드를 보았을 때 어떤일이 벌어지는지 매우 명확하게 알 수 있다.

code itself describes what is happening

hyperwallet

Hyper wallet 결제 방식

Payment fund 는 미리 준비된 카드나 은행 계좌로 옮겨진다.

요청에 따라 미래에 결제를 완료할 수 있다.

Client 객체를 통해 결제를 진행한다.

핵심적인 엔티티의 의미는 다음과 같다.

DestinationToken
For Portal solutions, provide a user-token

For Select solutions, provide a user-token

For Direct solutions, provide a bank-account-token

For Card solutions, provide a prepaid-card-token

Destination Token에 따라 계좌 혹은 유저 계정으로 돈을 보낼 수 있다.
var Hyperwallet = require(‘hyperwallet-node’);
var client = new Hyperwallet({ username: ‘testuser@12345678’, password: ‘myAccPassw0rd’ });

client.createPayment({
“amount”: “20.00”,
“clientPaymentId”: “DyClk0VG”,
“currency”: “USD”,
“destinationToken”: “usr-c4292f1a-866f-4310-a289-b916853939de”,
“programToken”: “prg-83836cdf-2ce2-4696-8bc5-f1b86077238c”,
“purpose”: “OTHER”
}, function(error, body) {
// handle response body here
});

expiresOn
When the payment will expire if unclaimed
curl -X “POST” “https://api.sandbox.hyperwallet.com/rest/v3/transfers" \
-u testuser@12345678:myAccPassw0rd \
-H “Content-Type: application/json” \
-H “Accept: application/json” \
-d “{
“clientTransferId”: “6712348070812”,
“destinationAmount”: “125”,
“destinationCurrency”: “USD”,
“notes”: “Partial-Balance Transfer”,
“memo”: “TransferClientId56387”,
“sourceToken”: “usr-ac5727ac-8fe7-42fb-b69d-977ebdd7b48b”,
“destinationToken”: “trm-e3af62b4-24d5-100f-a4eb-ada857b8fc30”
}”

Transfer 이란 Hyperwallet계좌에서 실제 계좌 혹은 카드로 돈을 전송하는 것을 의미한다.
sourceToken 엔티티는 대금의 출처를 의미한다. 선지급 카드 혹은 유저 계좌가 들어갈 수 있다.

싱가포르에서 한국으로 입금 혹은 한국에서 싱가포르로 입금이 가능한가?

hyperwallet에서 test를 진행하기 위하여 tutorial 에서 발급받은 program key 를 기준으로 테스트를 진행이 가능하다.
여기서 user를 생성하고 account를 연결하여 transfer 및 payment를 테스트 가능하다.
계좌를 입력하는 경우 iban 코드가 필요한데 이는 international bank account number로 각 계좌마다 존재한다. 하지만 국내 은행의 경우 이러한 iban 이 없는 경우가 ㅁ낳다.
Bank swift code는 각 은해마다 존재한다.

플랫폼사업자를 위한 stripe

Overview

stripe의 connect는 사업자가 사용자에게 과금을 하고 과금된 금액을 다시 서비스 공급자에게 제공하기 위한 플랫폼 서비스에 매우 적합한 기술이다. connect를 통해 과금, 인증, 서비스 공급자에게 대금 지불 등의 많은 일들을 한번에 처리 가능하다. striped의 connect는 다음과 같은 일련의 작업을 처리한다.

  1. 고객으로 부터 플랫폼으로 얼마의 돈이 유입되고 최종적으로 플랫폼의 서비스 공급자에게 어떻게 흘러가는 지를 정의한다.
  2. 플랫폼의 수수료를 책정한다.
  3. 결제 스케줄과 방법을 결정한다.
  4. 여러 종류의 stripe계정을 지원한다.

이를 위해 플랫폼 사용자는 stripe 계정을 연동하여야 한다.

프로세스의 흐름

  1. 고객으로 부터 결제를 진행 charges!
  2. 플랫폼에서 연결된 계정(서비스 공급자)으로 돈을 전달
  3. 서비스 공급자에게 대금을 지급(stripe 내의 asset을 실제 현금으로 전환, payout) payout!

활용현황

connect는 킥스타터와 같은 크라우드 펀딩 서비스와 shopify 등의 e commerce 플랫폼 등에서 사용되고 있다.

Creating charges

connected accound 에 대금 결제를 요청하는 세가지 프로세스이다.

  1. connected account에 직접 과금
  2. 특정 connected account에 전달이 되도록 과금
  3. create the charge on your platform account and separately transfer funds to the connected account

첫번째 방식은 connected account에 직접 과금을 수행하는 방식으로 유저와 마켓 사이의 단순 과금의 경우이며, 두번째 경우는 우버와 같이 고객이 서비스 공급자에게 대금을 지불하는 직접 지불 방식이다. 마지막으로 세번째 방식은 고객에게 부과한 대금을 자체적으로 보관 한 뒤에 훗날 서비스 공급자에게 일괄로 지급하는 방식이다.

여기서 세번째 방식이 플랫폼 사업자에게는 가장 적합하지만, 현재는 플랫폼 사업자와 서비스 공급자가 미국 혹은 유럽 내에서 같은 지역 내에 위치한 경우에만 가능하기 때문에 글로벌한 서비스나 혹은 아시아권에서 사용하기에는 무리가 있다.

Getting Started - third method

stripe 의 connect를 사용하기위한 절차는 다음과 같다.

  1. register your platform
  2. create a connected account
  3. process a payment

플랫폼 등록 및 accout 만들기

stripe에 플랫폼을 등록하고 accout를 만들고 연결하고 payment를 진행해 볼 수 있다. accout에 연결한 뒤에는 반드시 finalize 해주어야 한다.

payment 실행하기

아래와 같은 curl 명령을 통해 특정 account에 payment를 실행해 볼 수 있다.

1
2
3
4
5
6
curl https://api.stripe.com/v1/charges \
-u sk_test_XuTtHvVjbiOgT9aCFsFTsZTA: \
-d amount=1000 \
-d currency=usd \
-d source=tok_visa \
-d destination[account]="{CONNECTED_STRIPE_ACCOUNT_ID}"

Installation

1
sudo npm install -g handlebars

import settings
require('handlebars')

handlebar’s expression

undefined 위처럼 {{}} 사이에 expression을 이용 할 수 있다.

how to compile

다음과 같이 컴파일 할 수 있다.

1
2
var source   = document.getElementById("entry-template").innerHTML;
var template = Handlebars.compile(source);

nestjs 시작하기

Installation

1
2
3
4
5
6
7
8
npm i -g @nestjs/cli
nest new project-name

nest generate module users // generate module
nest g co users // generate controller
npm install

npm run start

Controllers

request를 받아 response를 반환하는 역할을 한다.

decorator 를 사용하여 해당 하는 url로 routing을 할 수 있다.

1
2
3
4
5
6
7
8
9
import { Controller, Get } from '@nestjs/common';

@Controller('cats') //define url
export class CatsController {
@Get()
findAll() {
return 'This action returns all cats';
}
}

controller의 request와 response는 @Req()@Res() 를 통해 다음과 같이 사용될 수 있다.

end point decorator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Controller, Get, Post } from '@nestjs/common';

@Controller('cats')
export class CatsController {
@Post()
create() {
return 'This action adds a new cat';
}

@Get()
findAll() {
return 'This action returns all cats';
}
}

위와 같이 @Post()@Get() 등의 decorator를 통해 endpoint를 설정할 수 있다.

Route parameters

1
2
3
4
5
@Get(':id')
findOne(@Param() params) {
console.log(params.id);
return `This action returns a #${params.id} cat`;
}

Async

1
2
3
4
5
6
7
8
9
@Get()
async findAll(): Promise<any[]> {
return [];
}

@Get()
findAll(): Observable<any[]> {
return of([]);
}


[ Opensource Blockchain Engine, IT-CHAIN] 01. Peer To Peer Network

현재 블록체인 기술은 가장 빠르게 확산되고 있는 유망한 기술 중 하나이며, Bitcoin, Ethereum, EOS 등 수많은 외산 블록체인 엔진들이 입지를 굳혀가는 가운데 국내에서도 블록체인 코어 기술을 위한 많은 연구가 진행이 되고 있습니다.

이번 글에서는 수많은 블록체인 엔진들 중에서도 Lightweight Customizable Chain을 목표로 활발하게 개발이 진행중인 국내 오픈소스 블록체인 엔진인 IT-CHAIN에 대해 살펴보고자 합니다.

본 포스트는 연재 형식으로 IT-CHAIN의 핵심적인 component인 p2p, consensus, blockchain, authentication, txpool, iCode 를 다루는 총 4~6편의 포스트로 이루어 질 예정이며, 오늘은 it-chain의 전체적인 구조와 더불어 그 첫번째 component 인 p2p component에 대한 소개를 하고자 합니다.

What is it-chain?

많은 블록체인 엔진들 중에서 it-chain을 소개하게 된 계기는 무엇보다 구조적으로 매우 직관적이고 이해하기 쉽게 설계되어 있기 때문입니다. 가령, ethereum과 hyperledger처럼 당장 상용화를 목적으로 개발이 진행중인 엔진들은 실용적 문제들에 봉착하여 다양한 기법과 최신 기술을 도입하여 코드를 당장 이해하기 어려움이 있기에 블록체인을 처음 접하는 사람들의 경우 전체 코드를 한눈에 이해하는 것은 매우 어려운 일이 아닐 수 없습니다. 하지만, it-chain은 전체 설계 및 핵심적인 컴포넌트들이 비교적 상세하게 문서화가 되어 있고, 블록체인의 핵심이 되는 기본적인 기능만을 구현하였기 때문에, 블록체인 엔진이 움직이는 큰 그림을 보다 직관적이고 쉽게 이해할 수 있는 장점이 있습니다. 만약 블록체인 엔진 개발에 관심이 있는 엔지니어라면 그 시작으로 it-chain 의 구현을 살펴보는 것을 추천합니다. (it-chain의 github 주소, https://github.com/it-chain/engine)

it-chain이 지향하는 바는 블록체인을 개발하는 누구든지 쉽고 가볍게 커스터마이징이 가능한 엔진을 만드는 것 입니다. 만약 누군가가 ethereum의 코드를 가져다가 자신만의 블록체인 엔진을 만든다고 한다면 그것은 매우 어려운 일일 것 입니다. 합의 알고리즘 하나를 변경하더도 관련된 모든 코드에 대한 이해가 필요하며 얼기설기 얽혀있는 수많은 코드들을 재정리 해야 합니다. 하지만, it-chain 은 event-sourcing을 기반으로 모든 동작이 event를 기반으로 이루어 지기에 다른 구성요소들의 동작에 구애받지 않고 원하는 파트만 손쉽게 변형하여 자신만의 engine을 만들 수 있습니다.

it-chain의 전체 구조

it-chain은 6개의 독립적으로 동작하는 핵심 컴포넌트들로 구현되며, 각각은 AMQP(Asynchronous Message Queue Protocol) 를 통해 커뮤니케이션을 합니다. AMQP는 이벤트 버스로서 각 컴포넌트들에서 일어난 모든 일들은 이벤트 형태로 전파되어 다른 컴포넌트들이 해당 이벤트에 맞는 동작을 수행함으로써 전체 기능이 동작하는 방식입니다.

다음은 it-chain의 각 컴포넌트의 간단한 역할을 보여줍니다.

  • TxPool 컴포넌트: 트랜잭션을 임시로 저장하고 관리하는 컴포넌트로, 합의되어 블록에 저장되지 않은 트랜잭션들을 모아둡니다.
  • Consensus 컴포넌트: 합의를 담당하는 컴포넌트이며, 현재는 PBFT(Practical Byzantine Fault Tolerance) 알고리즘을 따릅니다.
  • BlockChain 컴포넌트: 블록을 생성하고 관리하는 컴포넌트입니다.
  • P2P 컴포넌트: 네트워크의 참여하는 Peer들을 찾고, 유지하는 컴포넌트입니다.
  • Auth 컴포넌트: 각종 인증을 담당합니다.
  • iCode 컴포넌트: it-chain의 스마트 컨트랙트인 iCode 관련 기능을 담당합니다.

It-chain의 Peer to Peer 네트워크

이번 포스트에서는 it-chain에서 여러 노드들 사이의 네트워크 정보를 동기화하고 커넥션을 관리하는 p2p component와 노드 사이의 합의를 이루는 consensus 컴포넌트에 대해 알아보고자 합니다.

먼저, P2p 컴포넌트가 하는 일은 다음과 같습니다.

  • 블록체인 네트워크 내의 다른 노드들의 존재를 인지하고 저장합니다.
  • 네트워크 내의 노드들 사이의 connection정보와 ip 주소 정보를 Peer 라는 이름으로 저장하고 여러 Peer 들의 집합인 PeerTable 을 형성합니다.
  • 모든 노드들이 네트워크 내의 모든 노드들에 대한 정보인 PeerTable 을 공유하고 동기화 합니다.

예를 들어 현재 블록체인 네트워크가 A, B, C 노드로 이루어져있다고 가정해 봅시다.

여기서 D라는 새로운 노드가 A라는 노드에게 접속을 요청을 하게 된다면 D 노드는 A 노드의 정보만을 알고 있게 될 것이며, 마찬가지로 B, C 노드도 D노드에 대한 정보를 알지 못할 것입니다.

하지만 private 블록체인에서는 모든 노드들이 계속해서 서로 통신을 위해 연결되어 있어야 하기 때문에 새롭게 연결된 노드의 정보를 다른 노드들에게 전파해 주어야 하며 각 노드들은 전체 네트워크에 대한 일관된 정보를 공유해야 합니다.

네트워크 정보는 어떻게 저장되나요?

p2p 컴포넌트 내의 연결 정보는 Peer 라는 이름으로 저장이 되며, 그 안에는 특정 노드와의 연결에 대한 고유값인 connectionId와 상대 노드의 ip 주소 를 저장합니다.

가령 A, B, C 노드로 구성된 네트워크가 있다면 A 노드는 B, C 노드와 연결됨에 따른 고유한 connection과 B, C 노드의 ip 주소를 Peer A, Peer B 라는 이름으로 저장하며 모든 노드는 이러한 peer들의 정보를 peer 들의 정보의 집합인 PeerTable 에 저장합니다.

네트워크 정보는 어떻게 공유되나요?

블록체인 네트워크에 새로운 노드가 접속하는 것은 네트워크 내의 특정 노드에게 연결을 요청하는 것에서 시작됩니다.

노드 A, B, C 로 구성된 네트워크에서 D라는 노드가 접속되는 상황을 가정해 봅시다.

노드 D는 A, B, C 노드 중 임의의 노드인 A 노드에게 연결을 요청하고 만약 연결이 이루어 진다면 노드 D의 정보는 노드 A의 PeerTable 에 저장되고, 노드 A 는 새롭게 바뀐 PeerTable 을 노드 D에게 전달해 줍니다.

노드 D는 A에게 받은 PeerTable을 살펴보고 아직 자신이 연결하지 않은 노드인 B와 C 노드에 대해 알게되고 해당 노드의 ip 주소로 연결을 요청하게 됩니다.

B, C 노드가 새로 접근한 노드인 D 노드에게 연결을 요청받고 승인하는 것으로 네트워크 내의 모든 노드는 새로 접근한 노드인 D 노드와 연결이 이루어지게 됩니다.

It-chain의 Consensus 컴포넌트

블록체인에서 핵심은 바로 consensus 입니다.

consensus 컴포넌트는 특정 블록을 생성하기 위해 다른 노드들에게 해당 블록을 생성해도 되는지 검증을 요구하고 네트워크 구성원들의 합의가 이루어지면 새로운 블록을 생성합니다.

It-chain 에서 이러한 합의 알고리즘은 설정을 통해 간편하게 교체할 수 있으며 기본적으로 pbft 알고리즘에 따라 합의가 이루어 지게 됩니다.

pbft 합의 알고리즘

consensus-PBFT

기본적인 PBFT 알고리즘은 다음과 같은 순서로 이루어지게 됩니다.

  1. 클라이언트가 네트워크 구성원에게 어떤 합의문에 대해 합의할 것을 요청합니다.
  2. 합의 요청을 받은 노드들 중 리더 노드는 네트워크 내의 모든 구성원에게 특정 합의에 대한 합의를 시작할 것을 알리는 preprepare message 를 전달합니다.
  3. preprepare message 를 전달받은 모든 노드는 다시 모든 노드에게 prepare message 를 전달합니다.
  4. 전체 네트워크 구성원들 중 정족수(2/3) 이상의 노드에게 받은 preparemessagecommit message 를 모든 노드들에게 전달합니다.
  5. 위 과정이 끝나면 모든 노드들은 정족수이상이 합의한 결과를 가지게 됩니다.

하지만 It-chain 에서는 오직 리더만이 새롭게 생성될 블록을 제안하고 실제로 생성할 수 있으므로 위 과정에서 클라이언트 및 요청 응답이 존재하지 않습니다.

It-chain에서 pbft 알고리즘의 구현

It-chain에서는 위와 같은 pfft 알고리즘 구현을 위해 다음과 같은 몇가지 개념을 도입합니다.

  • Parliament: 의회, 즉, 합의에 참여할 노드들의 집합을 의미합니다.
  • Representative: 대표자, 즉 합의에 참여할 실제 노드 구성원을 의미합니다.
  • Leader: 의장, 즉 의회 구성원의 대표인 리더를 의미합니다.

pbft의 목적은 어디까지나 합의하고자 하는 블록에 대한 합의이기에 다음과 같은 과정에 따라 pbft 기반의 합의 알고리즘이 동작됩니다.

  1. 리더 노드의 consensus 컴포넌트가 블록 생성을 담당하는 blockchain 컴포넌트로 부터 합의하고자 하는 블록을 제안받습니다.
  2. 리더 노드는 해당 블록에 대한 합의를 진행하기 위해 현재 네트워크를 구성하고 있는 정보를 담고 있는 PeerTable 에서 전부 혹은 부분적인 노드를 선출하여 Parliament 를 구성합니다.
  3. 리더 노드가 Parliament 에 속한 모든 Representative 들에게 preprepare message 를 전달합니다.
  4. preprepare message 를 받은 모든 representative 들은 받은 정보를 통해 각자의 Parliament 를 구축하고 다른 Representative 들에게 prepare message 를 전달합니다.
  5. Representative 들은 정족수 이상의 prepare 메세지를 받기 까지 받은 모든 prepare messageprepare message pool 에 저장하고 정족수 이상이 넘으면 commit message 를 전파합니다.
  6. 전체 의회 구성원의 1/3 이상에게 commit message를 받은 각 Representative 들은 Commit message 내의 Proposed Block 에 대한 승인을 하는 이벤트를 발생시키고 블록체인 컴포넌트는 해당 블록에 대한 검증을 시작합니다.
    Proposed Block 이 confirm 되기 까지 Commit message 들은 Commit message pool 에 저장됩니다.

It-chain에서 리더의 선출

it-chain 에서의 리더 선출은 RAFT 라는 알고리즘을 통해 진행되며 consensus 컴포넌트에 구현되어 있습니다.

다음은 RAFT 알고리즘의 간단한 프로세스입니다.

  1. 리더가 사라지면 노드는 의회를 구성합니다.
  2. 150ms ~ 300ms 사이의 랜덤 값으로 모든 노드가 타이머를 동작시킵니다.
  3. 노드의 타이머가 다 되면 그 노드는 자신의 상태를 Candidate 으로 바꾸고 RequestVoteProtocol을 통해 의회 내의 다른 노드에게 투표 요청 message 를 전달합니다.
  4. RequestVoteProtocol 로 메세지를 받은 노드는 아직 타이머가 다 되지 않은 경우 타이머를 리셋하고, 송신한 노드에게 VoteLeaderProtocol을 통해 메세지를 전달하여 리더로 투표합니다.
  5. 만약 상태가 CANDIDATE 인 노드가VoteLeaderProtocol를 통해 다른 모든 노드에게 투표 메세지를 받는다면 그 노드는 스스로 리더가 되고 다른 모든 노드들에게 리더가 됨을 선포합니다.

위와 같은 과정을 통해 물리적으로 떨어져 있는 여러 개의 노드들이 서로 합의를 이루고 리더를 선출 할 수 있게 됩니다.

이번 포스트에서는 국내 블록체인 엔진인 it-chain 의 p2p network 와 consensus 알고리즘, 그리고 리더 선출에 대해 알아보았습니다.

다음 포스트에서는 it-chain에서 블록을 합의하는 컴포넌트인 Blockchain 컴포넌트에 대해 알아보겠습니다.

  • LNH

살아가면서 누군가를 설득하여 원하는 바를 이루어 내는 것은 정말 중요하다.

특히 요즘 사회에는 정보의 홍수와 수많은 미디어의 출현으로 역설적이게도 절대적 진리에 대한 탐구는 점점 더 어려워만 가고있으며, 특정 목적을 가진 많은 기업 및 단체들이 더욱 교묘하게 매체와 심리를 활용하여 상대방을 기술적으로 설득시키는 모습을 흔히 볼 수 있다.

사실 우리가 알지 못하는 사이 대부분의 정당들은 사람들의 심리를 기술적으로 활용하여 정치적 우호감을 확산시키고 있으며, 수많은 기업들의 상업 광고는 우리의 소비 심리를 교란시키고 소비의 마법 앞에 굴복시키고 있다.

이런 사회적 현실 속에서 냉철한 판단을 잃지 않기 위해 우리는 그들이 사용하는 설득의 심리를 이해할 필요가 있으며, 이는 인류가 반드시 추구해야할 진리에의 탐구에 한걸음 더 다가갈 수 있는 유용한 수단이 될 수 있다.

이번 포스트에서는 ‘로버트 치알디니’ 의 저서 ‘설득의 심리학’ 을 기반으로 설득의 심리와 기술에 대해 알아보고 보다 냉철한 현대인으로 거듭나고 한다.

설득의 무기

문명의 발전은 인간이 무의식적인 사고 없이 자동적으로 수행할 수 있는 작업이 늘면서 이루어 졌다. 대부분의 사람들은 문명의 발전과 복잡한 사회 구조가 현대인을 보다 합리적이고 논리적으로 진화시켰다고 생각하지만, 역설적이게도 복잡한 사회는 수백년간의 사회적 통념이란 비 논리적 허점을 낳았고, 우리는 복잡한 사회를 사회적 통념으로 부터의 추상화를 거쳐 이해하게 되었다. 즉, 너무나 많은 정보를 처리하기 위한 판단근거로 절대적 진리를 통한 냉철한 판단은 점차 어려워 지고 인습적 통념에 의존하여 판단을 내리게 된 것이다.

이러한 사실은 인간 뿐만 아니라 동물의 세계에서도 쉽게 찾아볼 수 있다. 가령 칠면조는 새끼가 내는 ‘칩칩’ 거리는 소리로만 자식의 유무를 판단하는 데 이는 사실 절대적 진실과 근거에 의거한 것이 아닌 수십 수백년간 새끼는 ‘칩칩’ 거리며 운다라는 사회적 동물적 통념을 근거로 하여 판단을 하는 것이고, 특정 목적을 가진 누군가가 이를 악용할 수 있는 것이다.

이러한 예는 현실 사회에서도 다양한 형태로 나타난다.
비싼 것이 좋은 것이라는 자본주의 사회의 통념, 무언가 이유를 말하면 그 타당성에 관계없이 논리적으로 더 옳아보이는 인습적 통념, 전문가의 말은 진실일 확률이 높다는 전문가에 대한 의존이 바로 그 예이다. 수많은 미디어는 이를 광고에 활용하고 수많은 전문가와 고부가가치 상품들에 대한 프리미엄 전략 등의 모태가 되었다.

이러한 현상을 좀 더 일반화 하면 사람의 행동에는 자동화된 패턴이 존재한다. 라는 결론이 나오게 되는데, 특정 전문가 집단과 사회적 관습에 의존하는 것을 넘어서 전혀 연관이 없어 보이는 특정한 자동화된 패턴이 있음을 알 수 있다. 가령, 비싼 물건을 구매하고 난 뒤에 보여주는 물건은 상대적으로 아주 저렴하게 느껴지는 대비 효과 의 경우 등도 오랜 시장 거래의 관습에서 얻어진 비논리적 통념의 예로 볼 수 있다.

설득의 원칙

앞의 문단에서 우리는 설득의 기본적인 원리에 대해 알아보았다.
이번에는 보다 구체적으로 두 가지의 설득의 원칙에 대해 알아보고자 한다.

첫번째 원칙은 상호성의 원칙 이다.
우리는 누군가에게 호의를 받으면 항상 갚으려고 하는 습성이 있는데 이것은 상호성의 원칙 의 근간이 된다.
이러한 상호성의 원칙은 수많은 판촉의 모델로써 활용되고 있다. 특정 온라인 쇼핑몰에서 회원 가입을 하면 포인트를 준다거나, 값비싼 물건을 50% 파격적으로 할인한다는 점을 강조하여 상대적으로 양보를 하는 포지션을 취하는 것이 그 예이다. 또한, 상인들이 물건을 흥정시 처음에 값비싼 가격을 부르고 차츰 차츰 가격을 내려 원래 팔고자 했던 가격에 매매하는 기법도 이러한 상호성의 원칙을 활용한 설득의 원리라 볼 수 있다.

두번째 원칙은 일관성의 원칙 이다.
이를 쉽게 표현하면 우리는 한번 내린 판단을 유지하려 하는 습성이 있다는 것이다.
이 원칙 또한 삶의 너무나 많은 부분에 퍼져 있지만 우리는 이것을 알지 못한다.
가령, 헬스장을 등록하고 가지 않더라도 우리는 헬스장 등록이라는 선택은 내가 내린 선택이므로 헬스장을 거의 가지 않더라도 이것은 아주 바람직한 선택이었다고 합리화 하는 경향이 매우 강하다. 때문에 헬스장에서는 고객이 오던 오지 않던 최초 결제일 한번만 잘 구스르고 설득하면 남은 기간동안 서비스가 조금 떨어지더라도 기간이 지나면 지날때마다 고객들의 충성도는 올라가게 된다. 또 다른 예로 자동 결제를 하면 파격적으로 상품의 가격을 깍아주는 많은 서비스들이 있는데, 이것은 최초의 한번의 선택이 어렵지 한번 선택을 내린 뒤에는 사람들이 가급적 결정을 유지하려고 하는 습성을 잘 이용한 것이다. 특히 음악 이용권의 경우 최초의 한 두달의 경우 무료에 가까운 가격으로 음악을 들을 수 있는 경우가 많은데, 이는 사람들의 일관성의 원칙 을 잘 활용한 예라고 볼 수 있다.

이러한 일관성의 원칙 의 또다른 확장은 사람들의 자아이미지를 바꾸어 그들이 자신이 스스로 만들어낸 이미지를 지키기 위해 노력하게 할 수 있다 는 것이다. 이는 어떤 의미에서 브랜딩 그 자체의 목적이라고 보아도 무방하다. 유명한 스포츠 브랜드인 ‘나이키’ 의 경우를 생각해 보자. 그들은 운동화를 구매하는 소비자가 자기 스스로 경쟁을 즐기고 열정이 넘치며 활력적인 사람이라는 자아 이미지를 내도록 끊임없이 부추기게 되고, 그들은 그들 스스로가 만들어낸 이미지의 연속성에서 지속적인 구매를 하도록 유도한다.

어디를 향해 나아가는가?

위의 두가지 원칙 말고도 우리 사회에서는 기술적으로 끊임없이 우리의 심리를 이용하고 활용하는 설득의 기술을 사용하고 있다. 자본주의의 충실한 소비자로써 기존 정치 세력의 충직한 지지자로써 대중을 설득한다.

수세기가 지나면서 사회 경제적 우위에 서있는 기업과 단체 소수자들은 자신들의 권력을 유지하기 위해 대중을 설득해 왔으며, 미디어의 홍수인 오늘날 이런 현상은 더욱 더 위험하다. 하지만, 인류의 역사를 생각해보자. 인류의 위대한 변혁은 기존의 관습에서 벗어나 절대적 진리와 논리적인 이성에 입각하고 과감히 이를 부수는 것에서 시작되었으며, 오늘날 모든 현대인은 더욱 발전된 미래를 위해 절대로 통념에 대한 관성으로 인해 절대적 진리에 대한 추구를 멈추어서는 안되는 것이라 생각한다.

필자를 비롯한 오늘날 모든 사람들이 설득의 기술을 이해하고 정의를 설득하고 통념에 설득당하지 않을 수 있었으면 하는 바램이다.


참조 문헌
로버트 치알디니, 설득의 심리학

Class와 Instance가 무엇인지 알아보자.

객체 지향 언어란?

객체(Object) 란 실제 세계의 많은 사물들을 컴퓨터 내에서 하나의 객체로써 표현하는 하나의 프로그래밍 패러다임을 의미한다.
가령 사과, 사과 장수, 사과의 판매 처럼 실존하는 형태와 형태의 행위들을 표현할 수 있게 된다.

Class 란?

Class 란 하나의 틀(mold) 라고 보면 된다.
가령 현실 세계의 사과 장수는 수없이 많고, 각 사과장수는 공통된 특성을 가지고 공통된 행위가 가능하다.
컴퓨터 프로그래밍 에서는 이러한 상태와 특성 그리고 행위를 표현 가능하며 각각을 property와 method 라고 부른다.

가령 사과 장수라면, 나이, 가지고 있는 사과의 개수, 판매하고자 하는 사과의 가격 등의 특성을 가지고 ‘사과를 판매’ 하거나 ‘사과를 구매’ 하는 등의 행위가 가능할 것이다.

Instance란?

Instance란 위에서 정의한 class로 찍어낸 실제 객체를 의미한다.
가령 현실 세계에서 사과장수는 하나의 추상적인 개념이다. 즉, 사과의 갯수, 나이 처럼 각종 특성을 가지는 하나의 무형의 존재이지만 실제 사과장수는 현실에서 존재한다. 가령 옆집에 사는 사과장수의 경우 정해진 나이와 사과의 갯수를 가지고 실존하는 것이며, 이를 object 또 instance라고 부른다.

Java에서는 class를 통해 instance를 만들어 낼 수 있으며, 새로운 instance를 생성하면 그 데이터가 저장되고 데이터를 가르치는 참조변수에 그 주소값을 저장한다.

생성자(Constructor) 란?

가령 AppleSeller 라는 class 와 appleSeller1이라는 참조 변수를 가지는 instance를 만들었다고 가정하자.
이 만드는 과정에는 그 사과장수의 나이와 사과의 갯수처럼 최초로 설정해 주어야 하는 값들이 있고, 이러한 설정을 Constructor 즉 생성자 내부에서 처리할 수 있다.


go test code 작성하기

이번 포스트에서는 go 언어로 test code를 작성하는 법을 알아보도록 한다.

먼저, go 에서 test code를 작성하기 위해서는 다음과 같은 규약을 따라야 한다.

  • 테스트 함수의 이름은 Test... 가 되어야 한다.
  • 테스트 함수는 t *testing.T 만을 입력값으로 받는다.
  • test code가 작성된 파일의 이름은 뒤가 _test.go 가 되어야 한다.

유용한 testing 함수와 활용방안

t.Error & t.Errorf

t.Error 함수는 문제가 일어나는 지점에서 에러를 발생시키며 좀 더 자세한 오류의 내용을 명시하고 싶은 경우 t.Errorf 를 사용한다.

example

1
2
3
4
5
6
func TestSum(t *testing.T) {
total := Sum(5, 5)
if total != 10 {
t.Errorf("Sum was incorrect, got: %d, want: %d.", total, 10)
}
}

t.Log

t.Log는 테스트 진행 중 콘솔창에 나타내고 싶은 말들을 명시한다.
어떤 입력값이 입력되는 지를 나타내거나 혹은 절차에 관한 간략한 설명을 곁들이는 것이 좋다.

example

1
2
3
4
5
6
7
func TestSum(t *testing.T) {
total := Sum(5, 5)
t.Log("testing sum function... input data: %d, %d", 5, 5)
if total != 10 {
t.Errorf("Sum was incorrect, got: %d, want: %d.", total, 10)
}
}

Test Table

테스트 하고자 하는 입출력 값을 table에 담아 보다 보기 좋게 명시할 수 있으며 다음과 같이 사용될 수 있다.

example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main_test

import "testing"
func Sum(a int, b int) int{

return a+b
}
func TestSum(t *testing.T) {
tests := map[string]struct{
input struct{
testData1 string
testData2 string
}
output struct{
testOutput1 string
testOutput2 string
}
err error
}{
input: struct{
testData1: "test data 1",
testData2: "test data 2",
},
output: struct{
testOutput1: "test output 1",
testOutput2: "test output 2",
}
}

for testName, test := range tests{
Sum(test)
}
}

mock 객체를 활용한 test 시의 dependency 처리

go 함수 내에 dependency injection이 있는 경우 일일히 모든 dependency들을 세팅해 주는 것은 테스트의 코스트가 너무 커진다.
때문에 테스트를 위한 fake interface를 구현하여 inject 해 줌으로써 해결한다.


Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×