Book/개발

[ 프레임워크 없는 프론트엔드 개발 ] 선언형?명령형?

ウリ김영은 2024. 12. 13. 17:52

1장 프레임워크에 대한 이야기

1장을 읽다 보면, 리액트에 관한 이야기를 할 때 선언적 패러다임, 선언적 패턴, 명령형 패턴 단어들이 보인다. 

 

선언적 패턴이 무엇이고, 명령형 패턴은 무엇이며, 

이 둘의 차이는 뭘까?

 

선언형?명령형 ? 

리액트 공식 홈페이지에 처음 들어가면 다음과 같은 화면이 나타난다. 

리액트 공식 홈페이지

 

 

선언형 프로그래밍(Declarative Programming) 이란?

 

원하는 결과를 묘사하는 방식으로 코드를 작성하는 프로그래밍 패러다임

 

 

 

원하는 결과를 선언하고

구체적인 실행 과정은 추상화해서

"무엇을" 할지에 초점을 맞춘다.

What To Do

 

 

명령형 프로그래밍(Imperative Programming) 이란?

코드가 어떻게 동작해야 하는지를 작성하는 프로그래밍 패러다임

 

 

 

단계별로 정확히 무엇을 할지 명시하고

컴퓨터에게 정확한 실행 방법을 지시해서

"어떻게" 해야 할는지에 초점을 맞춘다. 

- How To Do

 

 

 

예시1)

배열에서 짝수만 필터링하는 로직을 통해 이해를 해보자. 

 

- 선언형 프로그래밍

const numbers = [1,2,3,4,5,6,7,8,9,10];
const evenNumbers = numbers.filter(num => num % 2 === 0)

console.log(evenNumbers) // [2,4,6,8,10]

 

위 예시는 짝수를 어떻게 필터링해야 하는지가 아닌, 짝수를 필터링한 결과를 얻는 것에 초점이 맞춰져 있습니다. 

다른 말로, 원하는 데이터가 무엇인지에 집중을 하고 있습니다. 

 

 

- 명령형 프로그래밍 

const numbers = [1,2,3,4,5,6,7,8,9,10];
const evenNumbers = [];

for(let i=0; i<numbers.length; i++){
	const num = numbers[i]
    if(num % 2 === 0){
    	evenNumbers.push(num)
    }
}

console.log(evenNumbers) // [2,4,6,8,10]

 

위의 로직을 말로 풀어보면,

"만약 num이 2로 나누어 떨어진다면 evenNumbers 배열에 해당 변수(i)를 push하고 아니면 다음 숫자로 넘어간다.(i++)"

 

선언형과 달리 문제를 해결하는 구체적인 과정 이 작성되어 있습니다. 

 

 

 

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

 

예시2) 자동차를 주차하는 함수(로직) 

 

- 선언형 프로그래밍

function parkCar(car) {
    return parkingLot.findEmptySpace()
        .then(space => car.parkInSpace(space));
}

 

위의 코드는 원하는 결과만 선언하고 있고, 구현의 세부사항은 숨겨져 있습니다. 

 

 

- 명령형 프로그래밍

function parkCar(car) {
    // 1. 주차장 입구로 이동
    car.moveToEntrance();
    
    // 2. 빈 주차 공간 찾기
    for(let i = 0; i < parkingLot.spaces.length; i++) {
        if(parkingLot.spaces[i].isEmpty) {
            car.currentSpace = i;
            break;
        }
    }
    
    // 3. 방향 전환
    car.turnWheel(45);
    
    // 4. 후진
    car.reverseGear();
    car.moveBackward();
    
    // 5. 주차 완료
    car.stopEngine();
}

 

반면 두번째 코드는 주차 과정을 단계별로 상세히 지시하고 있습니다. 

 

 

선언형, 명령형의 장단점

이처럼 선언형 프로그래밍 스타일로 코드를 작성하면 전체적인 가독성과 추상화 수준을 높여 

개발자가 문제의 본질에 집중할 수 있도록 도와줍니다. 

또한 이러한 작업을 통해 재사용성이 높고 병렬 처리가 유리합니다. 

 

반대로 명령형 프로그래밍 은 상태와 제어 흐름을 명시적으로 관리함으로써 

세밀한 제어가 가능하여 정확한 결과를 얻을 수 있고, 성능 최적화에 용이합니다. 

다만 코드의 가독성이 저하되거나 재사용성이 낮아질 수 있어 코드 관리에 많은 노력이 필요합니다. 

 

 

 

리액트는 선언형 뷰(UI) ?

const LoginForm = () => {
	return (
    	<article>
        	<p>ID</p>
            <input name='id' type='text'/>
            <p>PASSWORD</p>
            <input name='password' type='password'/>
        </article>
    )
}

 

왜 위의 코드를 보고 선언형 UI로 작성되었다고 하는 걸까요?

 

개발자가 원하는 LoginForm의 모습(결과)만 return 하고 있으며, 어떻게 화면에 보이게 할 건지는 작성되어 있지 않습니다. 

 

즉, UI를 다루는 부분은 리액트에게 위임하고,개발자는 결과에만 초점을 맞춰 개발을 할 수 있습니다. 

개발자가 직접 DOM을 수정하는 대신 상태가 변경되었을 때 리액트가 나머지 작업을 수행하는 것입니다.

 

 

 

-끝


참조

https://yozm.wishket.com/magazine/detail/2083/

Claude