티스토리 뷰

해당 포스팅은 Imperative vs Declarative Programming 원문을 번역하고 각색하여 작성된 포스팅입니다.

 

명령형 프로그래밍과 선언형 프로그래밍에 대한 비교를 어디선가 한 번쯤은 접해봤을 거라 생각합니다. 그리고 그 둘이 실제로 무엇을 의미하는지 검색을 해보셨다면 아마 아래와 같은 정의를 마주했을 것입니다.

 

명령형 프로그래밍은 무엇을 어떻게 할 것인가에 가깝고, 선언형 프로그래밍은 무엇을 할 것인가와 가깝다.

 

이 정의를 처음 보면 무슨 말을 하는지 이해하기 어렵게 느껴집니다. 하지만 이 정의에는 명령형 프로그래밍과 선언형 프로그래밍의 핵심이 담겨 있습니다. 먼저, 이 정의를 쉽게 이해하기 위해 프로그래밍의 맥락에서 벗어나서 실세계의 예제를 살펴보겠습니다.

 

1. Red Lobster

나는 회사에서 열심히 일하고 퇴근을 한 뒤 Red Lobster에서 가족과 즐거운 외식을 하기로 결정했습니다. 그리고 Red Lobster에 도착한 뒤 안내 데스크에 다가가서 말합니다.

 

  • 명령형 방식 (HOW) : "12번 테이블 자리가 비어있습니다. 나와 우리 가족은 저 자리로 걸어가 앉을 것입니다."
  • 선언형 방식 (WHAT) : "네 명 앉을자리를 부탁해요"

위의 예시를 보면 알겠지만 명령형 방식은 내가 실제로 자리에 "어떻게" 자리에 앉을지 에 관심이 있습니다. 따라서 "어떻게" 자리에 앉을지에 대한 단계를 하나하나 나열해야 합니다. 그와 반대로 선언형 방식은 내가 "무엇을" 원하는지에 더 집중되어 있습니다.


2. 집에 돌아가는 법

또 다른 예시를 들어보겠습니다.

아래 질문을 보고 명령형 프로그래밍 방식과 선언형 프로그래밍 방식으로 해결했을 때에 대한 답을 모두 생각해 보았으면 합니다.

 

"나는 지금 e마트 바로 옆에 있습니다. 그럼 여기서부터 집까지 어떻게 가야 할까요?"

 

  • 명령형 방식 (HOW) : 주차장 북쪽 출구를 나와 왼쪽으로 가세요. 12번가 출구에 도착할 때까지 15번 북쪽 도로를 타세요. 이케아를 끼고 우회전하세요. 직진하여 첫 번째 신호등에서 우회전 하세요. 다음 신호등을 지나 좌회전을 하세요. 우리 집은 #298입니다.
  • 선언형 방식 (WHAT)  : 내 주소는 98 West Immutable Alley, Eden, Utah 84310입니다.

3. 수동 스틱과 오토 스틱 자동차

다른 간단한 예시로는 자동차로 설명할 수 있을 것 같습니다.
수동 스틱(1종) 자동차는 명령형 방식이라고 볼 수 있습니다. 그와 반대로 오토 스틱(2종) 자동차는 선언형 방식이라고 볼 수 있습니다. 만약 내가 차를 운전해야 한다면 수동 스틱(명령형) 자동차와 오토 스틱(선언형) 자동차 중 무엇을 운전할 것인가요? 

 


 

위 예시들을 통해 "그럼 자리에 앉는 방법은 누가 알고 있지?", "주소만 알고 있다고 해서 집에 어떻게 돌아가지?"라는 질문이 생길 수 있을 것 같습니다. 사실 선언형 방식이 제대로 동작하기 위해서는 명령형으로 "어떻게"가 구현된 것들이 추상화되어 있어야 합니다.

