가족이나 연인, 친한 친구와의 사이에서 갈등이 생기는 것은 당연하다. 친해서 자주 만나는 사람일수록 부딪힐 일이 많을 수밖에 없고 친밀할수록 서로 기대하는 것도 더 많기 때문에 기대에 반하는 행동을 하게 될 확률도 높을 수밖에 없다.
따라서 중요한 것은 갈등의 유무보다 갈등을 ‘어떻게’ 해결하느냐가 된다. 여기에서 가장 많이 저지르는 실수 중 하나가 부정적 정서의 상호 교환(negative-affect reciprocity)인데, 상대로부터 비판을 받았을 때 일종의 보복 행위로 더 큰 비난이나 부정적 정서를 돌려주는 행위를 말한다.
예를 들어 아내가 남편에게 “요즘 당신이 집안일을 거의 안 하니까 내가 너무 힘들어”라고 말했을 때 남편이 “내가 집안일을 안 한다고? 너야말로 요즘 가족들한테 신경 안 쓰잖아!”라고 공격적으로 반응하는 경우나 한 친구가 다른 친구에게 요즘 약속에 왜 이렇게 자주 늦냐고 했을 때 “너는 약속 지킨 적이라도 있어? 항상 네 멋대로잖아!”라고 되받아치는 등, 서로 계속해서 공격을 주고받으며 갈등이 증폭되는 상황이 여기에 해당한다.
특히 이미 문제가 많은 관계일수록 불만이 제기되었을 때 “아 그래? 미안해. 앞으로는 안 그럴게”라고 하기보다 “내가 잘못했다고? 너는 잘했어?” 같은 식으로 맞받아치는 모습이 더 흔히 나타나는 것으로 알려져 있다.
일라이 핑켈 노스웨스턴대의 심리학자에 의하면, 다행히도 생각보다 쉬운 방법으로 이런 부적응적인 패턴을 바꿀 수 있다. 연구자들은 관계를 개선하고 싶어 하는 부부들을 대상으로 네 달에 한 번씩 총 세 번(7분씩 총 21분)에 다음과 같은 생각 연습을 하도록 했다.
우선 서로 갈등을 빚었던 상황을 구체적으로 떠올려 보고 두 사람을 모두 잘 알고 있고 진심으로 둘을 응원하는 제3자 입장이 되어 그 사람이라면 이 갈등 상황에 대해 어떻게 생각할지 그 사람이라면 이 갈등에서 어떤 긍정적 가능성을 발견할 수 있을지 떠올리도록 했다.
그리고파트너와 대화할 때 ‘중립적인 제3자’의 시선을 취하는 것이 도움이 될 수 있다고 알려주면서 특히 갈등 상황에서 이런 시선을 취하지 못하게 만드는 방해 요인이 있다면 무엇인지 생각해보도록 했다.
마지막으로 앞으로 4개월 동안 갈등 상황에서 최대한 중립적인 입장을 취하려고 노력하는 데 도움이 될 구체적인 전략들에는 어떤 것들이 있을지 생각해보도록 했다.
그 결과 이런 짧은 생각 연습만으로도 이후 약 1년간 관계 만족도나 사랑, 친밀감, 신뢰 등이 이전에 비해 개선된 것으로 나타났다. 사실 많은 갈등들이 화가 몰아치는 상황에서 평소라면 하지 않았을 심한 말을 내뱉는 일 때문에 돌이킬 수 없게 나빠지곤 한다는 점을 고려하면 말하기 전에 한 번만 더 생각하는 정도의 작은 노력으로도 금방 좋은 효과를 얻을 수 있다는 사실이 이상하게 느껴지진 않는다.
좋은 관계를 오래 유지하고 싶다면 역시 말은 쉽게 하기보다 어렵게 하는 편이 좋은 것 같다.
※필자소개 박진영. 《나, 지금 이대로 괜찮은 사람》, 《나를 사랑하지 않는 나에게》를 썼다. 삶에 도움이 되는 심리학 연구를 알기 쉽고 공감 가도록 풀어낸 책을 통해 독자와 꾸준히 소통하고 있다. 온라인에서 ‘지뇽뇽’이라는 필명으로 활동하고 있다. 현재 미국 듀크대에서 사회심리학 박사 과정을 밟고 있다
마음챙김이란 마음속에 떠오르는 생각이나 감정들에 대해 최대한 판단하지 않고 받아들이는 마음이다. ‘지금, 여기’에 주의를 집중하는 상태에 관해 그간 다양한 연구들이 이루어졌다.
마음챙김이 스트레스를 줄여준다는 사실은 널리 알려져 있고 최근 연구들에 의하면 노화 진행을 줄여주고 심혈관 질환 위험성과 부적 상관을 보이는 등 마음챙김이 행복과 건강에 이롭다는 결과들이 다방면에서 보고되고 있다.
최근 이런 마음챙김이 주제인 학회에 다녀왔고 덕분에 흥미로운 사실들에 대해 더 많이 알게 되었다. 그중 하나는 그간 마음챙김이 친사회적 행동과 관련을 보인다는 연구 결과들이 많이 소개되었지만 반대로 도움이 되지 않거나 심지어 해를 끼치는 듯 보이는 결과들 또한 많다는 것이다.
래드퍼드대 연구자 대니얼 베리에 의하면 예를 들어 나르시시스트적인 성향이 있는 사람들의 경우 짧게나마 마음챙김 명상을 하면 어려움에 처해 있는 사람을 도우려는 모습을 ‘덜’ 보이는 현상을 확인했다고 한다.
반대로 또 다른 세션에서는 평소 마음챙김 명상을 자주 하는 사람들의 경우 ‘화’를 덜 내고 자신을 화나게 한 사람을 더 잘 용서하는 모습을 보였다는 보고도 있었다.
하지만 평소 이러한 마음 수련에 관심이 많고 열심히 하는 사람들이 타인에게 더 너그러운 모습을 보인다는 것은 마음챙김 수련 하나의 효과라기보다 그 사람들이 가지고 있는 어떠한 특성이 마음챙김과 합쳐져 친사회적인 행동을 증가시키는 것일 수도 있다.
나르시시스트적인 성향이 있는 사람들에게는 마음챙김 명상이 되레 친절하고 너그러운 행동을 ‘덜’ 보였다는 연구 결과와 비슷하게 마이클 풀린 뉴욕주립대 버펄로캠퍼스 심리학자의 연구에서도 평소 ‘독립적’인 자아관(자신을 규정할 때 본인이 가지고 있는 고유한 특성들: 나는 아름답다, 나는 독창적이다 등으로 규정)을 가지고 있는 사람들은 관계적 자아관(사회적 관계와 역할: 누구의 딸, 어느 학교 학생, 어느 회사 직원 등으로 규정)을 가지고 있는 사람들과 달리 마음챙김 명상이 도움 행동을 줄이는 것으로 나타났다.
사람들에게 독립적인 자아관 또는 관계적인 자아관을 가지게 유도했을 때에도(각각 ‘나’ 또는 ‘우리’로 지칭되는 글을 읽게 함) 독립적인 자아관으로 사고하게 된 사람들이 마음챙김 명상을 했을 때 명상 말고 다른 활동을 한 통제 집단에 비해 봉사활동 의향을 ‘덜’ 보이는 것으로 나타났다. 반대로 관계적 자아관을 가지게 된 사람들은 통제 집단에 비해 봉사활동 의향을 더 많이 하려는 의향을 보였다.
생각해보면 원래의 마음챙김 수행이 가지고 있던 맥락(마음속 번민을 줄이고 자비를 실천할 것)을 떠나 그냥 기술적인 부분만 실시한다고 더 도덕적이고 자비로운 사람이 될 것 같지는 않다. 따라서 앞선 발견들은 어쩌면 당연한 결과인지도 모른다.
이런 맥락 없이 무턱대고 자신을 판단하지 않고 받아들이는 연습을 하면 그냥 원래 가지고 있던 좋은 모습과 나쁜 모습들이 여과 없이 쏟아져 나올 것 같기도 하다.
미국에서 마음챙김은 벌써 3조 원 규모의 어마어마한 사업이 되었다고 한다. 본질을 떠나 빠르게 위로받기에만 급급해진 분위기를 반영하고 있는 것은 아닌지 생각해본다.
※필자소개 박진영. 《나, 지금 이대로 괜찮은 사람》, 《나를 사랑하지 않는 나에게》를 썼다. 삶에 도움이 되는 심리학 연구를 알기 쉽고 공감 가도록 풀어낸 책을 통해 독자와 꾸준히 소통하고 있다. 온라인에서 ‘지뇽뇽’이라는 필명으로 활동하고 있다. 현재 미국 듀크대에서 사회심리학 박사 과정을 밟고 있다.
어린 시절을 돌아보면 ‘비교’와 ‘불안’이 항상 마음 한구석에 자리하고 있었다. 어렸을 때부터 좋은 학교를 가지 못하면 인생이 망할 것처럼 이야기하는 어른들 때문이었는지, 언제부턴가 조금만 미끄러지면 삶이 끝장나기라도 하는 것처럼 늘 두려움 속에서 살았던 것 같다.
친구들이 좋은 결과를 얻으면 함께 기뻐하는 마음과 함께 나는 왜 이렇게 좋은 결과를 내지 못하는 거냐는 자기비난과 열등감이 자라났다. 그러면서 친구의 기쁨을 온전히 함께 기뻐하지 못하는 나의 속물스러움에 질리고 자신을 더더욱 혐오하는 파괴적인 굴레에 갇혀 있었던 것 같다.
다행히 시간이 지나면서 점차 내가 최악일 때나 가장 좋은 모습일 때나 한결같이 나를 응원해주는 사람들과 나의 성취를 자신의 일인 것처럼 함께 기뻐해주는 사람들을 만나게 되었다. 그러면서 누군가에게 생긴 기쁜 일을 함께 기뻐하면 그만큼 내 행복도 배가 된다는 사실을 조금씩 경험하게 되었던 것 같다.
덕분에 쓸데없는 자기비난과 열등감, 자기혐오가 많이 줄어들었다. 생각해보면 쓸데없이 마음속에 지옥을 담아두고 살았던 것 같다. 내 마음이 지옥이면 가장 큰 피해를 보는 사람은 결국 나다.
한편 누군가의 좋은 일을 굳이 나에 관한 일로 해석해버리는 습관 또한 자기 과몰입(hyper-egoic) 상태라는 생각이 든다. 많은 사람들이 습관적으로 삶의 대부분을 ‘자기 자신’에 대한 생각에 빠져 보내는 자아중독 상태에 빠져 있다.
마크 리어리 듀크대 심리학자에 의하면 이런 자기 과몰입 상태에는 고질적으로 많은 양의 주의를 바깥세상보다 자기 자신에게 쓰는 것, 세상 모든 일을 자신의 관점에서 해석하는 자기중심성, 타인의 시선을 신경 쓰며 살아가는 타율성 같은 것들이 포함된다.
친구에게 생긴 좋은 일에 대해 들으면 친구에게 포커스를 둬야 하는데 그런 상황에서도 굳이 자기 자신에게로 주의를 돌려 결국 뭐든지 자기 자신에 대한 일로 만들어버리는 것 역시 고질적인 자기 과몰입에 해당될 것이다. 이런 점에서도 자기 과몰입은 정신 건강과 나아가 인간관계에도 해로운 영향을 미칠 수 있다.
자신에게 이런 면이 있다면 빨리 인정하고 최소한 누군가 잘된다고 해서 내가 잘못되는 것이 아님을 생각해보는 것이 좋겠다. 안타깝지만 ‘사촌이 땅을 사면 배가 아프다’는 말이 존재하는 것을 보면 또 의외로 연인이나 부부 관계에서도 특히 이성애자 남성의 경우 자신의 파트너가 자신보다 더 잘 나가면 위축되는 현상이 많은 걸 보면 흔히 나타나는 현상인 것 같다. 아마도 이런 사고방식이 한 사회가 좀 더 불행해지는 데 한몫할지도 모르겠다.
연구들에 의하면 ‘파이가 정해져 있다는 믿음(fixed-pie perception)’, 함께 나눠 먹는 파이의 양은 정해져 있어서 타인이 조금 더 많이 먹으면 내 몫이 줄어든다는 생각이 자기파괴적인 질투나 근시안적이고 지나치게 경쟁적인 태도와 관련을 보인다.
물론 그런 상황도 존재하겠지만 내 친구에게 생긴 좋은 일이 직접적으로 나에게 안 좋은 영향을 미치는 경우는 거의 없다(예를 들어 ‘내가 잘된다고 해서 네가 잘 안 되는 게 아니야’라는 말처럼). 그나마 나에게 우호적인 사람들을 경쟁적인 시선으로 바라보는 것보다 적어도 이 사람들과는 ‘함께’ 잘되기를 바라는 것이 장기적으로 모두의 행복에 훨씬 바람직할 것이다.
삶은 원래 별거 없고 우리에게 찾아온 좋은 인연들을 쫓아버릴 만큼 중요한 일도 잘 없다. 뭐라도 잡아보려고 주먹을 꼭 쥐고 살아가기보다, 보다 편안한 마음으로 살아갈 수 있기를 바래본다.
※필자소개 박진영. 《나, 지금 이대로 괜찮은 사람》, 《나를 사랑하지 않는 나에게》를 썼다. 삶에 도움이 되는 심리학 연구를 알기 쉽고 공감 가도록 풀어낸 책을 통해 독자와 꾸준히 소통하고 있다. 온라인에서 ‘지뇽뇽’이라는 필명으로 활동하고 있다. 현재 미국 듀크대에서 사회심리학 박사 과정을 밟고 있다.
파이토치에서 학습 루프를 정의하는 건 보다 간단하고 직관적이다. 변수를 생성하고 동적 그래프를 그때그때 정의하면서 모델을 학습할 수 있다. 데이터와 타겟을 디바이스(CPU/GPU)에 할당하고 순전파를 연산한다.
모델이 순전파(feed-forward) 연산을 마치고 나면, pytorch의 사전 정의된 개체들을 통해 역전파 과정을 수행할 수 있다. 그래디언트를 계산하고, 역전파 방법론을 적용함으로써 파라미터를 업데이트 한다.
for epoch inrange(epochs):
for batch, (data, target) inenumerate(train_loader):
# cuda 파라미터 가져오기
data = data.to(device=device)
target = target.to(device=device)
# 순전파
score = model(data)
loss = criterion(score, target)
# 역전파
optimizer.zero_grad()
loss.backward()
optimizer.step()
4. MNIST로 파이토치 이해하기
필요한 라이브러리를 불러온다
import torch
import torchvision
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
import numpy as np
import matplotlib.pyplot as plt
평소 자신이 무언가를 잘못 알고 있거나 틀릴 가능성을 어느 정도 인식하고 있는 사람이 있는 반면 그렇지 않은 사람이 있다. 예를 들어 다른 사람들은 이따금씩 틀리더라도 자신만은 그렇지 않을 것이고 자신이 옳다고 생각하는 것들은 대체로 다른 상황에서도 다른 사람들에게도 ‘내가 대체로 옳다’고 여기는 자신감이 쓸데없이 과한 사람들이 있다.
이렇게 자신의 지적 한계에 대해 인식하는 특성을 ‘지적 겸손’이라고 부른다. 안타깝게도 연구들에 의하면 이는 꽤 안정적인 특성이라서 지적 겸손도가 높은 사람들은 일반적으로 어떤 현상을 바라볼 때 한 가지 설명(보통 자신의 시각)에만 매몰되어 있기보다 서로 다른 다양한 시각에 열려 있는 편이다.
자신과 의견이 다르다고 해서 누군가를 미워하거나 적대시하는 일도 비교적 적다. 복잡한 현상에 대해 지나친 단순화나 과한 일반화를 좋아하지 않고 복잡하게 얽혀 있는 다양한 층위의 원인들을 파고드는 것을 좋아하는 편이다.
이와 달리 지적 겸손도가 낮은 사람들의 경우 보통 자신의 시각에 지나치게 과한 가중치를 두고 자신의 의견과 비슷한 의견만 골라서 듣는 경향이 있다.
자신과 생각이 다른 사람을 싫어하거나 배척하는 일이 비교적 흔하게 나타나고 문제의 복잡함에 반해 지나치게 ‘간단명료한 설명’을 선호한다. 그러다 보니 지적 겸손도에 따라 좀 더 지혜로운 사람이 될 수 있는지의 여부가 달라지기도 한다.
물론 어느 정도 옳고 그름이 명확한 문제에 대해서는 그나마 지적 겸손도가 낮은 것이 큰 문제가 되지 않을 수 있지만 이런 경우에도 사람들은 지적 겸손도가 낮기보다 높은 사람들의 의견을 더 잘 청취하는 경향이 있다.
예를 들어 과학자들의 경우에도 지적 겸손도가 높을 때(또는 높다고 여겨질 때), 사람들이 더 과학자들이 한 연구 내용을 신뢰한다는 발견들이 있었다. 또 조직 내에서도 리더의 지적 겸손도가 높을 때 그렇지 않을 때에 비해 창의적인 결과물들이 더 많이 나온다는 연구 결과들도 있었다.
비교적 ‘정답’이 존재하는 세계에서도 그렇지만 정답이라는 것이 존재하지 않고 다양한 입장이 상충하는 사회적 문제나 인간관계에서의 갈등 상황에서도 지적 겸손은 중요한 역할을 한다. 조나 코에트키 피츠버그대 연구자의 연구에 의하면, 지적 겸손도가 높은 사람들은 그렇지 않은 사람들에 비해 다양한 ‘갈등’ 상황을 더 잘 해쳐나가는 편이다.
지적 겸손도가 높은 사람들은 그렇지 않은 사람들에 비해 갈등 상황에서
① 긍정적 정보 전달: 다른 사람들이 자신의 입장을 잘 이해할 수 있도록 자신에게 있어 중요한 것들에 대해 솔직하게 이야기
② 긍정적 회피: 사람들이 여러 대안을 더 잘 검토할 수 있도록 문제를 차후 다시 논의하자고 제안
③ 긍정적 개방: 어떤 해결책을 제안하기 전에 상대방에게 있어 가장 중요한 요소들이 무엇인지 살핌
④ 긍정적 연대: 함께 마음을 모아 해결하면 문제를 해결할 수 있을 것이라고 믿는 건설적인 행동을 더 자주 한다고 보고하는 것으로 나타났다.
그런 반면 지적 겸손도가 높은 사람들은 지적 겸손도가 낮은 사람들에 비해
⑤ 부정적 공격: 상대방에게 무례한 태도를 보이거나
⑥ 부정적 회피: 갈등이 불편해서 침묵을 지키거나 대화 주제를 바꾸는 등의 해로운 행동은 덜 하는 편이라고 보고했다.
나아가 역사적으로 첨예한 국가 간, 집단 간 갈등 상황에서도 지적 겸손도가 높은 사람들은 그렇지 않은 사람들에 비해 양쪽의 입장에 좀 더 균등한 관심을 보이고 팔이 안으로 굽기보다 외집단 사람들의 피해 상황과 고통에 대해서도 인지하며 폭력적이기보다 대화를 통한 해결을 선호한다는 발견들이 있었다.
점점 살면서 겪는 대부분의 문제들에서 꼭 ‘한 가지 정답’만 존재하는 경우는 드물 것이라는 생각이 든다. 특히 서로 다른 의견들이 부딪히는 문제에서는 더더욱 그럴 것이다. 그렇기 때문에 내 생각이 반드시 옳거나 특히 내 생각만 옳을 가능성은 아마 매우 적을 것이다.
당연한 이야기인 것 같지만 안타깝게도 우리 모두 이런 지혜를 기본적으로 장착하고 있는 것은 아니어서 내가 반드시 옳다는 생각이 들 때면 나의 지적 겸손도를 따져봐야겠다는 생각이 든다.
※필자소개 박진영. 《나, 지금 이대로 괜찮은 사람》, 《나를 사랑하지 않는 나에게》를 썼다. 삶에 도움이 되는 심리학 연구를 알기 쉽고 공감 가도록 풀어낸 책을 통해 독자와 꾸준히 소통하고 있다. 온라인에서 ‘지뇽뇽’이라는 필명으로 활동하고 있다. 현재 미국 듀크대에서 사회심리학 박사 과정을 밟고 있다.
많은 사람들이 어려움을 겪는 사람들을 보면 안타까움을 느끼면서도 동시에 “왜?”, “어쩌다가?” 같은 질문을 던진다. 집에 불이 나거나 실직을 하는 등 부주의나 실수 같은 개인의 책임이 있을 수도 있는 일에 대해서는 물론이고 큰 병에 걸리는 것처럼 항상 뚜렷한 원인이나 책임이 존재하는 것은 아닌 문제들에 대해서도 나름 원인을 찾아보려고 애쓴다.
물론 나쁜 일에 대해 어떤 원인을 밝히려고 노력하는 것은 유용할 때가 많다. 왜 그런 일이 발생했는지 알아야 자신이나 주변 사람들에게 비슷한 나쁜 일이 발생하는 것을 막을 수 있을 것이고 최소한 자신의 힘으로 나쁜 일을 어느 정도 막을 수 있다는 ‘통제감’을 가지는 것이 가능하다. 문제는 그런 노력이 개인에 대한 지나친 비난과 구조적인 문제를 감추고 지속시키는 결과를 가져올 수 있다는 것이다.
사람들은 삶이 예측 가능하고 자신의 힘으로 통제할 수 있기를 바란다. 조금만 생각해 봐도 세상에는 우리가 계획한 대로 되지 않는 일이 더 많고(예> 불경기, 운) 한 치 앞도 살필 수 없는 것이 삶이지만 노력하고 착하게 살면 나쁜 일이 닥치지 않을 것이라고 믿고 싶어한다. 그 대표적인 예가 세상은 대체로 공정하다는 믿음(Belief in a Just World)이다.
이 믿음 덕분에 그렇지 않은 사례들이 즐비함에도 내가 하는 행동들이 무의미하지 않다는 의미감과 잘될 거라는 희망을 가지고 살아가는 것이 가능하다. 하지만 그와 동시에 착하고 열심히 살아온 사람들에게 나쁜 일이 닥치는 불편한 사실을 외면하게 되기도 한다. 재난 뉴스에 “그러게 거기 왜 갔냐”는 댓글들이 달리고 무고한 피해자에게 “걔도 뭔가 잘못을 했을 거다”라는 추측과 2차 가해가 따라붙는다.
자신의 통제감과 희망을 유지하기 위해서 사회 구조적인 문제가 숨어 있는 문제들, 예를 들어 ‘가난’에 대해서도 빈부격차나 높은 물가와 실업률, 낮은 임금 같은 문제들을 전부 ‘게으름’ 같은 개인 내적 문제로 환원시키기도 한다.
대부분의 문제들이 개인 내적·외적 요소들이 얼키고설켜 만들어지고 겉으로 보이는 것보다 훨씬 복잡한 이면을 가지고 있음에도 이것들을 너무 단순하게 축소시켜 버린다. 그러다 보니 진짜 해결해야 할 문제를 놓치고 괜한 사람들만 비난하는 것으로 문제 해결을 종결시키고 만다.
최근 연구들에 의하면 ‘내가 노력하면 된다’는 믿음은 동기부여에 도움이 된다는 이점이 있지만 특히 ‘남들도 대체로 자신에게 걸맞은 결과를 얻는다’는 믿음은 가난한 사람에 대해 게으르거나 능력이 부족하다는 낙인을 찍는 것이나 이미 차별받고 있는 사람들을 더 차별하고 처벌하려는 행동과 관련을 보인다.
나의 상황과 타인의 상황이 전혀 다를 수 있고 내가 노력하면 할 수 있는 일이 누군가에게는 전혀 다른 차원의 문제일 수 있다. 하지만 이렇게 삶의 문제들을 입체적으로 다각도에서 분석하는 데에는 많은 훈련이 필요하다.
어쩌면 생각보다 해결 방법은 단순할지도 모른다. 삶은 한 치 앞도 예측하기 힘들고 많은 문제들이 개인 내적·외적 요소들에 걸쳐 복잡하게 꼬여 있으며 세상에는 내가 모르는 차원의 문제들도 존재함을 인정하면 적어도 타인의 삶을 쉽게 판단하는 행동은 삼가게 되지 않을까?
연구들에 의하면 ‘지혜로운’ 사람들의 경우 이와 같이 인간의 삶은 다층적이고 다면적임을 아는 편이다. 이 세상에 단순하고 간단한 문제란 없음을 기억해야겠다.
※필자소개 박진영. 《나, 지금 이대로 괜찮은 사람》, 《나를 사랑하지 않는 나에게》를 썼다. 삶에 도움이 되는 심리학 연구를 알기 쉽고 공감 가도록 풀어낸 책을 통해 독자와 꾸준히 소통하고 있다. 온라인에서 ‘지뇽뇽’이라는 필명으로 활동하고 있다. 현재 미국 듀크대에서 사회심리학 박사 과정을 밟고 있다.
나는 언젠가 분명 ‘명령적(Imperative) 프로그래밍 vs 선언적(Declarative) 프로그래밍’에 대해 들어본 적이 있다.
저게 무엇을 의미하는지를 당연히 검색해봤지만, 그 때마다 요런 정의 정도만 접해볼 수 있었다.
명령형(절차적) 프로그래밍은 당신이 어떤 일을 어떻게 할 것인가에 관한 것이고,
선언적 프로그래밍은 당신이 무엇을 할 것인가에 관한 것입니다.
만약 내가 명령형과 선언형의 차이를 이미 알고 있었더라면 이 정의가 명확하게 다가왔겠지만 나는 그렇지 않았다.
사실 나 뿐만 아니라 많은 사람들이 이 주제에 대해 어려움을 느끼는데,
아마 직관적으로는 무슨 말인지 알지만, 누군가에게 설명할 만큼 명확하지는 않기 때문일 것이다.
많은 개발자들이 여기기에 가장 효과적인 방법은 비유와 실제 코드를 조합해서 설명해주는 것이었다고 하니,
해당 방법으로 ‘명령형 vs 선언적 프로그래밍’이라는 주제를 다뤄보도록 하자.
우선, 위에서 언급했던 저 ‘어떻게, 무엇을’에 관한 정의는
사실 ‘명령형 vs 선언형’의 핵심을 담고있다고 봐도 무방하다.
이를 이해하기 위해, 프로그래밍의 관점에서 잠깐 벗어나 현실에서의 예시를 들어보도록 하자.
■ Red Lobster
당신은 회사에서 너무 오랜 시간 자바스크립트를 다루느라 피곤해졌습니다.
그리고 이를 달래기 위해 퇴근 후에 아내와 함께 ‘Red Lobster’ 식당에 근사한 데이트를 하러 갔습니다.
당신은 Red Lobster에 도착했고, 프론트 데스크에 가서 다음과 같이 말했습니다.
명령형 접근(HOW): “저기 Gone Fishin’ 이라고 적힌 표지판 아래에 있는 테이블이 비어있네요.
우리는 저기로 걸어가서 저 테이블에 앉도록 하겠습니다.”
선언형 접근(WHAT): “2명 자리 주세요.”
명령형 방식은 내가 실제로 자리에 어떻게 앉을지에 관심이 있다.
이를 위해 나는 내가 어떻게 테이블을 잡아서 자리에 앉을지에 관해, 필요한 단계들을 하나하나 나열해야 한다.
반면, 선언형 방식은 오로지 내가 무엇을 원하는지에 관심이 있다. 여기서 말한 ‘두 명을 위한 테이블’ 처럼.
■ Wal-Mart
친구가 당신의 집에 집들이를 오기 위해 Wal-Mart에서 선물을 샀습니다.
현재 친구는 Wal-Mart 바로 옆에 있으며, 당신의 집에 어떻게 도달해야 하는지를 전화로 물어봅니다.
이에 관한 명령형 대답과 선언형 대답을 모두 생각해보세요.
명령형 접근(HOW): “주차장 북쪽 출구로 나와서 좌회전을 해. 12번가 출구에 도착할 때까지
I-15 북쪽 도로를 타고 와야 해. 거기서 IKEA에 가는 것처럼 출구에서 우회전을 해. 그리고 거기서
직진하다가 첫 번째 신호등에서 우회전을 해. 그 다음에 나오는 신호등을 통과한 후에 좌회전을 하면 돼.
우리 집은 #298 이야.”
선언형 접근(WHAT): “우리 집 주소는 298 West Immutable Alley, Eden, Utah 84310 이야.”
추가로 한 가지 비유를 더 하자면, 수동 스틱 자동차와 오토 스틱 자동차를 예로 들 수 있다.
친구가 ‘우리 집에 어떻게 도착하는가’ 와는 별개로, 친구가 어떤 차를 운전하느냐에 관한 이야기이다.
수동 스틱(1종)은 명령형 방식이고 오토 스틱(2종)은 선언적 방식이다.
만약 당신이라면 어떤 차를 운전하겠는가?
실제 코드로 예시를 들기 전에, “자리에 앉는 방법은 누가 알지?”,
“주소는 아는데, 집에 가는 방법은 누가 알지?”와 같은 의문이 생길 수 있을거라 생각한다.
이에 대한 대답은, 선언적 방식의 접근을 위해서는 명령형 방식으로
‘어떻게 접근하는가’에 관한 내용이 먼저 추상화 되어있어야 한다 라는 것.
Red Lobster 직원에게 사용했던 선언형 접근(“2명 자리 주세요.”)에는, Red Lobster 직원이
‘테이블에 어떻게 앉는가’에 관한 모든 명령형(절차적) 단계들을 알고 있다는 가정이 뒷받침되어 있다.
친구에게 우리 집의 주소를 알려주는 것도, 친구가 ‘우리 집에 어떻게 도착할 수 있는가’에 관한 명령적 절차들을
모두 알고있는 일종의 GPS 같은 것을 가지고 있다는 것을 전제로 한다.
오토 스틱(2종) 자동차는 변속 기어에 대해 일종의 추상화 계층(Layer)을 가지고 있다.
위의 내용들을 다음의 문장으로 다시 한 번 정리할 수 있다.
많은 선언적(Declarative) 접근 방식들의 기반에는 일종의 ‘명령적(Imperative) 추상화’가 존재한다.
이제, 여러가지 비유로 떡칠된 예시들을 졸업하고 현실 세계의 코드 예시를 살펴볼 차례이다.
그 전에, ‘선언적 프로그래밍 언어’와 ‘명령적 프로그래밍 언어’에는 어떤 것들이 있는지 간단히 살펴보자.
명령적 언어: C, C++, Java
선언적 언어: SQL, HTML
(Can be) Mix: Javascript, C#, Python
우선, 대표적인 선언형 언어인 SQL과 HTML의 코드를 살펴보자.
SELECT * FROMUsersWHERE Country='Mexico';
<article><header><h1>Declarative Programming</h1><p>Sprinkle Declarative in your verbiage to sound smart</p></header></article>
이 두 가지 예시 모두 문법만 알고 있다면, 어떤 일이 일어나고 있는지 명확히 알 수 있다.
이 둘은 모두 선언형 프로그래밍이며, 어떤 일을 어떻게 수행하는가 보다는 무엇을 수행하는가에 관심이 있다.
즉, 우리가 무엇을 얻고자 하는가에 관해서만 묘사하고 있고, 그것을 어떻게 얻는가에 관해서는 알려주지 않는다.
SQL 예시에서는 멕시코에 거주하는 모든 유저들을 선택하는 ‘방법에 대한 구현’은 우리에게서 추상화되어있다.
HTML 예시에서는 ‘웹 브라우저가 어떻게 article 엘리먼트를 파싱해서 화면에 보여주는가’는 고려하지 않는다.
우리의 WHAT은 오직 ‘멕시코 유저들‘과 웹사이트의 ‘header와 paragraph‘이다.
지금까지는 충분히 알아먹을 수 있을 것 같다.
이제, 조금 더 실전적인 자바스크립트 예제로 들어가보자.
■ 기술 면접
당신은 현재 기술 면접을 보는 중이고, 나는 해당 기술 면접의 interviewer입니다.
콘솔창을 열고, 제가 묻는 질문에 해당하는 답을 작성해보세요.
1. 숫자 배열을 받아서, 해당 배열의 모든 원소들을 두 배 시킨
새로운 배열을 리턴하는 ‘double’이라는 이름의 함수를 작성하세요.
ex) double([1, 2, 3]) // [2, 4, 6]
2. 숫자 배열을 받아서, 해당 배열의 모든 원소들을 더한 값을 리턴하는 ‘add’라는 함수를 작성하세요.
ex) add([1, 2, 3]) // 6
3. jQuery나 Vanilla Javascript를 이용해서, btn이라는 id를 가진 엘리먼트에 이벤트 리스너를 달아보세요.
해당 버튼을 클릭했을 때 highlight라는 class를 toggle(add or remove)해야 하고,
엘리먼트의 현재 상태에 따라 버튼의 텍스트를 ‘Add Highlight’와 ‘Remove Highlight’로 바꿔야 합니다.
이 문제들에 대해, 가장 흔히들 작성하는 ‘명령적’ 코드들을 먼저 살펴보자.
functiondouble (arr) {
let results = []
for (let i = 0; i < arr.length; i++){
results.push(arr[i] * 2)
}
return results
}
functionadd (arr) {
let result = 0for (let i = 0; i < arr.length; i++){
result += arr[i]
}
return result
}
$("#btn").click(function() {
$(this).toggleClass("highlight")
$(this).text() === 'Add Highlight'
? $(this).text('Remove Highlight')
: $(this).text('Add Highlight')
})
무엇이 이 코드들을 명령적으로 만드는지 알기 위해서는, 이 세 가지 코드들에서 공통점을 뽑아내야 한다.
1. 가장 명백한 공통점은 이들이 어떤 일을 어떻게 처리하는지에 관해 묘사하고 있다는 것.
각각의 예시에서, 우리는 명시적으로 배열을 반복하거나(for 문),
우리가 원하는 기능을 수행하기 위한 단계들을 명시적으로 나열하고 있다.
2. 각각의 예시에서 우리는 ‘상태(state)의 일부’를 변경하고 있다.
(상태: 메모리에 저장되어 있는 것들에 대한 정보. 변수와 비슷하다고 생각하면 됨)
처음 두 예시에서는 ‘results’라는 변수를 만들어 그것을 계속해서 수정하고 있다.
세 번째 예시에서는 아무런 변수도 없지만, 여전히 DOM 자체에 state가 존재하고 있다.
그리고 해당 코드는 DOM의 state를 수정하고있다.
3. 약간 주관적이지만, 위의 코드들은 가독성이 떨어진다.
위의 코드들을 한 번 슥 훑어보고 어떤 일이 일어나고 있는지 바로 알아채기는 쉽지 않을 것이다.
우리의 뇌는 코드가 존재하는 맥락을 고려해가며, 해당 코드들을 인터프리터처럼 차근차근 살펴봐야 한다.
처음 두 예제에서, 자바스크립트의 내장 함수인 map과 reduce를 활용한 레버리징에 주목하자.
이는 이 글 내내 반복해서 언급했던,
‘가장 효율적인 선언적 프로그래밍 방법은 명령적으로 작성된 코드를 추상화하는 것이다‘
라는 것에 관한 내용이다.
해당 예제들은 우리가 어떻게 처리할지보다, 무엇을 원하는지를 설명한다.
(우리는 map과 reduce가 어떻게 구현되어있는지는 전혀 알지도 못하고, 관심도 없다)
우리는 아무런 state도 변경하지 않는다. 모든 변경들은 map과 reduce 내부에 추상화되어있다.
그리고 당신이 map과 reduce에 익숙하다는 가정 하에, 훨씬 더 가독성이 좋다.
이제, 마지막 예제를 살펴보자.
여기서는 약간의 편법으로 리액트를 사용했다.
그러나 중요한 것은 명령형의 세 가지 문제점들이 모두 해결이 되었다는 것.
리액트의 진정한 강점은 이러한 선언적인 방식으로 UI를 작성할 수 있다는 것이다.
우리의 Btn 컴포넌트를 보면, 해당 UI가 어떤 식으로 보일지를 빠르게 알아챌 수 있다.
또 다른 강점은 state가 DOM에 존재하는 대신, 우리가 만든 리액트 컴포넌트 자체에 존재한다는 것.
선언적 프로그래밍의 또 다른, 덜 알려진 장점 중의 하나는
우리의 프로그램이 context-independent 해질 수 있다는 것이다.
(전체적인 맥락, 상황에 좀 더 독립적이다)
선언적 코드들은 최종적인 목표가 무엇인지에 대해서만 관심이 있지,
해당 목표를 이루기 위한 세부적인 단계들(해당 목표에 의존적인 과정들)에는 관심이 없다는 것.
그래서 동일한 코드들이 다른 프로그램에 쓰이더라도 정상적으로 동작할 수 있게 된다.
당장 위의 세 예시만 보더라도, 저 함수들이나 컴포넌트는
우리가 만들고자 하는 어떤 프로그램에 갖다붙여도 정상적으로 동작한다.
저들은 현재 어떤 프로그램에 속해있는가 하는 것에 전혀 구애받지 않는다.
명령형 코드들은 그렇지 못한 경우가 많은데, 그 이유는 대부분의 경우
명령형 코드들이 현재 상태의 컨텍스트에 의존적이기 때문이다.
(그래서 다른 곳에서 재사용하기가 어렵다)
이 글의 저자는, 선언적 프로그래밍에서 더 나아가 함수형 프로그래밍까지 다뤄보라고 권유하고 있다.
map, reduce, filter를 사용해보면서 차근차근 시작하라고 하는데, 함수형 프로그래밍에 관해서도
조만간 한 번 알아보는 시간을 가지면 좋을 듯.
개인적으로 가장 와닿았던 부분은, 선언적 프로그래밍은 절차적 구현을 추상화함으로써 이루어진다는 것.
선언적 프로그래밍을 어떻게 해야 하는가에 대해 좀 더 감을 잡을 수 있게 해준 내용인 듯.
리뷰어분들께서 말씀하시는 ‘재사용성’이나 ‘순수 함수’에 관한 것들이 약간 일맥상통하는 부분이 아닌가 싶다.
최대한 독립적이고 재사용성이 높은 함수들을 구현하여, 해당 함수들의 조합으로 프로그래밍을 구성하면
전체 코드의 유지보수가 쉬워지고 가독성도 훨씬 높아지겠지. 그게 말처럼 쉽겠냐마는..
아래는 저자가 웹을 돌아다니며 발견한 선언적 프로그래밍의 또 다른 정의들.
Declarative programming is “the act of programming in languages that conform to the mental model of the developer rather than the operational model of the machine.”
선언적 프로그래밍은 “기계의 동작을 모델로 하는 것이 아닌, 개발자의 두뇌(정신, 생각)를 모델로 본딴 언어를 가지고 프로그래밍 하는 것” 이다.
Declarative Programming is programming with declarations, i.e., declarative sentences.
선언적 프로그래밍은 선언(선언적 문장, 선언문)들을 사용해서 프로그래밍하는 것이다.
?
The declarative property is where there can exist only one possible set of statements that can express each specific modular semantic. The imperative property is the dual, where semantics are inconsistent under composition and/or can be expressed with variations of sets of statements.
선언적 속성이란, 특정 모듈을 설명하는 문장 집합이 단 하나만 존재할 수 있다는 것을 의미한다. 명령적 속성은 이중적이고, 이는 의미들의 구성에 일관성이 없고 여러 가지 문장 집합들로 표현될 수 있다는 것을 의미한다.
Declarative languages contrast with imperative languages which specify explicit manipulation of the computer’s internal state; or procedural languages which specify an explicit sequence of steps to follow.
선언적 언어는 컴퓨터의 내부 상태를 명시적으로 조작하는 명령형 언어, 또는 밟아야 하는 일련의 절차들을 명시적으로 지정하는 절차적 언어와 반대된다.
In computer science, declarative programming is a programming paradigm that expresses the logic of a computation without describing its control flow.
CS에서 선언적 언어는 제어 흐름을 설명하지 않고, 계산 로직을 표현하는 패러다임(개념)이다.
I draw the line between declarative and non-declarative at whether you can trace the code as it runs. Regex is 100% declarative, as it’s untraceable while the pattern is being executed.
나는 코드의 실행을 추적할 수 있는지 여부에 따라 선언형과 비선언형을 구분한다.
정규표현식(Regex)은 패턴이 실행되는 동안 그것을 전혀 추적할 수 없기 때문에 100% 선언적이라고 할 수 있다.
+ Zereight’s Blog에서 본 인상적인 설명
명령형 프로그래밍은 문제를 어떻게 해결해야하는지 컴퓨터에게 명시적으로 명령을 내리는 방법을 의미하고,
선언형 프로그래밍은 무엇을 해결할 것인지에 보다 집중하여 어떻게 문제를 해결하는지에 대해서는
컴퓨터에게 위임하는 방법이다.
처음 프로그래밍이라는 개념이 등장했을 떄부터, 지금까지도 컴퓨터에게 명시적으로 명령을 내리는 방법인
명령형 프로그래밍을 주로 사용했지만, 함수형 프로그래밍은 문제를 해결하는 방법에 더 집중하고
사소한 작업은 컴퓨터에게 넘겨버리는 선언형 프로그래밍의 일종이다.
즉, 컴퓨터에게 사소한 작업들을 위임해버리는 패러다임의 특성 상
선언형 프로그래밍에는 필연적으로 높은 수준의 추상화라는 키워드가 붙는다.
추상화 수준이 낮다면 저 사소한 작업들을 개발자가 일일이 다 컨트롤해야한다는 의미이기 때문이다.