프로그래밍 패러다임

**프로그래밍 패러다임**(programming paradigm)은 컴퓨터 프로그램의 구현을 개념화하고 구조화하는 비교적 높은 수준의 방법이다. 하나의 프로그래밍 언어는 하나 또는 여러 개의 패러다임을 지원하는 것으로 분류될 수 있다.

패러다임은 프로그래밍의 서로 다른 측면에 따라 구분되고 설명된다. 어떤 패러다임은 부작용을 허용할지 여부나 연산의 순서가 실행 모델에 의해 정의되는지 여부와 같은 실행 모델의 함의에 관한 것이다. 다른 패러다임은 상태와 동작을 모두 포함하는 단위로 그룹화하는 것과 같이 코드가 조직되는 방식에 관한 것이다. 또 다른 것들은 구문 및 형식 문법에 관한 것이다.

일반적인 프로그래밍 패러다임의 일부는 다음과 같다(계층적 관계로 표시됨):
* 명령형  코드가 제어 흐름과 상태 변화를 직접 제어하며, 프로그램 상태를 변경하는 명시적인 문을 사용함
** 절차적  서로를 호출하는 절차들로 조직됨
** 객체 지향  데이터 구조와 관련 동작을 모두 포함하는 객체들로 조직되며, 데이터 필드와 메서드로 구성된 데이터 구조와 그들 사이의 상호작용(객체)을 사용하여 프로그램을 설계함
*** 클래스 기반 – 객체 자체가 아닌 객체의 클래스를 정의함으로써 상속이 이루어지는 객체 지향 프로그래밍
*** 객체 기반 – 객체가 상태와 동작을 캡슐화하는 구문을 갖는 패러다임
*** 프로토타입 기반 – 클래스를 피하고 인스턴스의 복제를 통해 상속을 구현하는 객체 지향 프로그래밍
* 선언형  코드가 원하는 결과의 속성을 선언하지만 계산 방법은 선언하지 않으며, 상세한 상태 변화를 지정하지 않고 수행해야 할 계산이 무엇인지 설명함
** 함수형  원하는 결과가 일련의 함수 평가값으로 선언되며, 수학적 함수의 평가를 사용하고 상태와 가변 데이터를 피함
** 논리형  원하는 결과가 사실과 규칙 시스템에 대한 질문의 답으로 선언되며, 프로그래밍에 명시적인 수리 논리를 사용함
** 반응형  데이터 흐름과 변경 사항의 전파를 통해 원하는 결과가 선언됨
* 병행 프로그래밍 – 병행성을 위한 언어 구문을 가지며, 이는 멀티스레딩, 분산 컴퓨팅 지원, 메시지 전달, 공유 자원(공유 메모리 포함) 또는 퓨처를 포함할 수 있음
** 행위자 프로그래밍 – 환경에 반응하여 지역적인 결정을 내리는 행위자들을 이용한 병행 계산(이기적이거나 경쟁적인 동작이 가능함)
* 제약 프로그래밍 – 변수 사이의 관계가 제약 조건(또는 제약 네트워크)으로 표현되어 허용 가능한 해를 유도함(단체법 또는 제약 충족 사용)
* 데이터플로 프로그래밍 – 데이터 값이 변경될 때 공식의 재계산을 강제함 (예: 스프레드시트)
* 분산 프로그래밍 – 컴퓨터 네트워크를 통해 통신하는 여러 자율 컴퓨터들을 지원함
* 제네릭 프로그래밍 – 나중에 지정될 유형으로 작성된 알고리즘을 사용하며, 이후 매개변수로 제공된 특정 유형에 대해 필요에 따라 인스턴스화됨
* 메타프로그래밍 – 다른 프로그램(또는 자기 자신)을 데이터로 작성하거나 조작하는 프로그램을 작성하거나, 런타임에 수행될 작업의 일부를 컴파일 타임에 수행함
** 템플릿 메타프로그래밍 – 컴파일러가 템플릿을 사용하여 임시 소스 코드를 생성하고, 이를 나머지 소스 코드와 병합하여 컴파일하는 메타프로그래밍 방법
** 반영 프로그래밍 – 프로그램이 자기 자신을 수정하거나 확장하는 메타프로그래밍 방법
* 파이프라인 프로그래밍 – 원래 중첩 함수 호출 구문이 없도록 설계된 언어에 이를 추가하기 위한 단순한 구문 변경
* 규칙 기반 프로그래밍 – 지식 베이스를 구성하는 경험 법칙의 네트워크로, 전문가 시스템 및 문제 추론과 해결에 사용될 수 있음
* 시각적 프로그래밍 – 프로그램 요소를 텍스트로 지정하기보다 그래픽으로 조작함 (예: 시뮬링크); 도식적 프로그래밍이라고도 함

