-
-
함수형 프로그래밍 with 자바 - 함수형 프로그래밍을 적용하여 객체 지향 자바 코드 향상시키기
벤 바이디히 지음, 허귀영 옮김 / 한빛미디어 / 2024년 3월
평점 :
네이버 블로그 리뷰: https://blog.naver.com/rock1192/223415211558
함수형 프로그래밍은 주로 복잡한 애플리케이션과 시스템 개발에 있어 고수준의 추상화와 불변성, 효율적인 병렬 처리 등의 많은 장점을 제공한다
2014년 자바 8에서 람다 표현식과 스트림 API가 소개되었는데, 이는 자바에서 함수형 프로그래밍의 출발점이 되었다
함수형 프로그래밍은 대규모 데이터 처리, 분산 시스템, 클라우드 컴퓨팅 등 현대 개발 환경의 복잡한 요구 사항에 효과적이다
이 책에서는 함수형 프로그래밍이 무엇인지와 자바에서 함수형 프로그래밍을 채택한 구체적인 이유와 기존 자바 코드를 함수형 스타일로 전환하는 방법에 대해 설명한다
또한 함수형 프로그래밍에 익숙하지 않은 개발자들이 쉽게 이해할 수 있도록 다양한 예제와 그림 자료를 제공한다
소프트웨어 개발은 매우 복잡한 작업이라서 많은 자바 개발자가 복잡성을 극복하기 위해 객체 지향 프로그래밍(OOP)을 이용한다
객체 지향 프로그래밍에서는 개발하고자 하는 대상을 자료 구조로 표현하며, 주로 명령형 코딩 스타일을 통해 프로그래밍의 상태를 관리한다
객체 지향 프로그래밍은 가장 유명하고 검증된 프로그래밍 패러다임 중 하나이지만 항상 최적의 해결책이 되지는 않는다
오히려 모든 문제에 이 원칙을 적용하다 보면 프로그램이 더 복잡해질 수도 있다
따라서 상황에 적합한 도구와 패러다임을 선택해야 한다
이러한 맥락에서 함수형 프로그래밍(FP) 패러다임은 문제 해결에 대한 새로운 접근 방식을 제안한다
이 책에서는 함수형 프로그래밍의 장점을 활용해 기존의 프로그래밍 방식과 소프트웨어 개발 도구를 보완하는 방법을 소개한다
합성(composition): 모듈식으로 쉽게 합성할 수 있는 블록을 구축
표현식(expressiveness): 의도를 명확하게 표현하는 간결한 코드를 작성
코드 안정성(safer code): 오류를 발생시키지 않고 경합 조건(race condition)이나 락(lock)을 처리할 필요가 없는 더 안전한 자료 구조를 만들 수 있다
모듈성(modularity): 큰 프로젝트를 더 쉽게 관리할 수 있는 모듈로 분할한다
유지보수성(maintainability): 연관성이 적은 함수형 블록들을 사용하여 코드의 다른 부분을 손상시키지 않으면서 코드 변경이나 리팩터링을 더 안전하게 수행할 수 있다
데이터 조작(data manipulation): 더 적은 복잡성으로 효율적인 데이터 조작 파이프라인을 구축한다
성능(performance): 불변성과 예측 가능성을 통해 큰 고민 없이 병렬로 수평 확장이 가능하다
Part 1
1부에서는 함수형 프로그래밍의 핵심 개념과 역사를 소개하고, 자바에서 이러한 개념을 구현하는 방법과 사용 가능한 기능에 대해 소개한다
Part 2
2부에서는 일반적인 프로그래밍 개념을 포함하여 함수형 원칙과 새로 도입된 기능들을 어떻게 활용할 수 있는 지에 대해 소개한다
레코드와 스트림처럼 주요 기능들은 예제와 사용 사례를 통해 배워본다
https://github.com/benweidig/a-functional-approach-to-java
함수형 프로그래밍은 주로 추상 함수에 기반을 두고 있으며 이 패러다임을 구성하는 많은 개념은 선언적 스타일로 '무엇을 해결할 것인가'에 초점을 맞추고 있다
함수형 프로그래밍의 장점
간결성(simplicity)
일관성(consistency)
(수학적) 정확성(mathematical) correctness
안전한 동시성(safer concurrency)
모듈성(modularity)
테스트 용이성(testability)
함수형 프로그래밍의 단점
학습 곡선(learning curve)
고수준 추상화(higher level of abstraction)
상태 처리(dealing with state)
성능 영향도(performance implication)
최적의 문제 상황(optimal probelm context)
함수형 프로그래밍은 '람다 대수'라는 수학적 원리를 기반으로 한다
함수형 프로그래밍에는 문장보다 표현식을 기반으로 하는 선언적 코딩 스타일이 필수이다
많은 프로그래밍 개념은 본질적으로 함수형인 것처럼 느껴지지만, 언어나 코드를 완전히 '함수형'으로 만들 필요는 없다
순수성, 일관성, 간결성은 함수형 접근 방식을 취대한 활용하기 위해 코드에 작용해야 하는 필수적인 속성이다
함수형 개념과 실제 적용 사이에는 타협이 필요하다
함수형 개념의 장점은 단점을 능가하거나 어떠한 형태로든 완화할 수 있다
람다 표현식은 자바 코드가 한 줄 또는 블록 단위로 이루어져 있으며 0개 이상의 매개변수를 갖고 값을 반환할 수 있다
람다는 어떠한 객체에도 속하지 않는 익명 메서드와 비슷하다
람다 문법은 매개변수, 화살표, 바디 세가지 부분으로 구성된다
자바 인터페이스 선언은 인터페이스 이름과 선택적으로 사용되는 제네릭 바운드(generic bound), 상속 인터페이스(inherited interface)와 인터페이스의 바디로 구성된다
메서드 시그니처(method signature), 기본 메서드(default method), 정적 메서드(static method), 상수
스트림은 다른 데이터 처리 방식처럼 작업을 수행하지만 내부 반복자라는 장점이 있다
주요 장점
선언적 접근법(declarative approach)
조합성(composability)
지연 처리(laziness)
성능 최적화(performance optimization)
병렬 데이터 처리(parallel data processing)
스트림의 특성
느긋한 계산법
(대부분) 상태 및 간섭 없음
최적화(성능 향상을 위한 여러 전략 활용)
(무상태의) 연산 융합
불필요한 연산 제거
단축 파이프라인 경로
보일러 플레이트 최소화
재사용 불가능
원시 스트림
쉬운 병렬화
예외 처리의 한계
람다 표현식은 지연 평가를 위해 표현식을 캡슐화하는 간단한 저 수준의 방법이다
한 가지 부족한 점은 평가 후 결과를 저장하는 것, 즉 두 번 호출되어도 표현식을 다시 평가하지 않도록 하는 메모이제이션(memoization)이다
이 부족한 점을 해결하는 방법이 바로 썽크(Thunk) 이다
썽크는 연산을 감싸는 래퍼로, 결과가 필요할 때까지 연산을 지연시키기 위해 사용한다
연산을 지연시키지만 여러 번 호출할 수 있는 Supplier와는 달리 썽크는 한 번만 계산되며 이후의 호출에서는 결과를 즉시 반환한다
썽크는 객체 지향 코드에서 자주 발견되는 디자인 패턴인 지연 로딩(lazy loading)/지연 초기화(lazy initialization)의 일반적인 범주에 속한다
지연 로딩과 지연 초기화는 비엄격 평가와 결과 캐시라는 동일한 목표를 달성하기 위한 메커니즘이다
CompletableFutures의 설계 철학은 스트림과 매우 유사하다
두 방식 모두 작업 기반 파이프라인을 제공하며, 일반적인 함수형 인터페이스를 받아들이는 매개변수화된 메서드를 제공한다
이 새로운 API는 CompletionStage나 CompletableFuture의 새 인스턴스를 반환하는 다양한 조정 도구들을 추가로 제공한다
이러한 비동기 계산을 위한 컨테이너와 조정 도구들을 사용하면, 기존에 부족했던 모든 기능들을 유연하게 구성 가능하며 선언적인 API로 제공한다
프로미스(promises)는 비동기 파이프라인의 기본 구성 요소로, 오류 처리를 포함하여 여러 작업을 연결하고 결합할 수 있는 내장된 조정 도구를 갖추고 있다
프로미스는 대기(완료되지 않음), 성공(완료되었으며 정상 상태), 실패(완료되었지만 오류 상태)의 세 가지 상태 중 하나이다
합성 파이프라인에서 이러한 상태 간의 이동은 데이터와 오류 채널 간의 전환을 통해 이루어진다
데이터 채널은 모든 것이 잘 진행될 때의 이상적인 경로이다
프로미스가 실패하면 파이프라인은 오류 채널로 전환된다
이런 방식으로 실패가 전체 파이프라인을 중단시키지 않고 스트림처럼 우아하게 처리되거나 복구되어 다시 데이터 채널로 전환될 수 있다
CompletableFuture API는 사실상 다른 이름을 가진 프로미스라고 볼 수 있다
이 책은 자바 개발자를 위한 함수형 프로그래밍 도서 이다
총 두개의 파트로 나누어져 있으며 Part 1에서는 함수형 기초에 대해서 다루고 있고 Part 2에서는 함수형 접근 방식을 다루고 있으며 Part 2에서 최신 Java에서 사용할 수 있는 여러가지 함수형 기법들과 비동기 프로그래밍에 대해서도 배울 수 있다
본인도 자바 개발자로 객체지향적 사고방식을 가지고 있어 함수형 프로그래밍 패러다임을 이해하기는 쉽지 않다
하지만 가끔 스트림과 Function을 사용한 코드가 객체지향으로 구현하기에 매우 복잡한 로직을 매우 쉽고 간결하게 해결해주는 경험을 해본적이 있어 스트림과 Function, 그리고 CompletableFuture를 활용한 비동기 프로그래밍은 꽤나 자주 사용하여 개발을 하고 있다
이 책을 잘 읽어보면 내가 느낀대로 함수형 프로그래밍은 객체지향으로 풀기 어려운 문제들을 쉽게 풀어낼 수 있는 패러다임이라는 것을 알 수 있다
물론 뭐든 남용하면 좋지 않다는 것도 잘 알고 있다
객체지향도 추상적인 개념을 많이 사용하지만 함수형 프로그래밍에 비해서는 매우 명확하고 로직을 이해하기 쉬운 장점이 있다
하지만 간혹 특정 문제를 해결하기 위한 로직은 상상이상으로 복잡해지며 수많은 클래스파일을 생성하여 복잡도가 매우 올라가고 그만큼 로직도 매우 복잡해져 이해하기 어려운 코드가 되기도 한다
이런 복잡한 문제를 해결하기 위해서는 함수형 프로그래밍을 적절히 접목하면 로직을 굉장히 간결하게 구현할 수 있으며 병렬처리와 비동기 처리, 지연처리들을 활용하여 성능적인 이점도 가져갈 수 있게 된다
함수형 프로그래밍은 깊이 공부해본적이 없어서 모호하게 이해하고 있던 부분들을 이 책을 통해 기초도 단단히 다지고 몇가지 노하우도 얻을 수 있어서 매우 유익했던 것 같다
그동안 자바 개발자를 위한 함수형 프로그래밍 서적은 그 수가 많지 않아 궁금하거나 알고 싶은 부분들은 블로그를 통해 파편적으로 정보를 얻고 있었는데 그럼에도 불구하고 내용이 꽤나 어려워 명확히 이해되지 않는 부분들이 많이 있었다
이 책 덕분에 궁금증이 상당 부분 해소되고 모호한 부분들을 명확하게 이해할 수 있게 되어 매우 만족스러웠다
※ 한빛미디어 <나는 리뷰어다> 활동을 위해서 책을 제공받아 작성된 서평입니다.