favicon

Jayden { do: smite }

쏙쏙 들어오는 함수형 코딩 Chapter 5

🖍 쏙쏙 들어오는 함수형 코딩 - 심플한 코드로 복잡한 소프트웨어 길들이기

이 글은 쏙쏙 들어오는 함수형 코딩 - 심플한 코드로 복잡한 소프트웨어 길들이기를 읽고 작성한 글입니다. 함수형도 함수형이지만, 이 책을 통해 좀더 깔끔하고 직관적인 코드를 작성할 수 있을 것이란 팀원들의 의견을 토대로 이번 스터디 서적으로 선정하였습니다.

Chap 5. 더 좋은 액션 만들기

  • 암묵적 입력과 출력을 제거해서 재사용하기 좋은 코드 만들기
  • 복잡하게 엉킨 코드를 풀고 더 좋은 코드 만들기

모든 액션을 없앨 수는 없다. 액션은 필요하다. 하지만 암묵적 입력과 출력을 줄임으로써 액션을 최소화할 수 있다.

1) 비즈니스 요구사항과 설계 고려하기

  • 기계적인 리팩토링만이 항상 최선의 구조를 만들어주진 않는다.
  • 비즈니스 요구사항을 고려해야 한다.

비즈니스 요구 사항: 장바구니에 담긴 제품을 주문할 때 무료 배송인지 확인하는 기능

아래 함수는 비즈니스 요구사항인 장바구니에 담긴 제품에 대한 내용 없이 총액무료배송에 대한 내용만을 가지고 있다.

function getFreeShipping(total, itemPrice) { return total + itemPrice >= 20; }

이를 좀더 비즈니스 로직에 맞게 개선하면 아래와 같다.

function getFreeShipping(cart) { return getTotalPriceFromCart(cart) >= 20; } function getTotalPriceFromCart(cart) { return cart.reduce((result, item) => result + item.price, 0); }

사실 위의 경우, 함수의 동작을 변경했기 때문에 엄밀히 말하면 리팩토링이라고 할 수 없다.

Tip1) 리팩토링(함수 분리)을 하다보면 코드가 더 길어지기도 하는데, 괜찮은건가?<br/>

  • 함수를 분리함으로써 코드의 가독성이 높아지고, 재사용성이 높아지기 때문에 코드의 길이가 늘어나더라도 좋은 코드라고 할 수 있다.<br/> Tip2) 불변성 유지를 위해 객체를 복사하는 게 오히려 비용을 많이 쓰지 않나?<br/>
  • 굳이 비교하자면 기존 객체를 변경하는 방식보다는 비용이 더 든다. 하지만 현대의 언어 런타임과 가비지 컬렉터는 이를 최적화하고 있기 때문에 큰 문제가 되지 않는다. 또한, 이에 반해 불변성을 유지했을 때 얻는 이점이 너무 크다.

2) 압묵적 입력과 출력은 적으면 적을수록 좋다!

  • 암묵적 입력: 전역변수를 읽는 등 인자 외의 다른 모든 입력값
  • 암묵적 출력: console.log(), DOM 변경, 전역변수 변경 등 반환값 외의 다른 모든 출력값

어떤 함수(컴포넌트)에 암묵적 입력과 출력이 있다면, 다른 함수(컴포넌트)와 강하게 연결된 컴포넌트가 된다. 이는 재사용성을 떨어뜨리고, 테스트하기 어렵게 만든다. 또한 다른 곳에서 사용할 수 없기 때문에 모듈이라고 할 수 없다. 암묵적인 것들을 명시적으로 변경함으로써 모듈화할 수 있다.

계산: 암묵적 입력과 출력이 없는 함수 => 모듈화 가능 및 테스트하기 좋다.

3) 설계는 엉켜있는 코드를 푸는 것이다.

  • 함수를 사용하면 자연스럽게 관심사를 분리할 수 있다.
  • 함수는 인자와 반환값을을 사용하는 방법을 분리한다.(너무도 자연스럽게 input과 output을 나누게 되니까)
  • 때로는 함수를 합치고 싶을 수 있다. 그러나 조합하는 것은 언제든 쉽게 할 수 있지만, 분리하는 것은 어렵다. 즉, 가능하면 함수를 분리해두는 것이 더 좋다.

함수를 작게 분리해두었을 때의 이점

  1. 재사용하기 쉽다.
  2. 유지보수하기 쉽다.
  3. 테스트하기 쉽다.

4) 패턴 빼내기(유틸 함수 만들기)

만약 아래와 같은 함수가 존재한다고 해보자.

function addItem(cart, item) { let newCart = [...cart]; newCart.push(item); return newCart; }

잘 생각해보자. 위의 함수는 과연 cart(장바구니)에만 한정된 함수인가??? 아니다. 새로운 배열(cart)에 새로운 값(item)을 추가하는 유틸 함수이다. 따라서 아래와 같이 변경해주는 것이 좋다.

function addItem(array, item) { let newArray = [...array]; newArray.push(item); return newArray; }

이로써 의미적으로 좀더 다양한 곳에서 활용할 수 있는 유틸 함수를 만들었다.

Tip1) 코드에서 비즈니스 로직은 어떻게 구분할 수 있는가?<br/>

  • 예를 들어 장바구니 기능을 담당하는 코드는 대부분의 전자상거래 서비스에서 공통적으로 사용된다. 즉, 그 서비스만의 비즈니스 로직이라고 볼 수 없다.<br/>
  • 반면 총 가격이 50,000원이 넘어갈 때는 배송비가 무료라는 기능은 그 서비스만의 로직이다. 즉, 그 서비스만의 비즈니스 로직이라고 볼 수 있다.<br/>
  • 일반적으로 비즈니스 로직을 담당하는 코드는 더 자주 바뀐다.(기획에 따라서 언제든 변경되니까) 반면에 유틸 함수는 그렇지 않다.

5) 정리

  • 일반적으로 암묵적 입력과 출력은 명시적 입력과 출력인 인자와 리턴값로 바꿔주는 게 좋다.
  • 코드를 설계하는 것은 엉켜있는 것을 푸는 것이다. 최대한 많이 풀어두면 언제든 쉽게 조합할 수 있다.
  • 엉켜있는 것을 풀어 각 함수가 각자 하나의 책임, 역할을 갖게 하면 개념을 기준으로 쉽게 코드를 구성할 수 있다.(ex. 장바구니 기능, 배송비 기능, 할인 기능, 유틸 함수 등)
undefined

Copyright 2023. all rights reserved by Jayden