## 개요
섬네일|250px|left|피터 판 로이가 정리한 다양한 프로그래밍 패러다임의 개요

프로그래밍 패러다임은 기존의 소프트웨어 개발 관행에 대한 컴퓨터 과학 연구에서 비롯되었다. 연구 결과는 프로그래밍 관행과 프로그램을 작성하는 데 사용되는 언어를 설명하고 비교할 수 있게 해준다. 관점의 차이로, 다른 연구 분야에서는 소프트웨어 공학 프로세스를 연구하고 이들을 설명하고 비교하기 위해 다양한 방법론을 기술한다.

프로그래밍 언어는 패러다임의 관점에서 설명될 수 있다. 어떤 언어들은 단 하나의 패러다임만을 지원한다. 예를 들어, 스몰토크는 객체 지향을 지원하고 하스켈은 함수형을 지원한다. 대부분의 언어는 다중 패러다임을 지원한다. 예를 들어, C++, 오브젝트 파스칼, 또는 PHP로 작성된 프로그램은 순수하게 절차적일 수도 있고, 순수하게 객체 지향일 수도 있으며, 두 패러다임 혹은 다른 패러다임의 측면을 모두 포함할 수도 있다.

다중 패러다임을 지원하는 언어를 사용할 때, 개발자는 어떤 패러다임 요소를 사용할지 선택한다. 하지만 이 선택이 패러다임 그 자체를 고려하는 것을 의미하지는 않을 수도 있다. 개발자는 종종 언어가 제공하는 기능을 개발자가 알고 있는 범위 내에서 사용한다. 결과물인 소스 코드를 패러다임별로 분류하는 것은 흔히 사후에 이루어지는 학술적 활동이다.

**명령형 패러다임**으로 분류되는 언어는 두 가지 주요 특징을 갖는다. 연산이 발생하는 순서를 명시하고 그 순서를 명시적으로 제어하는 구문을 가지며, 특정 시점에 코드 한 단위 내에서 상태를 수정하고 나중에 다른 코드 단위 내에서 다른 시점에 이를 읽을 수 있는 부작용을 허용한다. 코드 단위 간의 통신은 명시적이지 않다.

대조적으로, **선언형 패러다임**의 언어는 연산을 실행할 순서를 명시하지 않는다. 대신 시스템에서 사용 가능한 여러 연산과 각 연산이 실행될 수 있는 조건을 제공한다. 언어의 실행 모델 구현은 어떤 연산이 실행 가능한지 추적하고 독립적으로 순서를 선택한다. 자세한 내용은 다중 패러다임 프로그래밍 언어의 비교를 참조하라.

**객체 지향** 프로그래밍에서 코드는 객체의 코드에 의해 소유되고 (보통) 제어되는 상태를 포함하는 객체들로 조직된다. 대부분의 객체 지향 언어는 명령형 언어이기도 하다.

객체 지향 프로그래밍에서 프로그램은 상호작용하는 객체들의 집합으로 취급된다. 함수형 프로그래밍에서 프로그램은 상태가 없는 함수 평가의 시퀀스로 취급된다. 다수의 프로세서를 가진 컴퓨터나 시스템을 프로그래밍할 때, **프로세스 지향 프로그래밍**에서 프로그램은 논리적인 공유 자료 구조에서 작동하는 병행 프로세스들의 집합으로 취급된다.

