2025-08-09 10:16
Tags:
프로그래밍 패러다임 핸드북
1. 만들어진 이유: 문제 해결을 위한 다양한 접근 방식의 필요성
초기 컴퓨터 프로그래밍은 단순히 기계가 이해할 수 있는 명령어(기계어)를 나열하는 방식. 하지만 프로그램의 규모가 커지고 복잡해지면서 이런 방식은 한계에 봉착. 코드의 재사용이 어렵고, 수정이나 유지보수가 거의 불가능에 가까웠기 때문.
이를 해결하기 위해 사람들은 코드를 더 체계적으로 구성하고, 문제에 더 효과적으로 접근할 수 있는 ‘생각의 틀’을 고안. 이것이 바로 프로그래밍 패러다임의 시작.
- 비유: 요리에 비유할 수 있음. 똑같은 재료(데이터)를 가지고도 한식 레시피(절차지향), 양식 코스요리 레시피(객체지향), 분자요리 레시피(함수형) 등 다양한 조리법(패러다임)에 따라 과정과 결과물이 달라지는 것과 같음. 각 패러다임은 특정 종류의 문제를 더 우아하고 효율적으로 해결하기 위해 만들어짐.
2. 구조: 주요 프로그래밍 패러다임의 종류와 핵심 개념
프로그래밍 패러다임은 크게 명령형 프로그래밍과 선언형 프로그래밍 두 가지로 나눌 수 있음.
가. 명령형 프로그래밍 (Imperative Programming)
-
‘어떻게(How)’ 할 것인지를 명시하는 방식. 컴퓨터에게 수행할 명령을 순서대로 상세하게 지시.
-
상태(State) 와 상태를 변경시키는 구문(Statement) 이 중심.
1) 절차지향 프로그래밍 (Procedural Programming)
-
프로그램을 ‘절차(Procedure)’ 또는 ‘함수(Function)’ 의 연속으로 보는 관점. 데이터는 부차적.
-
코드를 기능 단위로 묶어 재사용성을 높임.
-
핵심 요소: 프로시저(함수), 전역 변수, 순차적 실행
-
대표 언어: C, Pascal, Fortran
2) 객체지향 프로그래밍 (Object-Oriented Programming, OOP)
-
프로그램을 상호작용하는 ‘객체(Object)’ 들의 집합으로 보는 관점. 데이터와 그 데이터를 처리하는 함수(메서드)를 하나로 묶어 객체로 만듦.
-
핵심 요소:
-
캡슐화 (Encapsulation): 데이터와 기능을 객체 안에 숨기고, 외부 노출을 제어.
-
상속 (Inheritance): 부모 객체의 속성과 기능을 자식 객체가 물려받음.
-
다형성 (Polymorphism): 같은 이름의 메서드가 다른 객체에서 다른 방식으로 동작.
-
추상화 (Abstraction): 불필요한 세부 정보는 숨기고, 핵심적인 기능만 노출.
-
-
대표 언어: Java, C++, Python, C#
나. 선언형 프로그래밍 (Declarative Programming)
-
‘무엇을(What)’ 할 것인지를 기술하는 방식. ‘어떻게’ 해결할지는 컴퓨터에 위임.
-
직접적인 제어 흐름이나 상태 변경을 다루지 않음.
1) 함수형 프로그래밍 (Functional Programming)
-
프로그램을 순수 ‘함수(Function)’ 의 조합으로 보는 관점. 부수 효과(Side Effect)를 최소화하고 상태 변경을 피함.
-
핵심 요소:
-
순수 함수 (Pure Function): 동일한 입력에 대해 항상 동일한 출력을 반환.
-
불변성 (Immutability): 생성된 후에는 상태를 변경할 수 없는 데이터.
-
1급 객체 (First-class Citizen): 함수를 변수에 할당하거나, 다른 함수의 인자로 전달하거나, 반환 값으로 사용할 수 있음.
-
-
대표 언어: Lisp, Haskell, F#, JavaScript(부분적 지원)
2) 논리 프로그래밍 (Logic Programming)
-
프로그램을 ‘논리적인 추론’ 의 집합으로 보는 관점. 주어진 사실과 규칙에 기반하여 목표를 증명하는 방식으로 동작.
-
대표 언어: Prolog
3. 사용법: 패러다임별 코드 예시
“1부터 10까지의 합을 구하는” 동일한 문제를 각 패러다임으로 어떻게 다르게 해결하는지 살펴봄.
가. 절차지향 (C 언어)
- 어떻게:
total
변수를 만들고,for
반복문을 이용해 1부터 10까지 순서대로 더해나가는 과정을 명시.
#include <stdio.h>
int main() {
int total = 0;
for (int i = 1; i <= 10; i++) {
total += i; // 상태(total)를 직접 변경
}
printf("Total: %d\n", total);
return 0;
}
나. 객체지향 (Java)
- 어떻게: 합계를 계산하는 책임을 가진
Calculator
객체를 설계.calculateSum
메서드를 통해 계산을 수행.
class Calculator {
public int calculateSum(int n) {
int total = 0;
for (int i = 1; i <= n; i++) {
total += i;
}
return total;
}
}
public class Main {
public static void main(String[] args) {
Calculator calculator = new Calculator(); // 객체 생성
int sum = calculator.calculateSum(10); // 객체의 메서드 호출
System.out.println("Total: " + sum);
}
}
다. 함수형 (JavaScript)
- 무엇을: 1부터 10까지의 배열을 만들고(
Array.from
), 그 배열의 모든 요소를 더한다(reduce
)는 ‘무엇’을 할 것인지만 선언.
// 1부터 10까지 숫자로 이루어진 배열을 생성
const numbers = Array.from({ length: 10 }, (_, i) => i + 1);
// reduce 함수를 이용해 합계를 구함
// 이전 값(acc)과 현재 값(cur)을 더하는 함수를 전달
const sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log("Total: " + sum);
4. 심화 내용: 멀티-패러다임 언어와 패러다임의 선택
현대의 많은 프로그래밍 언어는 하나의 패러다임만 지원하지 않음. Python, JavaScript, C++ 등은 여러 패러다임을 지원하는 멀티-패러다임 언어. 개발자는 문제의 성격에 따라 가장 적합한 패러다임을 선택하거나 조합하여 사용할 수 있음.
- 예시: 웹 프론트엔드 개발에서 UI 컴포넌트는 객체지향적으로 설계하고, 서버와의 데이터 통신이나 상태 관리는 함수형으로 처리하여 코드의 안정성과 예측 가능성을 높이는 식.
패러다임 선택 기준:
-
문제의 종류: 계산이 많은 과학 분야는 절차지향이나 함수형이, 복잡한 시스템을 모델링해야 하는 경우는 객체지향이 유리할 수 있음.
-
팀의 숙련도: 팀원들이 익숙한 패러다임을 사용하는 것이 생산성에 도움.
-
프로젝트의 규모 및 유지보수: 대규모 프로젝트일수록 구조화되고 예측 가능한 객체지향이나 함수형 패러다임이 유지보수에 유리.
각 패러다임은 우열의 관계가 아닌, 문제 해결을 위한 서로 다른 도구 상자와 같음. 다양한 패러다임에 대한 이해는 더 나은 문제 해결 능력으로 이어짐.