Declarative, Imperative

ou·2024년 1월 18일
0

basic

목록 보기
6/24

들어가며

프로그램 덩치가 작을 땐 좋은 코드와 나쁜 코드가 구별되지 않는다.
오히려 초반에는 나쁜 코드가 생산성이 높다. 하지만 일정 규모를 넘어설때 코드에 설계가 없다면 점점 생산성이 떨어진다. 그렇기에 우리는 좋은 설계를 해야하고 유지하려는 노력이 필요하다.

'좋은 설계를 유지한다'는 한번이 아닌 코드 전반에 걸쳐 일관적인 원칙과 규칙으로 작성돼야 하기 때문이다. 이런 원칙과 방법을 우리는 프로그래밍 패러다임이라고 부르고 있다.

앞에서 글로 적은 적 있떤 객체 지향 프로그래밍은 객체를 중심으로 사고하고 프로그램을 작성하는 방법이라면, 함수형 프로그래밍은 함수를 중심으로 사고하고 프로그래밍하는 것이다.(적고보니 그냥 이름을 풀어쓴거잖아?)

Imperative(명령형)

HOW

어떻게 해야할지 기술
목표를 달성하는데 필요한 절차 작성

앞에서 한번 정리한적 있던 객체 지향 프로그래밍인 명령형 프로그래밍의 하위 집합이라 볼 수 있다.

Declarative(선언형)

WHAT

무엇을 원하는지 기술
달성하고자 하는 결과 작성

하지만 선언형 프로그래밍은 여전히 ​​보이지 않는 곳에서 명령형 프로그래밍을 사용하므로, 순수한 선언적 코드를 작성하는 것은 불가능해!

맞는 말이다.
컴퓨터가 ChatGPT도 아니고 무엇을 원하는지 말하기만 하면 답을 내어줄 수 있겠나? (나중에는 가능할지도 모르겠다.)
핵심은 순수한 선언형 코드를 작성하는게 아니고 명령적 코드를 구현 세부 사항만 나타내도록 추상화하는 것

나에게 이해하기 쉬운 예시로 SQL 이 있었다.
SELECT * FROM projects WHERE id > 100;
어떻게 가져오는지는 관심 없다. 오직 내가 얻고 싶은 결과를 기술했다.

더하기(함수형)

함수형 프로그래밍을 빼놓고 선언형 프로그래밍만 말하기 어렵다.
선언형 프로그래밍의 하위 집합을 함수형 프로그래밍으로 본다.

함수형 프로그래밍은 사이드 이펙트가 없는 것이 특징.
함수 외부 데이터에 의존하지 않으며, 외부에 있는 데이터를 변경하지 않는다.
함수형의 모든 것은 이러한 속성에서 파생된다.

함수형 프로그래밍의 원칙
1. 순수함수
- 입출력이 순수해야한다.
- 들어온 인자가 같다면 항상 같은 값을 반환
- 외부의 상태에 영향을 끼치지 않음
2. 부작용이 없어야 한다.
3. 일급함수
함수를 값으로 다뤄 다른 함수의 매개변수로 제공
변수에 할당, 인자로 전달, 반환값으로 사용, 동적 프로퍼티 할당이 가능해야한다.
4. 고차함수
함수를 인자로 받거나 반환하는 함수로 함수를 추상화하고 조합성을 높이는데 사용

입출력이 순수하다는 것은 하나 이상의 인자를 받고 결과를 돌려주어야 한다는 것. 인자를 제외한 다른 외부 변수를 사용하면 안된다는 것.

부작용이 없어야한다는 것은, 원본데이터는 불변해야함.

아래는 비 함수형 function 의 예제인데
함수가 외부 데이터 변수인 a에 의존하고 있다.

var a = 0;
function increase(){
	return a += 1;
}
increase() // 1;

이를 함수형으로 바꾸면


function increase(a){
	return a+1;
}
increase(0); //1

불변성 - 카피 온 라이트, 방어적 복사

함수가 여러번 실행돼도 외부 영향에 값이 변경되지 않아야함.
함수가 객체나 배열을 인자로 사용한다면, JS는 기본적으로 pass by reference 방식을 사용하기에 언제든 외부에서 값이 수정되거나 내부에서 외부로 영향을 미칠 수 있다는 것을 알아야함.
이것을 방지하기 위해 객체나 배열을 pass by value로 변경하는 방식을 알아야함

함수에서 배열이나 객체의 원본 값을 직접 수정하면 메모리상으로 효율적이겠지만 외부에 영향을 끼쳐 더 큰 혼란을 초래할 수 있음

얕은 복사와 깊은 복사가 있는데 깊은 복사를 위해 최근 structuredClone() API가 Native로 추가됐으니 이를 활용하면 됨

불변성 - 카피 온 라이트와 방어적 복사를 이용해 불변성을 유지

선언적 패턴과 계층형 구조

설계는 엉킨 코드를 푸는 것

코드를 작게 분리하면 좋은 점

  • 재사용이 쉽다.
  • 유지보수가 쉽다.
  • 테스트하기 쉽다.

이렇게 분리한 코드를 조합하는 과정에서 자연스레 함수 간에 계층이 생기는 것을 알 수 있음.

계층을 나누고 계층을 침범하지 않도록 코드를 작성하면 추상화 벽이 만들어지며, 벽 너머로 영향을 미치지 않도록 할 수 있음.

선언적 패턴 : 계층형 설계와 추상화 벽으로 '무엇'과 '어떻게'를 구분하는 좋은 설계 유지

함수형 라이브러리들
상태관리를 하는 Redux, 반응형 프로그래밍에 함수형 프로그래밍 개념을 엮은 rxjs, 불변성 관리를 위한 immutable.js 등이 있음. 이처럼 특정 목적성을 가진 여러 라이브러리가 함수형 패러다임을 적절히 결합하는 방식으로 발전

함수형 프로그래밍은 함수형 라이브러리를 배우는 것이 아님.
함수형 패러다임, 함수형 사고를 해야함.

실전에서 적용하기 좋은 함수형 사고
1. 프로그램을 액션 - 계산 - 데이터로 구분
2. 계산은 가급적 명시적 입력과, 출력으로 만들어서 테스트
3. 코드의 계층적 구조를 그려보고 같은 계층의 레벨에 맞는 위치에 코드 작성
4. 계층을 뛰어넘는 코드를 작성하지 않도록

참고자료
https://yozm.wishket.com/magazine/detail/2083/ (선언, 명령)
https://yozm.wishket.com/magazine/detail/1485/ (함수형 ⭐⭐)
https://www.zerocho.com/category/JavaScript/post/576cafb45eb04d4c1aa35078 (함수형 ⭐)
https://medium.com/@mr.november11/%EB%B2%88%EC%97%AD-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-ec0a95dc49d1
https://github.com/icepeng/articles/blob/master/imperative-and-declarative-programming.md (선언형)
https://velog.io/@injoon2019/%EB%AA%85%EB%A0%B9%ED%98%95-vs-%EC%84%A0%EC%96%B8%ED%98%95-%ED%95%A8%EC%88%98%ED%98%95 (선언형)

profile
경험을 현명하게 사용한다면, 어떤 일도 시간 낭비는 아니다.

0개의 댓글

관련 채용 정보