많은 프로그래밍 패러다임은 지원하는 기술만큼이나 금지하는 기술로도 잘 알려져 있다. 예를 들어, 순수 함수형 프로그래밍은 부작용을 허용하지 않으며, 구조적 프로그래밍은 goto 구문을 허용하지 않는다. 부분적으로 이러한 이유 때문에, 새로운 패러다임은 종종 기존의 것에 익숙한 사람들에게 교조적이거나 지나치게 엄격한 것으로 간주되기도 한다. 하지만 특정 기술을 피함으로써 프로그램의 동작을 더 쉽게 이해하고 프로그램의 올바름에 대한 정리를 증명하는 것이 더 쉬워질 수 있다.

프로그래밍 패러다임은 API만을 사용하여 실행 모델을 호출할 수 있게 해주는 프로그래밍 모델과도 비교될 수 있다. 프로그래밍 모델 또한 실행 모델의 특징에 따라 패러다임으로 분류될 수 있다.

병렬 컴퓨팅의 경우, 언어 대신 프로그래밍 모델을 사용하는 것이 일반적이다. 그 이유는 병렬 하드웨어의 상세한 내용이 하드웨어를 프로그래밍하는 데 사용되는 추상화로 유출되기 때문이다. 이로 인해 프로그래머는 알고리즘의 패턴을 (하드웨어 유출로 인해 추상화에 삽입된) 실행 모델의 패턴에 매핑해야 한다. 결과적으로, 하나의 병렬 프로그래밍 언어가 모든 계산 문제에 잘 들어맞지는 않는다. 따라서 기본 순차 언어를 사용하고 프로그래밍 모델을 통해 병렬 실행 모델에 대한 API 호출을 삽입하는 것이 더 편리하다. 이러한 병렬 프로그래밍 모델은 공유 메모리, 메시지 전달 방식의 분산 메모리, 코드에서 가시적인 장소(place)의 개념 등 하드웨어를 반영하는 추상화에 따라 분류될 수 있다. 이들은 병렬 언어와 프로그래밍 모델에만 적용되는 프로그래밍 패러다임의 일종으로 간주될 수 있다.

## 비판

로버트 하퍼 및 슈리람 크리슈나무르티와 같은 일부 프로그래밍 언어 연구자들은 프로그래밍 언어의 분류로서 패러다임이라는 개념을 비판한다. 그들은 많은 프로그래밍 언어가 하나의 패러다임으로 엄격하게 분류될 수 없으며, 오히려 여러 패러다임의 기능을 포함하고 있다고 주장한다. 다중 패러다임 프로그래밍 언어의 비교를 참조하라.

## 역사

프로그래밍에 대한 다양한 접근 방식은 시간이 흐르면서 발전해 왔다. 각 접근 방식의 분류는 그 방식이 처음 개발될 당시에 설명되기도 했지만, 종종 한참 시간이 흐른 뒤에 사후적으로 이루어졌다. 의식적으로 그렇게 식별된 초기 접근 방식 중 하나는 1960년대 중반부터 주창된 구조적 프로그래밍이다. 프로그래밍 패러다임이라는 개념 자체는 최소 1978년 로버트 플로이드의 튜링상 강연인 《프로그래밍의 패러다임》(The Paradigms of Programming)으로 거슬러 올라가는데, 그는 토머스 쿤이 그의 저서 《과학혁명의 구조》(1962)에서 사용한 패러다임의 개념을 인용했다. 초기 프로그래밍 언어들은 명확하게 정의된 프로그래밍 패러다임을 가지고 있지 않았으며, 때때로 프로그램들이 goto 문을 과도하게 사용하여 이해와 유지보수가 어려운 스파게티 코드를 만들어내기도 했다. 이는 goto 문의 사용을 금지하고 더 구조화된 프로그래밍 구문만을 허용하는 구조적 프로그래밍 패러다임의 개발로 이어졌다.

