개발 R.I.P.

7.06 Dev.Feedback (프로그래밍 패러다임)

편행 2021. 7. 6. 21:06
반응형

패러다임

프로그래밍을 하는 기초적인 방법을 말한다.

언어에 독립적이며 어떤 프로그래밍 구조를 사용할지, 언제 구조를 사용해야 하는지를 결정하게 해주는 기준이다.

즉, 프로그래머에게 프로그래밍 관점을 제공해준다.

패러다임은 무엇을 해야할지를 제시하기 보다는 추가적인 규칙들을 부과하여 하면 안되는 기준을 제시한다.

 

순차적 프로그래밍(Sequential Programming), 비구조적 프로그래밍(Non-structured programming)

이름에서 유추할 수 있듯 코드가 순서대로 흘러가는 방식이다.

구조라는 개념이 없어서 goto문을 사용했다.

하지만, 수 많은 goto문의 남용으로 인해 코드 자체에 대한 이해가 어려워지고(순서를 신경써야 하므로 여기저기 왔다 갔다 해야하는)

보수를 해야되는 상황이 벌어지면 엄청난 혼란을 야기하게 됐다.

 

절차적 프로그래밍(Procedural Programming), 구조적 프로그래밍(Structured Programming)

최초로 적용된 패러다임이다.

구조화 프로그래밍으로도 불리며 프로그래밍 패러다임의 일종인 절차적 프로그래밍의 하위 개념으로 볼 수 있다.

단순히 순차적인 명령 수행이 아니라 루틴, 서브루틴, 메소드, 함수 등(이를 통틀어 *프로시저라고 한다.)을 이용한 프로그래밍 패러다임을 뜻한다.

  • 여기서 *프로시저 역시 함수이다. 하지만 어떤 값을 return 하는 것이 아닌 실행하는 것에 중점이 놓인 함수로 볼 수 있다.

절차적 프로그래밍의 발전한 형식이 구조적 프로그래밍이다. 절차적 프로그래밍이 함수를 기준으로 나누는 반면, 구조적 프로그래밍은 반복될 가능성이 있는 *모듈을 재사용 가능한 프로시저 단위(함수단위)로 나누어 사용한다.

  • 여기서 *모듈은 또한 여러 프로시저가 모여서 만들어진 소스 파일이다.

goto -> if/then/else/do/while/until

 

그러나 이런 절차적(구조적)프로그래밍도 문제가 발생하게 됐는데, 프로시저라는 것이 함수의 실행 같은 추상적인 부분에만 국한되어 있기에 어떤 구체적인 자료들을 저장하고 다뤄야 하는 상황 즉,물리적인 요소(변수나 상수등의 값들)을 관리하는 방법에서는 약점이 나타나게 된 것이다.

 

이 문제를 예시로 들어보면 만일 어떤 사이트에 사용자가 가입을 하게 됐을 때 우리는 그 사용자의 정보를 저장해두고 필요할 때 그 사용자의 정보를 가져와서 검사를 하고 적합성을 판단하거나 만일 어떤 물품을 주문했을 때 가입했을 때 입력한 정보를 통해 주소를 알고 주문한 상품을 보내주게 된다. 근데 구조적 프로그래밍 하에서 이 기능을 구현하려면 사용자의 정보를 따로 두고 사용자의 정보를 물러오는 함수를 또 따로 둬야하게 되는 것이다. 이것이 양이 적으면 개발자가 얼추 알아볼 수는 있겠지만, 만일 양이 넘처나게 되면 프로그래밍을 하는 데에 있어 방대한 양의 코드를 해석해야 하는 상황에 빠지게 되는 것이다.

 

즉 사용자의 자료와 사용자의 자료를 불러오거나 활용할 수 있는 함수를 한 번에 묶어줄 수 있는 패러다임이 필요하게 됐다. 

 

객체 지향 프로그래밍(Object-Oriented Programming)

이런 필요성에 기반해서 등장한 것이 객체지향 프로그래밍이다.

객체지향 프로그래밍은 사용자의 자료와 함수를 한 번에 묶어줄 수 있는 패러다임이다.

객체지향 프로그래밍에서 중요한 특징은 모든 객체가 그 내부에 자료형(Field)와 함수(Method)가 포함하고 있다는 것이다.

이런 특징에서 볼 수 있 듯 객체지향 프로그래밍은 가능한 모든 물리적, 논리적 요소들을 객체로 만드려고 한다.

 

만일 우리가 객체지향 프로그래밍을 통해 하나의 객체 내부에 자료형과 함수를 완전히 구성했다면, 그 객체는 다른 객체로부터 독립을 했다고 말할 수 있다. (물론 완벽히 독립됐다라고는 할 수 없을지도 모른다.)

이런 객체지향 프로그래밍 패러다임을 적용하면, 초반에 객체를 구성하는데만 조금 시간이 걸릴 뿐, 중복 코딩이 줄게되고 객체와 객체간에 독립성이 확립되어 유지보수에 큰 도움이 된다.

 

객체지향 프로그래밍 또한 많은 변화를 겪었는데, 초창기에는 정말로 변수와 함수를 묶는 선에서 끝났지만 독립성이 무기라는것을 알게됨으로 그 독립성을 지키는 방향으로 발전해 왔다.  이런 방향성에 따른 기술이 은닉화와 캡슐화, 다형성, 상속이다. 이런 기술이 추가됨으로 객체는 초기보다 훨씬 독립적이고 효율적인 형태로 탈바꿈 하였다.

 

함수형 프로그래밍(Functional Programming)