위에서 살펴본 선언형 예시들에서도 명령형 방식이 추상화된 부분을 찾아볼 수 있습니다. 

 

  1. Red Lobster : 선언형 방식으로 자리에 앉을 때("네 명 자리를 부탁해요") Red Lobster 직원은 우리 가족을 식탁에 데려가는 모든 단계를 알고 있다고 가정하고 있습니다.
  2. 집에 돌아가는 법 : 나는 집으로 가는 명령형 단계를 모두 알고 있는 GPS를 가지고 있다고 가정하고 있습니다.
  3. 오토 스틱(2종) 자동차는 변속 기어 위에 일종의 추상화 레이어가 있습니다.

 


 

그럼 이제 실생활에서 돌아와서 다시 코드를 통해 명령형 프로그래밍과 선언형 프로그래밍의 차이를 살펴보도록 하겠습니다. 아래 코드는 선언형 프로그래밍 방식으로 대표적인 SQL과 HTML의 간단한 예제입니다.

SELECT * FROM Users WHERE Country=’Mexico’;
<article>
  <header>
    <h1>Declarative Programming</h1>
    <p>Sprinkle Declarative in your verbiage to sound smart</p>
  </header>
</article>

두 가지 예제 모두 무엇이 일어나고 있는지 정확하게 이해할 수 있습니다. 두 예제 모두 선언형 프로그래밍이며 원하는 것을 "어떻게" 수행하는 것보다는 "무엇을" 수행하는지에 대해 관심이 있습니다.

 

어떻게 그것을 달성해야 하는지에 대한 설명 없이 무엇을 달성하려 하는지에 대해서만 설명하고 있습니다. 

  • Mexico에 거주하는 모든 사용자를 선택하는 방법에 대한 구현은 추상화되어 있습니다.
  • 웹 브라우저가 어떻게 html 문서를 파싱 하고 보여주는지에 대한 방법은 관심이 없습니다.

그럼 이제 조금 더 와 닿는 Javascript 예제를 통해 명령형 프로그래밍 방식과 선언형 프로그래밍 방식에 대해 살펴보겠습니다.

// 배열을 파라미터로 받고 각 요소들의 값에 2를 곱하는 함수
function double (arr) {
  let results = []
  for (let i = 0; i < arr.length; i++){
    results.push(arr[i] * 2)
  }
  return results
}
// 배열을 파라미터로 받고 각 요소들을 합한 값을 반환하는 함수
function add (arr) {
  let result = 0
  for (let i = 0; i < arr.length; i++){
    result += arr[i]
  }
  return result
}
// 버튼이 클릭 되었을 때 highlight 클래스를 토글하는 jquery listener
$("#btn").click(function() {
  $(this).toggleClass("highlight")
  $(this).text() === 'Add Highlight'
    ? $(this).text('Remove Highlight')
    : $(this).text('Add Highlight')
})

이 3가지 예시의 공통점이 무엇인지 살펴보면 실제로 필수 요소가 무엇인지 더 잘 식별할 수 있습니다.

 

  1. 가장 명백한 공통점은 세 예제 모두 "어떻게"를 설명하고 있다는 점입니다. 명시적으로 배열을 반복하거나 원하는 기능을 수행하는 방법에 대한 단계를 설명하고 있습니다.
  2. 각 예시 모두 '상태'의 일부를 변경하고 있습니다 ('상태' : 기본적으로 메모리에 저장된 것에 대한 정보라고 볼 수 있습니다 - 변수와 비슷). 처음 두 예제에서는 results라는 변수를 만든 다음 계속 수정하고 있습니다. 세 번째 예제에서는 변수가 없지만 DOM의 상태를 가지고 있습니다. 그리고 DOM 의 상태를 수정합니다.
  3. 약간 주관적일 수 있지만 위의 코드들은 읽기 쉽지 않습니다. 코드를 보고 무슨 일이 일어나고 있는지 한 번에 이해할 수 없습니다. 코드를 정확하게 이해하려면 발생 가능한 상황(변동 가능한 데이터)을 고려하면서 컴파일러처럼 코드를 단계별로 살펴봐야 합니다.