## 언어와 패러다임

### 기계어

기계어는 컴퓨터가 이해할 수 있는 추상화의 가장 낮은 단계에서 동작을 정의하는 명령어 집합으로, 컴퓨터 프로그래밍의 가장 낮은 단계이다. 이는 코드를 작성하는 가장 지시적인 방식이므로 명령형으로 분류된다.

때때로 이를 1세대 프로그래밍 언어라고 부른다.

### 어셈블리

어셈블리어는 기계 명령어와 메모리 주소에 대한 니모닉(mnemonics)을 도입했다. 어셈블리는 명령형으로 분류되며 때때로 2세대 프로그래밍 언어라고 불린다.

1960년대에 어셈블리어는 라이브러리 COPY와 매우 정교한 조건부 매크로 생성 및 전처리 기능, 서브루틴 호출(CALL), 외부 변수 및 공용 섹션(전역)을 지원하도록 발전하여, READ/WRITE/GET/PUT과 같은 논리 연산자를 통해 하드웨어 특성으로부터 상당한 코드 재사용과 격리를 가능하게 했다. 어셈블리는 기계가 수행하는 작업에 대해 가장 많은 제어권을 제공하기 때문에 시간적으로 중요한 시스템과 임임베디드 시스템에서 과거에도 사용되었고 지금도 여전히 사용되고 있다.

### 절차적 언어

3세대 프로그래밍 언어라고도 불리는 절차적 언어는 최초로 고급 프로그래밍 언어로 기술된 언어들이다. 이들은 해결하려는 문제와 관련된 어휘를 지원한다. 예를 들면 다음과 같다.
* COmmon Business Oriented Language (코볼) 파일, move, copy와 같은 용어를 사용한다.
* FORmula TRANslation (포트란) 수학적 언어 용어를 사용하며, 주로 과학 및 공학 문제를 위해 개발되었다.
* ALGOrithmic Language (알골) 포트란과 마찬가지로 과학 및 공학 문제를 대상으로 수학적 언어 용어를 사용하면서, 알고리즘을 정의하기에 적절한 언어가 되는 데 집중했다.
* Programming Language One (PL/I) 포인터를 지원하는 상업적-과학적 하이브리드 범용 언어이다.
* Beginners All purpose Symbolic Instruction Code (베이직) 더 많은 사람들이 프로그램을 작성할 수 있도록 개발되었다.
* C 1969년에서 1973년 사이에 AT&T 벨 연구소의 데니스 리치가 처음 개발한 범용 프로그래밍 언어이다.

이러한 언어들은 절차적 패러다임으로 분류된다. 이들은 컴퓨터 프로그램이 따르는 단계별 프로세스를 직접 제어한다. 따라서 이러한 프로그램의 효능과 알고리즘 효율성은 프로그래머의 기술에 크게 의존한다.

### 객체 지향 프로그래밍

절차적 언어를 개선하려는 시도로 시뮬라, 스몰토크, C++, 에펠, 파이썬, PHP, 자바, C 샤프와 같은 객체 지향 프로그래밍(OOP) 언어들이 만들어졌다. 이러한 언어에서 자료와 자료를 조작하는 메서드는 객체라고 불리는 동일한 코드 단위 안에 있다. 이러한 캡슐화는 객체가 데이터에 접근하는 유일한 방법이 데이터를 포함하는 객체의 메서드를 통하는 것임을 보장한다. 따라서 객체를 사용하는 코드에 영향을 주지 않고 객체의 내부 작동 방식을 변경할 수 있다.

