본문 바로가기
카테고리 없음

선언적 프로그래밍 vs 명령형 프로그래밍

by xogns93 2024. 11. 8.

선언적 프로그래밍과 명령형 프로그래밍은 프로그래밍의 두 가지 주요 패러다임으로, 코드를 작성하는 방식 문제를 해결하는 접근 방식에 차이가 있습니다. 이 두 가지 패러다임의 차이와 각각의 특징을 알아보겠습니다.

1. 선언적 프로그래밍 (Declarative Programming)

  • 정의: 코드가 무엇을 해야 하는지에 초점을 맞추는 방식입니다. "어떻게" 수행하는지보다는 목표 상태를 기술합니다.
  • 특징:
    • 무엇을 수행할지에만 집중: 원하는 최종 상태만 설명하고, 이를 위한 과정은 프레임워크나 시스템이 알아서 처리하도록 합니다.
    • 비상태적: 코드가 상태 변화를 유발하지 않고 데이터의 흐름을 정의하는 경우가 많습니다.
    • 가독성 향상: 절차적 로직 없이 최종 상태만 설명하기 때문에 코드가 간결하고 이해하기 쉽습니다.
    • 대표 예시: SQL 쿼리, HTML/CSS, 함수형 프로그래밍, 리액티브 프로그래밍.
  • 장점:
    • 간결한 코드: 복잡한 절차를 생략하고 결과만을 정의하므로 코드가 간단하고 직관적입니다.
    • 유지보수 용이: 상태 변화가 적고 로직이 단순하기 때문에 수정과 유지보수가 쉽습니다.
  • 단점:
    • 복잡한 로직 표현의 어려움: 로직이 복잡해질 경우 선언적 방식만으로는 표현하기 어려운 경우가 생깁니다.
    • 성능 최적화 제약: 절차적 과정을 직접 제어할 수 없으므로 성능 최적화가 제한될 수 있습니다.

2. 명령형 프로그래밍 (Imperative Programming)

  • 정의: 코드가 어떻게 해야 하는지에 초점을 맞추는 방식입니다. 일련의 **명령(단계)**으로 문제를 해결합니다.
  • 특징:
    • 절차적 로직: 문제를 해결하기 위한 절차와 단계별 명령을 코드로 작성합니다.
    • 상태 변화: 변수를 통해 상태를 관리하고 변경하면서 로직을 구성합니다.
    • 대표 예시: 전통적인 Java, C, Python 등에서의 반복문과 조건문을 사용한 코드, 객체 지향 프로그래밍.
  • 장점:
    • 직접 제어 가능: 모든 과정을 명확하게 제어할 수 있어 성능 최적화나 세밀한 로직 처리가 용이합니다.
    • 복잡한 로직 구현 용이: 복잡한 로직을 세부 단계로 나누어 구현할 수 있습니다.
  • 단점:
    • 코드 복잡성 증가: 여러 단계의 절차와 상태 변화를 일일이 작성해야 하므로 코드가 길어지고 복잡해질 수 있습니다.
    • 가독성 저하: 로직의 모든 단계가 상세히 표현되기 때문에 가독성이 떨어질 수 있습니다.

예시를 통한 비교

간단한 예로 리스트에서 짝수를 필터링하는 코드를 보겠습니다.

 

명령형 프로그래밍 (Imperative)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ImperativeExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
        List<Integer> evenNumbers = new ArrayList<>();

        for (Integer number : numbers) {
            if (number % 2 == 0) {
                evenNumbers.add(number);
            }
        }

        System.out.println("짝수 리스트: " + evenNumbers);
    }
}

설명:

  • 이 코드에서는 리스트의 각 요소를 직접 순회하며(for 반복문 사용), 각 요소가 짝수인지 확인하는 조건 검사를 수행합니다.
  • if (number % 2 == 0) 조건문을 통해 짝수인 경우에만 새로운 리스트에 추가됩니다.
  • 즉, 리스트의 모든 요소를 하나씩 직접 처리하며 단계별로 명확히 작성되어 있습니다.
  • **"어떻게 짝수를 수집할지"**를 일일이 설명하는 방식입니다. 이를 통해 짝수를 수집하는 전체 로직의 절차를 세부적으로 보여줍니다.

 

 

선언적 프로그래밍 (Declarative)

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class DeclarativeExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

        List<Integer> evenNumbers = numbers.stream()
                                           .filter(number -> number % 2 == 0)
                                           .collect(Collectors.toList());

        System.out.println("짝수 리스트: " + evenNumbers);
    }
}

설명:

  • 이 코드에서는 .filter(number -> number % 2 == 0)을 사용해 짝수만 필터링하겠다는 조건만 명시합니다.
  • numbers.stream() 메서드를 통해 리스트를 스트림으로 변환하고, .filter 메서드를 사용해 짝수 조건을 걸어줍니다.
  • 최종적으로 .collect(Collectors.toList())를 사용해 필터링된 요소들만 새로운 리스트에 담습니다.
  • 이 방식에서는 반복문을 사용하지 않고, 짝수라는 조건만을 명확하게 전달합니다.
  • **"무엇을 필터링할지"**에만 집중하고, 실제로 어떻게 처리될지는 스트림 API가 알아서 수행합니다.

 

 

차이점 요약

특징선언적 프로그래밍명령형 프로그래밍

초점 무엇을 해야 하는지에 집중 어떻게 해야 하는지에 집중
코드 스타일 직관적이고 간결함 절차적, 단계별 코드가 필요
상태 변화 관리 상태 변화가 거의 없음 상태 변화가 필수적
가독성 높음 복잡할 수 있음
활용 예시 SQL, HTML/CSS, 함수형 및 리액티브 프로그래밍 객체 지향 프로그래밍, 전통적인 루프와 조건문
제어 수준 낮음 높음

정리

선언적 프로그래밍은 주로 목표 상태만 정의하고 이를 처리하는 로직은 프레임워크나 시스템에 위임하는 방식입니다. 반면 명령형 프로그래밍은 구체적인 로직을 명확히 작성하여 절차를 하나하나 정의해 나가는 방식입니다. 각 스타일은 상황과 문제에 따라 적절히 선택하여 사용할 수 있습니다.