Early Riser
생각정리
Early Riser
전체 방문자
오늘
어제
  • 분류 전체보기 (128)
    • JS (19)
    • React (33)
    • React Native (2)
    • Library, Tool (13)
    • CSS (2)
    • Algorithm (40)
    • Computer Science (3)
    • 회고 (3)
    • AI (13)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 글쓰기

공지사항

인기 글

태그

  • 논문리뷰
  • 손실함수
  • LGBM
  • local minima
  • 부스트캠프 합격
  • 자바스크립트
  • 파이썬
  • useState
  • 백준
  • 프로그래머스
  • 밑바닥
  • 백트래킹
  • 부스트캠프 합격 후기
  • 완전탐색
  • js
  • 알고리즘
  • 오늘의불경
  • dfs
  • global minima
  • react
  • RNN
  • 비동기
  • 딥러닝
  • javascript
  • BFS
  • 구현
  • boosting
  • useEffect
  • 부스트캠프 9기
  • lightgbm

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Early Riser

생각정리

회고

FP에서 함수 분리 단위

2025. 9. 22. 11:20

 회사에서 일하던 중 기존 함수를 재사용하는 게 낫지 않냐는 말을 들었다.

 나는 두 가지 이유 때문에 새 함수를 만들어야 한다고 생각했다. 첫째, 필요로 하는 데이터가 다르다. 새로 만들어야 할 함수는 기존 함수의 반환값의 부분집합이다. 따라서 인터페이스를 최소화하고 싶었다. 둘째로, 함수가 두 곳에서 쓰이면 추후 한 곳만 수정해야 할 때 수정이 힘들기 때문에, 즉 결합되어 있음, 새 함수를 만들어야 한다고 생각햇다.

 

 이때 FP에서는 이런 경우에 어떻게 할까? 함수를 재사용해야 할 때 어떤 단위로 함수를 분리해야 할까라는 의문이 들었다. OOP에서는 다형성, 메소드 오버라이드 등을 통해 메서드를 재사용하고, SRP처럼 클래스의 변경 사유는 오직 하나여야 한다는 분리 단위가 정해져 있는 것 같기 때문이다. 다형성이 OOP의 필요충분 조건은 아니지만, 기준이 어느 정도 명확하다.

 

 단순히 함수를 하나의 일만 담당하게 분리한다는 말은 SRP를 오해한 사람처럼 모든 사람이 똑같이 분리할 기준을 만들 수 없다고 생각했다. 왜냐하면 하나의 일에 대한 정의는 사람마다 다르기 때문이다. 예를 들어 active user를 분류하는 일은 하나의 일일까? filter가 하나의 일일까? 사람마다 생각이 다를 것이다.

 

 이에 처음에는 함수의 분리 단위를 정하기 위해 함수의 순수성과 선형성에 집중했다. 함수형 프로그래밍은 변수를 mutable하게 변환하지 않는 패러다임이기 때문이다. 그러나 순수성만 고려하면 문제가 생긴다. 예를 들어 한 함수 내에서 연산을 두 번 수행하는 경우를 보면

const activeByUser = (list) => {
  const incompleteItems = list.filter(item => item.complete === false);
  const grouped = incompleteItems.reduce((acc, item) => {
    const key = item.username;
    if (!acc[key]) acc[key] = [];
    acc[key].push(item);
    return acc;
  }, {});
  return grouped;
};

 이 함수는 순수하지만 재사용은 힘들다고 생각했다.

 

 그 다음에 집중한 것은 선형성이다. 함수 단위 하나하나를 선형 함수로 만들면 추후에 합성했을 때 선형성을 유지할 수 있다. 따라서 함수 분리 단위를 선형성에 집중하면 재사용이 편리하고 decoupling되어 있는 단위를 만들 수 있다고 생각했다. 그러나 이 역시 문제가 생겼다. filter나 reduce 같은 연산 자체가 구조적으로 비선형적이기 때문이다.

 

 마지막으로 생각해본 것은 데이터 변환 단위이다. 위 예제에서 보면 filter에서 한 번 데이터가 변환되고 reduce에서 한 번 더 변환된다. 이를 함수의 분리 단위로 삼고 분리해보면 합성이 편하고, 입력이 여러개인 경우 currying을 활용하면 재사용이 쉬운 단위가 된다.

const filterIncomplete = (list) => list.filter(item => item.complete === false);

const groupByUser = (list) => list.reduce((acc, item) => {
  const key = item.username;
  if (!acc[key]) acc[key] = [];
  acc[key].push(item);
  return acc;
}, {});


const compose = (f, g) => x => f(g(x));
const activeByUser = compose(groupByUser, filterIncomplete);

const todos = [
  { id: 1, username: 'alice', complete: false },
  { id: 2, username: 'bob', complete: true },
  { id: 3, username: 'alice', complete: false },
];

console.log(activeByUser(todos));
// => { alice: [ {id:1,...}, {id:3,...} ] }

 여기서 더 나아가, 입력 검증, 에러 처리, 비동기 호출까지 모나드를 활용하여 합성할 수 있다. 예를 들어 IO, Either, Maybe 모나드를 조합하면 다음과 같이 표현 가능하다.

// 간단한 FP 모나드 구현 예제
const Maybe = x => ({
  map: f => (x == null ? Maybe(null) : Maybe(f(x))),
  chain: f => (x == null ? Maybe(null) : f(x)),
  value: x
});

const Either = x => ({
  map: f => (x instanceof Error ? Either(x) : Either(f(x))),
  chain: f => (x instanceof Error ? Either(x) : f(x)),
  value: x
});

const IO = effect => ({
  map: f => IO(() => f(effect())),
  chain: f => IO(() => f(effect()).run()),
  run: effect
});

// 예제: JSON 데이터 불러와서 필터링하고 그룹핑
const fetchTodos = IO(() => [
  { id: 1, username: 'alice', complete: false },
  { id: 2, username: 'bob', complete: true },
  { id: 3, username: 'alice', complete: false }
]);

const safeParse = str => {
  try { return Either(JSON.parse(str)); }
  catch(e) { return Either(e); }
}

const processTodos = (list) => {
  return Maybe(list)
    .map(filterIncomplete)
    .map(groupByUser);
}

// 합성
const result = fetchTodos
  .map(processTodos)
  .run();

console.log(result.value);
// => { alice: [ {id:1,...}, {id:3,...} ] }

 

참고자료

https://fr.umio.us/favoring-curry

https://fr.umio.us/why-ramda

http://hughfdjackson.com/javascript/why-curry-helps/?ref=fr.umio.us

https://youtu.be/m3svKOdZijA?si=z2ZznlDF8UUhNefW

'회고' 카테고리의 다른 글

네이버 부스트캠프 웹 풀스택 9기 챌린지 합격 후기  (1) 2024.08.03
싱커톤 시즌3를 마무리하며(feat: 우수상 수상)  (2) 2023.10.26
    '회고' 카테고리의 다른 글
    • 네이버 부스트캠프 웹 풀스택 9기 챌린지 합격 후기
    • 싱커톤 시즌3를 마무리하며(feat: 우수상 수상)
    Early Riser
    Early Riser
    2년차 프론트엔드 개발자입니다. https://github.com/EarlyRiser42

    티스토리툴바