킹의 개발일지
쏙쏙 들어오는 함수형 코딩 (11 ~ 15일차) 본문
11일차
<카피-온-라이트 2>
이전 파트를 이어서, 쓰기를 하면서 읽기도 하는 동작에 카피온라이트를 적용하는 방법을 설명한다.
대표적으로 읽기와 쓰기를 하는 자바스크립트 함수로 shift 함수가 있다.
shift는 배열에서 첫 번째 원소를 제거하고 뺀 원소의 값을 반환한다. 뺸 원소를 반환하는 단계에서 읽기를, 배열에서 첫 번째 원소를 제거하는 쓰기를 한다.
방법으로 1. 읽기와 쓰기 함수로 각각 분리하는 방법, 2. 함수에서 값을 두 개 리턴하는 방법, 두가지를 설명하고 있다.
첫번째 방법의 경우 배열을 읽는 부분에선 카피온라이트를 적용하지 않고 쓰기 부분에서만 적용한다. 이는 두번째 방법도 마찬가지다. (읽기는 원본을 변경하지 않기 때문..)
흥미로웠던 점은 실제로 동작하는 함수는 안쪽에 두고 껍데기를 래핑해서 함수를 만들고 있다는 점이다.
add_cart_item(array, item) {
array.push(item);
}
(카피 온 라이트 적용 안 했음)
add_cart_item과 같이 실제 동작하는 함수의 내부는 단순히 push 함수이다.
불변성을 유지하기 위해서 아래 함수처럼 (shift나 pop.. 등의 메서드는 원본 배열을 직접 변경한다.)
add_cart_item(array, item) {
var new_arr = array.slice();
new_arr.push(item);
return new_arr;
}
래핑하기도 하지만 내 생각엔 래핑을 하는 장점은 그게 끝이 아닌듯 했다.
이렇게 만들어둔 함수는 재사용에 유리하고 함수 내부에 조건을 검사하는 로직을 두어 에러를 막을 수 도 있다. 또한 어떤 함수인지 함수 이름을 보고도 바로 이해할 수 있으니 실제 코드에 바로 적용 해보고 싶다.
12일차
<오브젝트 카피-온-라이트>
배열을 복사하는 메서드로 slice()가 있었다면, 오브젝트를 복사하는 메서드로는 assign함수가 있다.
assing의 문법은 Object.assgin({}, obj)이고,
동작은
1. 빈배열을 만들고 -> {}
2. 파라미터로 들어온 obj를 빈 배열에 대입한다.
그래서 첫 번째 인자로 빈배열 대신 기존에 있는 오브젝트를 준다면 그 오브젝트 안에 두 번째 인자로 들어온 오브젝트가 추가되는 구조이다.
나는 지금까지는 가비지 컬렉터 호출을 무조건 최소화 하는것이 좋다고 생각했다. 카피온라이트를 책에서 나온대로 막 쓰면 가비지 컬렉터에 불이나는것이 아닌가 하는 생각이 들었다.
그러나 어떻게 알았나 싶을정도로 이에대해 딱 짚어서 저자가 걱정 안 해도 된다고 말해준다.
저자의 말을 듣고보니 내가 가비지 컬렉터를 무시(?) 하는 생각이 아니었나 싶다. 심지어 사람들의 컴퓨터 하드웨어 성능이 점점 증가함에 따라 메모리 할당이 잦다고 나쁜것은 아닌것 같다는 생각이 든다. 성능도 중요하지만 읽기 좋은 코드, 예외가 덜 발생할 코드도 중요하다는 생각이 들었다.
13일차
<중첩된 쓰기를 읽기로 바꾸기>
지금까지 중첩되지 않은 쓰기들만 읽기로 변경 해왔다. 중첩된 쓰기라 하면, 객체 배열을 생각하면된다.
배열은 각 객체들의 주소를 들고 있으니, 배열의 원소에 접근해 이것을 써버리면 원본이 변경되는 문제가 발생한다. 이는 카피-온-라이트 정신에 위배된다.
문제는 배열만 복사를 한다면 배열 안에 있는 원소들은 여전히 같은 주소를(객체니까) 가르키고 있을 테고, 복사한 배열의 원소에 접근해 변경하면 원본이 손상 된다.
때문에 중첩된 쓰기는 배열, 배열의 원소까지 복사를 해야한다. 그리고 모든 원소를 복사하는것이 아니라 변경하기 원하는 원소(객체)만 복사를 해서 변경한다. 복사된 배열은 원소들을 구조적으로 공유하는데, 변경하고자 하는 데이터(객체)는 복사하기 때문에 원본은 여전히 보존된다.
다음장에서는 카피-온-라이트를 직접적으로 구현 할 수 없는 상황에서 원본을 보존할 수 있는 방법인, 방어적 복사를 공부 할 것이다.
14일차
<신뢰할 수 없는 코드와 상호작용하기>
내가 직접 카피-온-라이트를 모두 구현하지 않는 이상, 레거시 코드 처럼 기존에 있는 코드를 써야할 경우가 생긴다. 이땐 방어적 복사를 사용해야한다.
[방어적 복사 규칙]
1. 데이터가 안전한 코드에서 나갈 때 복사하기.
2. 안전한 코드로 데이터가 들어올 때 복사하기.
여기서 안전한 코드란 카피-온-라이트가 지켜지는 코드, 반대는 지켜지지 않는 코드이다.
안전하지 않은 코드는 원본이 변경 될 위험이 있는데, 이땐 구조적 공유를 믿을 수 없다. 어떤 객체를 변경할 지 모르기에, 복사해두지 않은 객체가 변경되는 경우에는 원본이 회손된다.
때문에 원본이 변경될 변수를 원천적으로 봉쇄하는 방법이 방어적 복사이다. 들어갈 때는 그렇다 치더라도 나갈 때까지 딥카피를 하는 이유는, 여기서 딥카피란 얉은 복사완 달리 중첩된 데이터 모두의 참조값이 바뀐다. 때문에 원본이 변경될 여지가 없다, 안전하지 않은 코드의 참조를 가지고 있기 때문이다.
마치 깨끗한 데이터를 오염지역에 넣고 뺄 때 또한 깨끗히 만드는 것과 비슷하다.
지금까지 책을 읽으면서 얉은 복사를 한다 했을 때 이상하게 생각했다. 구조적으로 참조를 공유하고 있기에, 원본을 보존할려면 전부 복사 해야하지 않을까 생각했다.
이번 장에서 이 생각에 대한 시원한 답변을 알려 줬는데, 간단하다. 비용이 매우 비싸다. 딥카피는 중첩된 데이터 전부를 복사하기에 변경하고 싶은 데이터만 복사하는 카피-온-라이트와 비교했을 때 비싸다. 그리고 자바스크립트로 구현하기 힘들다고 한다. 때문에 딥카피는 필요한 상황에서만 쓰는것이 맞다고 느껴졌다.
15일차
<계층형 설계1>
복습하는 차원에서 카피-온-라이트, 방어적 복사 두 방법에 대해 구분하는 예제들을 풀어봤다.
방어적 복사는 안전 지대를 벗어 나더라도 데이터의 불변성을 유지 할 수 있다는 장점이 있다. 이는 무조건 적인 장점이 아닌데, 필연적으로 많은 비용이 든다.
쓰기가 일어나는지 안 일어나는지 알 수 가 없는 코드이기에 카피-온-라이트가 그랬던것 처럼 구조적 공유를 유지할 수 없다. 때문에 무조건 적으로 중첩된 모든 데이터를 복사해야 하는 단점있다.
이후 앞장에서 저자가 뒤에서 살펴보기로 하고 간단히 소개하고 넘어갔던 계층형 설계에 도달했다. 계층형 설계 패턴에 대해서 설명 하지만, 앞장처럼 추상적인 설명에 그치기에 다음 장이 기대된다.
'독서 > 책너두 챌린지' 카테고리의 다른 글
| 쏙쏙 들어오는 함수형 코딩 (26 ~ 27일차) (0) | 2023.09.07 |
|---|---|
| 쏙쏙 들어오는 함수형 코딩 (16 ~ 20일차) (2) | 2023.09.07 |
| 쏙쏙 들어오는 함수형 코딩 (6 ~ 10일차) (0) | 2023.09.07 |
| 쏙쏙 들어오는 함수형 코딩 (1 ~ 5일차) (3) | 2023.09.07 |
| 책너두 (책이 너무 두껍다..) - 쏙쏙 들어오는 함수형 코딩 (1) | 2023.09.05 |