[TIL] 2022-04-01 / 10일차
미음제
·2022. 4. 1. 18:54
오늘 배운 내용
명령형 프로그래밍과 선언적인 프로그래밍 방식의 이해
명령형 프로그래밍
컴퓨터 과학에서 명령형 프로그래밍(命令型 프로그래밍, 영어: imperative programming)은 선언형 프로그래밍과 반대되는 개념으로, 프로그래밍의 상태와 상태를 변경시키는 구문의 관점에서 연산을 설명하는 프로그래밍 패러다임의 일종이다. 자연 언어에서의 명령법이 어떤 동작을 할 것인지를 명령으로 표현하듯이, 명령형 프로그램은 컴퓨터가 수행할 명령들을 순서대로 써 놓은 것이다.
쉽게 말해서 명령형 프로그래밍은 "컴퓨터가 수행할 명령들을 순서대로 나열한 것."이다. "어떻게?"라는 방법에 중점을 두고 있다.
컴퓨터에게, "내가 지금 이러한 데이터를 원하는데 1번부터 10번까지 순서대로 탐색해보고, 거기서 짝수일 때는 넘어가고 나머지 결과를 계산해줘." 이렇게 명령을 하는 것이라고 할 수 있다. 프로그래밍을 배우기 시작할 때 대부분 처음 접하는 방법이다(가장 기초적인 for loop는 모든 언어에서 비슷하게 쓰인다. 명령형 인 줄도 모르고 있었다). 중요한 것은 "어떻게 구현하는가?"를 디테일하게 기술하는 것에 관점이 있다는 것이다.
선언형 프로그래밍
프로그램이 어떤 방법으로 해야 하는지를 나타내기보다 무엇과 같은지를 설명하는 경우에 "선언형"이라고 한다. 예를 들어, 웹 페이지는 선언형인데 웹페이지는 제목, 글꼴, 본문, 그림과 같이 "무엇"이 나타나야 하는지를 묘사하는 것이지 "어떤 방법으로" 컴퓨터 화면에 페이지를 나타내야 하는지를 묘사하는 것이 아니기 때문이다. 이것은 전통적인 포트란과 C, 자바와 같은 명령형 프로그래밍 언어와는 다른 접근방식인데, 명령형 프로그래밍 언어는 프로그래머가 실행될 알고리즘을 명시해주어야 하는 것이다. 간단히 말하여, 명령형 프로그램은 알고리즘을 명시하고 목표는 명시하지 않는 데 반해 선언형 프로그램은 목표를 명시하고 알고리즘을 명시하지 않는 것이다.
우리가 알고 있는 대표적인 선언형 프로그래밍 언어로 HTML과 SQL이 있다. HTML의 경우 작성할 때, 트리의 구조로 화면에 그리고 싶은 tag들을 작성하면 화면에 tag들이 렌더링 된다. 이때, 개발자는 tag들이 어떻게 위치하고 그려지는지는 알 필요가 없고 무엇이 나타내는지만 선언해주면 되는 것이다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
<script src="index.js"></script>
</body>
</html>
이렇게 div tag 안에 ul tag가 들어오고, 그 안에 li tag들이 나열된다고 선언만 해주었을 뿐 화면에 어떻게 그려지는지는 신경 쓰지 않는 것이다.
만약 HTML 언어가 선언형 언어가 아니었다면? tag 하나하나가 화면에 어떻게 그려져야 하는지 명령형으로 어렵게 화면을 구성했을 것이다.
SQL에서도 student table에서 name 데이터를 원한다고 선언만 해주면 데이터를 어떻게 조회해서 가져오는지는 알 필요 없이 원하는 데이터를 가져올 수 있다(select name from student).
간단한 예제 코드로 명령형과 선언형의 차이를 보면 다음과 같다.
let tmp = [1,2,3,4,5];
let result1 = [];
for(let i=0; i<tmp.length; i++){
result1.push(tmp[i] * 2);
}
console.log(result1)
let result2 = tmp.map((value) => {
return value * 2;
})
console.log(result2)
result1과 result2는 같은 결과를 출력하지만, 작성하는 방법에서 차이가 있다. result1은 명령형의 결과인데 for loop에서 0번째부터 tmp 배열의 길이만큼 1씩 증가하며 탐색하고, 값에 2를 곱한 후 result 배열에 추가하라고 컴퓨터에게 명령하고 있다. 어떤 값들이 필요한지, 어떻게 할 것인지 하나하나 모두 기술하고 있다.
result2는 선언형의 결과인데 map 함수를 통해 값에 2를 곱한 것을 반환하라고 선언되어 있지만 result1과 똑같은 결과가 나온다. 간단한 예라서 코드의 길이가 비슷해 보이지만 로직이 복잡하고 조건이 여러 개라면 선언형이 단연 길이가 짧고 가독성이 좋아진다. 어떻게 처리할 것인가 보다 "무엇을"에 집중하고 있다.
map, reduce, forEach, filter 등을 통해 선언형 프로그래밍을 실현할 수 있다.
선언형 프로그래밍을 지향해야 하는 이유?
명령형으로 코드를 작성하게 된다면 기능의 추가, 유지보수 등에 어려움이 있다. 처음엔 간단한 기능에서 시작해서 여러 조건들이 붙고 기존 코드를 활용해 확장하려 할 때마다 코드가 복잡해지고 가독성도 떨어지게 된다. 즉, 새로운 로직이 추가될 때마다 규칙성 없이 코딩되어 유지보수와 확장이 어려워지는 것이다. 또한 명령형은 명령 순서에 따라 코드가 동작하는 방식이 달라질 수 있는데 명령 순서가 꼬이게 되어 에러가 발생할 위험도 높아진다.
반면 선언형 프로그래밍으로 작성하게 된다면 추상화된 개념으로 기능을 묶어 응집력을 높일 수 있고 해당 기능을 활용해 기능을 확장하기에도 용이하다.
간단하게 코드로 비교해보면 다음과 같다.
명령형으로 버튼 3개를 추가하여 렌더링 하기
// 버튼 3개 만들기
const $button1 = document.createElement('button');
$button1.textContent = 'button 1';
const $button2 = document.createElement('button');
$button2.textContent = 'button 1';
const $button3 = document.createElement('button');
$button3.textContent = 'button 1';
// 버튼을 화면에 렌더링
const $body = document.querySelector('body');
$body.appendChild($button1);
$body.appendChild($button2);
$body.appendChild($button3);
// 버튼 클릭 이벤트
$button1.addEventListener('click', () => {
console.log("this is button 1");
});
$button2.addEventListener('click', () => {
console.log("this is button 2");
});
$button3.addEventListener('click', () => {
console.log("this is button 4");
});
선언형으로 버튼 3개를 추가하여 렌더링 하기
function Button({
$tartget,
text
}){
const $button = document.createElement('button');
$tartget.appendChild($button);
$button.addEventListener('click', () => {
console.log(`this is ${$button.textContent}`);
})
this.render = () => {
$button.textContent = text;
}
this.render();
};
const $body = document.querySelector('body');
new Button({
$tartget: $body,
text: 'button 1'
});
new Button({
$tartget: $body,
text: 'button 2'
});
new Button({
$tartget: $body,
text: 'button 3'
});
명령형은 버튼 3개를 직접 추가해주어야 하고, 직접 버튼의 text도 지정해주어야 하고, 화면에 추가해주어야 하고, 버튼의 event도 각각 달아주어야 한다.
그러나 선언형은 Button 컴포넌트 하나를 활용해 새로운 버튼만 추가하겠다고 선언하기만 하면 된다.
같은 결과를 보이는 코드도 명령형과 선언형의 차이가 분명하다.
부족한 점
- 선언형 프로그래밍의 이해
- 고차 함수
느낀 점
선언형 프로그래밍의 효율성에 대해 놀랐다. 정처기를 준비하며 들어봤던 용어들이다. 명령형, 선언형. 그러나 무엇이 명령형인지? 선언형인지? 정확하게 인지하지 못했다. 다만 언어의 종류를 구분하는 정도로만 알고 있었다. 자격증 시험을 위한 암기의 단점.. 클론 코딩이나 가벼운 과제들을 진행할 때, 새로운 tag를 작성할 때마다 복잡하게 명령형으로 작성해왔던 것 같다. tag가 늘어나고 로직이 복잡해지면서 에러가 발생할 때마다 고치는데 애를 먹었던 기억이 있다. 내가 작성했던 방식이 명령형 인지도 인지하지 못했었고, 이렇게 복잡하게만 코드를 작성해야 하는 줄로만 알고 있었다.
강의를 들으며 선언형 코드의 좋은 가독성을 느꼈고 재사용성, 확장성에 대해 살짝 맛보기만 했는데 잘 활용하기만 하면 좋은 무기가 될 것 같다. 선언형을 잘 활용하기 위해 고차 함수를 많이 공부하고 활용할 줄 알아야 할 것 같다. 그리고 좋은 코드, 간결한 코드를 작성하는 것이 단순히 코드의 길이를 줄이는 것이라고만 생각했는데 선언형으로 작성할 수 있을지 고민을 해봐야 할 것 같다.
'프로그래머스 > 데브코스 프론트엔드' 카테고리의 다른 글
[TIL] 2022-04-05 / 12일차 (0) | 2022.04.06 |
---|---|
[TIL] 2022-04-04 / 11일차 (0) | 2022.04.04 |
[TIL] 2022-03-31 / 9일차 (0) | 2022.03.31 |
[TIL] 2022-03-30 / 8일차 (0) | 2022.03.30 |
[TIL] 2022-03-29 / 7일차 (0) | 2022.03.30 |