그럼 선언형 프로그래밍 방식으로 위의 3가지의 문제점들을 고쳐보도록 하겠습니다. 따라서 각각의 예시들은 "어떻게"가 아닌 "무엇" 이 일어나는지를 설명해야 합니다. 그리고 상태를 변경할 수 없으며, 한눈에 읽을 수 있어야 합니다.

function double (arr) {
  return arr.map((item) => item * 2)
}
function add (arr) {
  return arr.reduce((prev, current) => prev + current, 0)
}
<Btn
  onToggleHighlight={this.handleToggleHighlight}
  highlight={this.state.highlight}>
    {this.state.buttonText}
</Btn>

처음 두 예제에서는 JavaScript에 기본으로 내장된 map과 reduce 메서드를 활용했습니다. 이는 반복해서 이야기했던 내용과 마찬가지로 명령형 방식이 추상화된 것입니다. 선언형 프로그래밍의 중요한 솔루션은 명령형으로 작성된 구현에 대한 추상화입니다.

 

모든 예시들은 "어떻게" 보다 "무엇" 이 이루어지기를 원하는지를 설명합니다. (나는 map과 reduce 가 어떻게 이루어져 있는지 알지 못하고 신경 쓸 필요조차 없습니다) 그리고 상태를 변경하는 모든 지점들은 map과 reduce 메서드 안쪽으로 추상화되어 나는 직접 상태를 변경하지 않습니다. 또한 위 예제들은 훨씬 가독성이 높습니다. (map과 reduce 함수에 익숙하다면) 

그럼 세 번째 예제는 어떨까요? 사실 세 번째 예제에 React 문법이 약간 포함되어 있습니다. 하지만 이전 예제에서 언급된 세 가지 문제는 수정되었습니다. React의 진정한 장점은 위의 예제처럼 선언적인 방식으로 UI를 만들 수 있다는 것입니다. 

 

선언형 프로그래밍의 또 다른 이점은 프로그램이 상황에 독립적일 수 있다는 것 입니다. 종종 명령형 코드는 현재 상태의 컨텍스트에 의존하기 때문에 재사용하기 어려운 경우가 많습니다. 하지만 선언형 코드는 해당 코드가 달성하고자 하는 것이 무엇인지 만을 나열하기 때문에 동일한 코드를 다른 프로그램에서 재사용하기 쉽습니다.

마치며


선언형 프로그래밍은 rx를 접하게 되면서 관심을 가지게 되었는데요, rx의 특징 중 하나가 선언적 스타일로 코드를 작성하게 된다는 것이었습니다. rx를 제품에 도입하기에 앞서 rx를 왜 도입해야 하는지, rx를 도입함으로써 얻는 이점이 무엇인지를 탐구하고 설득할 수 있는 근거를 만들기 위해 알아보는 시리즈 중 첫 단계로써 해당 포스팅을 작성하게 되었습니다.

그래서 알아본 선언형 프로그래밍은 코드의 가독성과 재사용성을 높일 수 있다는 매력이 있는 것 같습니다. 하지만 결국 스스로 다양한 상황과 소프트웨어에서 직접 적용해보고 경험해 봐야 무엇이 진짜 어떻게 좋은지 판단할 수 있는 힘이 생기는 것 같습니다.

  • "어떻게"가 아닌 "무엇을" 달성할지를 나열하는 방식
  • 그 "무엇을" "어떻게" 달성할지는 추상화되어있는 것을 사용하거나, 추상화시킨다
  • 선언형 방식으로 코드를 작성하면 여러 곳에서 재사용하기 비교적 쉽다.

원문


해당 포스팅은 Imperative vs Declarative Programming 원문을 번역하고 각색하여 작성된 포스팅입니다. 오역, 오류가 있다면 댓글로 피드백 주시면 감사합니다.

 

Imperative vs Declarative Programming

A guide to understanding the difference between Imperative and Declarative programming.

tylermcginnis.com

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/03   »
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
글 보관함