
쏙쏙 들어오는 함수형 코딩 Chapter 1~6
오랜만에 스터디를 시작하였다. 3주동안 하나의 주제, 총 6개의 주제에 대해 다루는 긴 호흡의 스터디인데 중간에 하차하지 않고 끝까지 잘해나가고 싶다!
Chapter 1 : 쏙쏙 들어오는 함수형 코딩에 오신 것을 환영합니다
#함수형 프로그래밍 (from 위키)
#- 수학 함수를 사용하고 부수 효과를 피하는 것이 특징인 프로그래밍 패러다임
- 부수 효과 없이 순수 함수만 사용하는 프로그래밍 스타일
부수효과
- 함수가 리턴값 이외에 하는 모든일
순수 함수
- 인자에만 의존하고 부수 효과가 없는 함수
But!
실용적인 측면에서 부수 효과는 필요하다, 순수 함수만 쓸 수는 없다.
액션과 계산, 데이터 구분하기
#함수형 프로그래머는 코드를 액션, 계산, 데이터로 구분한다.
액션
- 실행 시점이나 횟수에 의존함
계산
- 입력값으로 출력값을 만드는 것
데이터
- 이벤트에 대해 기록한 사실
구분했을 때의 장점
#여러 컴퓨터가 네트워크 통신을 하기 시작하면 소프트웨어는 복잡해진다.
이때 실행 시점이나 횟수에 의존하는 코드를 없애면 코드를 더 쉽게 이해할 수 있으며 심각한 버그를 막을 수 있다.
데이터와 계산은 실행 시점이나 횟수에 의존하지 않는다. 그래서 코드를 데이터와 계산로 바꿀수록 소프트웨어에서 생기는 여러 문제를 해결할 수 있다.
액션은 실행 시점이나 횟수에 의존하지만 코드 전체에 영향을 주지 않도록 격리하면 된다.
Chapter 2 : 현실에서의 함수형 사고
#2장에서는 주방을 자동화하는 소프트웨어를 예시로 함수형 사고를 적용 해본다.
타임라인 커팅
#- 선제 작업이 끝날 때까지 기다린다. (액션이 올바른 순서로 실행할 수 있도록 보장해준다.)
A, B, C, D라는 일이 있고, A, B, C 라는 일이 모두 끝난 후(A, B, C 간의 순서는 없음) D라는 일이 시작되어야 한다면 타임라인 커팅이라는 기술을 활용한다.
Chapter 3 : 액션과 계산, 데이터의 차이를 알기
#액션
#- 부수 효과가 있는 함수, 순수하지 않은 함수
- 외부 세계에 영향을 주거나 받는 것
- 실행 시점과 횟수에 의존
- 함수로 구현 가능
- 액션을 잘 사용하기 위한 방법
- 가능한 액션을 적게 사용한다
- 액션은 가능한 작게 만든다
- 액션이 호출 시점에 의존하는 것을 제한한다
계산
#- 순수함수
- 실행 시점과 횟수에 관계없이 항상 같은 입력값에 대해 같은 출력값을 돌려줌
- 함수로 구현 가능
- 액션보다 좋다 (아래 이유로)
- 테스트가 쉽다
- 분석이 쉽다
- 조합하기 좋다
데이터
#- 이벤트에 대해 기록한 사실
- 일어난 일의 결과를 기록한 것
요점 정리
#액션 안에는 계산과 데이터, 또 다른 액션이 숨어 있을 수 있다.
액션은 외부 세계에 영향을 주거나 받는다.
계산은 더 작은 계산, 데이터 나눌 수 있다.
계산은 외부 세계에 영향을 주거나 받지 않으며 실행 시점이나 횟수에 의존하지 않는다.
계산은 같은 입력값을 주면 항상 같은 출력값이 나오기 때문에 액션보다 테스트하기 쉽다.
Chapter 4 : 액션에서 계산 빼내기
#함수에 암묵적 입력과 출력(부수효과)이 있으면 액션이 된다
계산 추출의 단계
#- 계산 코드를 찾아 빼낸다.
- 새 함수에 암묵적 입력과 출력을 찾는다.
- 암묵적 입력은 인자로 암묵적 출력은 리턴값으로 바꾼다.
As-is
function calc_cart_total() {
shopping_cart_total = 0;
for(var i = 0; i < shopping_cart.length; i++) {
var item = shopping_cart[i];
shopping_cart_total += item.price;
}
...
}To-be
function calc_cart_total() {
shopping_cart_total = calc_total(shopping_cart);
...
}
function calc_total(cart) {
var total = 0;
for(var i = 0; i < cart.length; i++) {
var item = cart[i];
total += item.price;
}
return total;
}암묵적 입력인 전역변수가 calc_total 안에서 없어졌다. 또한 암묵적 출력을 없애고 함수가 결괏값을 리턴하도록 개선하였다.
Chapter 5 : 더 좋은 액션 만들기
#액션은 필요하기 때문에 모든 액션을 없앨 수는 없다. 하지만 암묵적 입력과 출력은 적을수록 좋다
비즈니스 요구 사항과 함수를 맞추기
#비즈니스 요구사항이 합계 금액과 제품 가격에 대한 무료 배송 여부가 아니고 주문 결과가 무료 배송인지 확인해야한다면 어떻게 코드를 바꿔야 할까?
As-is
function gets_free_shipping(total, item_price) {
return item_price + total >= 20;
}
function calc_total(cart) {
var total = 0;
for(var i = 0; i < cart.length; i++) {
var item = cart[i];
total += item.price;
}
return total;
}
function update_shipping_icons() {
var buttons = get_buy_buttons_dom();
for(var i = 0; i < buttons.length; i++) {
var button = buttons[i];
var item = button.item;
if(gets_free_shipping(shopping_cart_total, item.price))
button.show_free_shipping_icon();
else
button.hide_free_shipping_icon();
}
}To-be
function gets_free_shipping(cart) {
return calc_total(cart) >= 20;
}
function calc_total(cart) {
var total = 0;
for(var i = 0; i < cart.length; i++) {
var item = cart[i];
total += item.price;
}
return total;
}
function update_shipping_icons() {
var buttons = get_buy_buttons_dom();
for(var i = 0; i < buttons.length; i++) {
var button = buttons[i];
var item = button.item;
var new_cart = add_item(shopping_cart, item.name, item.price);
if(gets_free_shipping(new_cart))
button.show_free_shipping_icon();
else
button.hide_free_shipping_icon();
}
}이제 gets_free_shipping 함수는 장바구니가 무료 배송인지 아닌지 알려준다.
암묵적 입력과 출력은 적을수록 좋다
#Why?
- 암묵적 입력과 출력이 있다면 다른 컴포넌트와 강하게 연결되었기 때문
설계는 엉켜있는 것을 푸는 것이다
#풀려있는 것은 언제든 다시 합칠 수 있다.
- 재사용하기 쉽다.
- 유지보수하기 쉽다.
- 테스트하기 쉽다.
Chapter 6 : 변경 가능한 데이터 구조를 가진 언어에서 불편성 유지하기
#불편성 원칙과 copy-on-write를 한다는 것은 같은 의미이다.
copy-on-write란
#- 복사본을 만들고 원본 대신 복사본을 변경하는 것
copy-on-write 원칙 세 단계
#- 복사본 만들기
- 복사본 변경하기(원하는 만큼)
- 복사본 리턴하기
예시
funcyion add_element_last(array, elem) {
var new_array = array.slice(); // 복사본 만들기
new_array.push(elem); // 복사본 바꾸기
return new_array; // 복사본 리턴하기
}불변 데이터 구조를 읽은 것은 계산이다.
#- 변경 가능한 데이터를 읽는 것은 액션이다.
- 쓰기는 데이터를 변경 가능한 구조로 만든다.
- 어떤 데이터에 쓰기가 없다면 데이터를 변경 불가능한 데이터이다.
- 불변 데이터 구조를 읽은 것은 계산이다.
- 쓰기를 읽기로 바꾸면 코드에 계산이 많아진다.
불변 데이터 구조는 충분히 빠르다.
#바뀔 때마다 복사를 하면 너무 비효율적이지않은가? 라고 생각할 수 있다.
하지만 ~
- 언제든 최적화 가능
- 가비지 콜렉터는 매우 빠르다.
- 생각보다 많이 복사하지 않는다.
위와 같은 사례로 일반 애플리케이션에서 사용하기는 충분히 빠르다.