명령형 프로그래밍을 기반으로 개발했던 개발자들은 개발하는 소프트웨어의 크기가 커짐에 따라, 복잡하게 엉켜있는 스파게티 코드를 유지보수하는 것이  매우 힘들다는 것을 깨닫게 되었다. 그리고 이를 해결하기 위해 함수형 프로그래밍이라는 프로그래밍 패러다임에 관심을 갖게 되었다. 함수형 프로그래밍은 거의 모든 기능을 순수 함수로 나누어 문제를 해결하는 기법으로, 가장 작은 단위의 문제를 해결하기 위한 함수를 작성하여 가독성을 높이고 유지보수를 용이하게 해준다.

명령형 프로그래밍(객체지향 프로그래밍의 상위개념이라고 생각해도 좋다)에서는 메소드를 호출하면 상황에 따라 내부의 값이 바뀔 수 있다. (side effects를 발현한다.) 즉, 우리가 개발한 함수 내에서 선언된 변수의 메모리에 할당된 값이 바뀌는 등의 변화가 발생할 수 있다.

하지만 함수형 프로그래밍에서는 대입문이 없기 때문에 메모리에 한 번 할당된 값은 새로운 값으로 변할 수 없다.

 

함수형 프로그래밍을 한 문장으로 나타내면

부수 효과가 없는 순수 함수를 1급 객체로 간주하여 파라미터로 넘기거나 반환값으로 사용할 수 있으며, 참조 투명성을 지킬 수 있다.

여기서 부수효과(Side Effect)란 다음과 같은 변화 또는 변화가 발생하는 작업을 의미한다.

  • 변수의 값이 변경됨
  • 자료 구조를 제자리에서 수정함
  • 객체의 필드값을 설정함
  • 예외나 오류가 발생하며 실행이 중단됨
  • 콘솔 또는 파일 I/O가 발생함

 

그리고 이러한 부수 효과(Side Effect)들을 제거한 함수들을 순수 함수(Pure Function)이라고 부르며, 함수형 프로그래밍에서 사용하는 함수는 이러한 순수 함수들이다.

  • Memory or I/O의 관점에서 Side Effect가 없는 함수
  • 함수의 실행이 외부에 영향을 끼치지 않는 함수

 

순수 함수(Pure Function)을 이용하면 얻을 수 있는 효과는 다음과 같다.

  • 함수 자체가 독립적이며 Side-Effect가 없기 때문에 Thread에 안전성을 보장받을 수 있다.
  • Thread에 안정성을 보장받아 병렬 처리를 동기화 없이 진행할 수 있다.

 

그리고 1급 객체란 다음과 같은 것들이 가능한 객체를 의미한다.

  • 변수나 데이터 구조 안에 담을 수 있다.
  • 파라미터로 전달 할 수 있다.
  • 반환값으로 사용할 수 있다.
  • 할당에 사용된 이름과 무관하게 고유한 구별이 가능하다.

함수형 프로그래밍에서 함수는 1급 객체로 취급받기 때문에 위의 예제에서 본 것 처럼 함수를 파라미터로 넘기는 등의 작업이 가능한 것이다. 또한 우리가 일반적으로 알고 개발했던 함수들은 함수형 프로그래밍에서 정의하는 순수 함수들과는 다르다는 것을 인지해야 한다.

(Javascript에서 함수형 프로그래밍을 우선적으로 할 수 있는 이유가 여기에서도 드러난다고 생각한다.)

 

마지막으로 참조 투명성(Referential Transparency)이란 다음과 같다. --> 이 부분 조차 순수함수 자체의 영역이라 생각하고 있었는데, 순수함수가 상위카테고리로 참조 투명성이라는 특징을 갖고 잇는 것이라고 생각해야 할 듯 하다.

  • 동일한 인자에 대해 항상 동일한 결과를 반환해야 한다.
  • 참조 투명성을 통해 기존의 값은 변경되지 않고 유지된다.(Immutable Data)

명령형 프로그래밍과 함수형 프로그래밍에서 사용하는 함수는 부수효과의 유/무에 따라 차이가 있다. 그에 따라 함수가 참조에 투명한지 안한지 나뉘어 지는데, 참조에 투명하다는 것은 말 그대로 함수를 실행하여도 어떠한 상태의 변화 없이 항상 동일한 결과를 반환하여 항상 동일하게(투명하게) 실행 결과를 참조(예측)할 수 있다는 것을 의미한다.

 

즉, 어떤 함수 f에 어떠한 인자 x를 넣고 f를 실행하게 되면, f는 입력된 인자에만 의존하므로 항상 f(x)라는 동일한 결과를 얻는다는 것을 의미한다. 부작용을 제거하여 프로그램의 동작을 이해하고 예측을 용이하게 하는 것은 함수형 프로그래밍으로 개발하려는 핵심 동기 중 하나이다. 그리고 이러한 부분인 병렬 처리 환경에서 개발할 때 Race Condition에 대한 비용을 줄여준다. 왜냐하면 함수형 프로그래밍에서는 값의 대입이 없이 항상 동일한 실행에 대해 동일한 결과를 반환하기 때문이다.

 

출처 : https://mangkyu.tistory.com/111  

참조

반응형

'개발 R.I.P.' 카테고리의 다른 글

7.09 Dev.Feedback (Redux)  (0) 2021.07.09
7.07 Dev.Feedback (Ajax)  (0) 2021.07.07
7.05 Dev.Feedback ( React #7 컴포넌트 디자인)  (0) 2021.07.05
7.04 Dev.Feedback (Node.js #3)  (0) 2021.07.04
7.03 Dev.Feedback (Side Effect)  (0) 2021.07.03