알렉산더 스테파노프, 리처드 스톨먼 및 다른 프로그래머들은 절차적 패러다임 대비 OOP 패러다임의 효능에 대해 논쟁을 제기해 왔다. 모든 객체가 연관된 메서드를 가져야 할 필요성 때문에 일부 회의론자들은 OOP를 소프트웨어 블롯과 연관시키기도 하며, 이러한 딜레마를 해결하려는 시도는 다형성을 통해 이루어졌다.

대부분의 OOP 언어는 3세대 언어이지만, 객체 지향 어셈블러 언어를 만드는 것도 가능하다. High Level Assembly(HLA)는 초기 기원에도 불구하고 고급 데이터 유형과 객체 지향 어셈블리어 프로그래밍을 완전히 지원하는 사례이다. 따라서 서로 다른 프로그래밍 패러다임은 한 단계에서 다음 단계로의 발전을 반드시 나타낸다기보다는, 옹호자들의 동기 부여적인 밈과 같은 것으로 볼 수 있다. 경쟁하는 패러다임들의 효능에 대한 정확한 비교는, 유사한 엔티티와 프로세스에 적용되는 새롭고 상이한 용어들과 언어 전반에 걸친 수많은 구현 차이로 인해 종종 어려움을 겪는다.

### 선언형 언어

선언형 프로그래밍 프로그램은 문제를 해결하는 방법이 아니라 문제가 무엇인지를 설명한다. 프로그램은 따라야 할 절차가 아니라 예상 결과에서 찾고자 하는 속성들의 집합으로 구조화된다. 데이터베이스나 규칙 집합이 주어지면 컴퓨터는 원하는 모든 속성과 일치하는 해를 찾으려고 시도한다. 선언형 언어의 전형적인 예로는 4세대 프로그래밍 언어인 SQL과 함수형 언어 및 논리형 프로그래밍 가족이 있다.

함수형 프로그래밍은 선언형 프로그래밍의 하위 집합이다. 이 패러다임을 사용하여 작성된 프로그램은 수학적 함수처럼 동작하도록 의도된 코드 블록인 서브루틴을 사용한다. 함수형 언어는 대입을 통한 변수 값의 변경을 지양하고, 대신 재귀를 많이 사용한다.

논리형 프로그래밍 패러다임은 계산을 지식체에 대한 자동화된 추론으로 본다. 문제 도메인에 관한 사실들은 논리식으로 표현되며, 프로그램은 문제에 대한 답을 찾거나 공식 집합이 모순임을 증명할 때까지 추론 규칙을 적용하여 실행된다.

### 기타 패러다임

심볼릭 프로그래밍은 공식과 프로그램 구성 요소를 데이터로 조작할 수 있는 프로그램을 설명하는 패러다임이다. 따라서 프로그램은 효과적으로 자기 자신을 수정하고 "학습"하는 것처럼 보일 수 있어, 인공지능, 전문가 시스템, 자연어 처리 및 컴퓨터 게임과 같은 응용 분야에 적합하다. 이 패러다임을 지원하는 언어로는 리스프와 프롤로그가 있다.

미분 가능 프로그래밍은 프로그램 전체에서 보통 자동 미분을 통해 미분이 가능하도록 프로그램을 구조화한다.

문학적 프로그래밍은 명령형 프로그래밍의 한 형태로서, 하이퍼텍스트 에세이와 같이 인간 중심의 망(web)으로 프로그램을 구조화한다. 문서화가 프로그램의 필수적인 부분이며, 프로그램은 컴파일러의 편의가 아니라 산문 설명의 논리에 따라 구조화된다.

프로그램이 자기 자신을 참조할 수 있게 하는 반영 프로그래밍(리플렉션)과 같은 심볼릭 프로그래밍 기법 또한 프로그래밍 패러다임으로 간주될 수 있다. 그러나 이는 주요 패러다임들과 호환되므로 그 자체로 독립적인 진정한 패러다임은 아니다.

## 같이 보기

* 언어 지향 프로그래밍
* ARS 기반 프로그래밍
* 문법 지향 프로그래밍

## 각주


분류:프로그래밍 언어 분류
분류:프로그래밍 언어 주제