16P by GN⁺ 2일전 | ★ favorite | 댓글 10개
  • 파이프라이닝은 프로그래밍 언어에서 코드의 가독성과 유지보수성을 높이는 중요한 기능임
  • 데이터 흐름을 왼쪽에서 오른쪽, 위에서 아래로 자연스럽게 표현할 수 있게 해주는 방식
  • Rust와 같은 언어에서 파이프라이닝은 코드의 흐름을 명확하게 하고, IDE의 자동 완성 기능을 통해 개발 생산성을 높임
  • Haskell, Elm, SQL 등 다양한 언어에서 적용되며, builder 패턴이나 메서드 체이닝도 일종의 파이프라이닝으로 간주
  • 가독성, 편집 편의성, IDE 지원, 버전 관리 도구(diff, blame) 에 모두 긍정적 영향
  • 함수 중첩 방식보다 간결하고 명확한 코드를 작성할 수 있어 협업과 유지보수 측면에서도 유리함

내가 제일 좋아하는 프로그래밍 문법, 파이프라이닝

파이프라이닝이란?

  • 이전 값을 전달하여 매개변수 목록에서 하나의 인수를 생략할 수 있는 기능
  • 코드의 가독성을 높이고, 주석을 추가하기 쉽게 만들어 줌
  • 데이터를 중심으로 연속된 처리 작업을 순차적으로 적용하는 문법 스타일
  • 함수형 스타일 코드에서 .map().filter().collect() 같은 메서드 체이닝 형태로 많이 사용됨
  • Rust에서 다음과 같은 코드가 대표적 예시:
    data.iter()  
        .filter(|w| w.alive)  
        .map(|w| w.id)  
        .collect()  
    
  • 반대로 모든 함수를 중첩하면 다음처럼 안에서 바깥으로 읽어야 하는 구조가 됨:
    collect(map(filter(iter(data), |w| w.alive), |w| w.id))  
    

왜 파이프라이닝이 좋은가?

  • 1. 가독성과 유지보수성

    • 위에서 아래로 읽기 쉬움 → 사람이 읽는 순서와 동일한 데이터 흐름
    • 각 줄에 주석 달기 쉬움
    • 긴 줄에 괄호 중첩 없이 간결하고 명확
  • 2. 편집 편의성

    • 중간에 .map() 등 새 함수를 한 줄로 쉽게 추가 가능
    • git diffgit blame에서도 변경사항 추적이 깔끔하게 드러남
  • 3. IDE / LSP 지원

    • . 키를 눌렀을 때 자동완성 목록이 뜨는 구조와 잘 맞음
    • 타입을 명확히 알고 있어야 가능한 정적 분석에 유리
    • 이 기능이 제대로 동작하려면 언어가 정적 타입 기반이어야 함 (e.g. Rust, TypeScript)

SQL에도 파이프라이닝이?

  • SQL의 중첩 SELECT 쿼리를 파이프라인 스타일로 바꿀 수 있다는 제안 존재
  • 예시:
    FROM customer  
    |> LEFT OUTER JOIN orders ON ...  
    |> AGGREGATE COUNT(...) GROUP BY ...  
    |> ORDER BY ...  
    
  • 기존 SQL보다 명확한 흐름, 가독성 향상
  • 단점: SELECT 구문이 위로 빠지면서 반환 타입 파악이 어려울 수 있음 → 해결 가능

Builder 패턴과의 연계

  • Rust의 Builder::new().option().option().build() 같은 형태는 전형적인 파이프라인 구조
  • 선택적 설정을 메서드로 구성하면서 코드 추적, 변경 관리가 용이

Haskell의 파이프라이닝 개선

  • Haskell의 $, &, |> 같은 연산자는 함수 합성 대신 파이프라인 사용을 가능하게 함
  • 예시 전후 비교:
    -- 기존  
    checkPalindromes content = unlines $ map (show . isPalindrome) $ lines $ map toLower content  
    
    -- 개선  
    checkPalindromes content =  
      content  
        & map toLower  
        & lines  
        & map (show . isPalindrome)  
        & unlines  
    

Rust에서 파이프라이닝의 장점

  • 메서드 체이닝, 타입 추론, trait 기반의 구조적 확장성이 모두 파이프라이닝과 잘 어우러짐
  • Rust는 함수형과 객체지향 문법의 장점만 뽑아낸 듯한 구조로, 파이프라이닝 사용이 가장 자연스러움

결론

  • 파이프라이닝은 단순한 문법이 아니라 코드 흐름, 편집성, 협업까지 영향을 주는 핵심 기능
  • f(g(h(x))) 같은 중첩 대신 x |> h |> g |> f 구조가 더 인간 친화적
  • 파이프라이닝은 "한 줄에 하나의 작업"이라는 단순한 규칙 아래, 자연스러운 흐름을 표현할 수 있는 최고의 방법

“각 파이프 조각은 주요 데이터를 받아 한 가지 작업을 수행한다. 마지막에는 명확한 이름을 붙여주면 그게 가장 이상적인 코드 구조다.”

어떤 텍스트든
줄바꿈 들여쓰기 가 가독성에 중요한 것과
비슷한 맥락일 듯요.

내가 제일 싫어하는 문법임
stacktrace 조금만 꼬여있어도 디버깅 최악

Gleam도 이것을 지원해서 꽤 깔끔하게 코드 작성이 되더라구요.

그나저나, 본문에 코드 블럭이 들어가서 그런지, 모바일에서도 데탑 레이아웃으로 니오네요.

그러고보니 elm도 되네요.

소량의 데이터와 위의 예시처럼 간단한 수준의 코드에서는 보기도 좋고 나쁠 건 없다고 봅니다.

하지만 map() 안에 코드가 조금씩 들어가다가 ... 코드가 점점 뚱뚱해지게 만드는 경향이 있고
언어나 구현 라이브러리에 따라 영향이 있지만, 데이터량이 많아지면 그냥 데이터구조에 데이터를 쌓거나 조작하면서 처리하는 것에 비해 쉽게 수천배 느려지기도 하기 때문에,

그리고 또 하나 선호하지 않게된 새로운 이유가 생겼는데요, 폰에서 이 기사를 봤더니 PC 수준의 너비가 그대로 유지되면서, 글씨 크기가 눈꼽만하게 작아지는 바람에 기사를 보기가 너무 어렵다는 이유 때문에 T.T

기본적으로 선호하지 않고, 일부러 저런 식으로 쓰려는 노력은 하지 않습니다.

js 도 좀 주세요 |> 굽신 굽신

|> 너무 이뻐요

Hacker News 의견
  • 작성자는 "pipelining"이라고 부르지만, 올바른 용어는 "method chaining"이라고 생각함

    • Bash의 간단한 파이프라인과 비교: 각 구성 요소가 병렬로 실행되며 중간 결과가 스트리밍됨
    • Ruby에서는 각 줄이 순차적으로 처리되며 각 단계 사이에 완전한 배열이 생성됨
    • 디버깅이 어려워져서 요즘은 더 명시적인 코드를 작성함
    • 명시적인 코드는 보기에는 덜 깔끔하지만 중간 상태를 쉽게 검사할 수 있음
  • 개인적으로 언어의 기능 세트를 작게 유지하고 빠르게 완성된 기능 세트를 달성하는 것을 지지함

    • 그러나 Elixir의 |> 문법을 모든 언어가 채택했으면 하는 바람이 있음
  • Lisp 매크로는 체인된 컬렉션 연산자뿐만 아니라 호출 체인의 순서를 결정할 수 있는 일반적인 솔루션을 제공함

    • 예를 들어, (foo (bar (baz x)))를 (-> x baz bar foo)로 작성할 수 있음
    • 추가 인수가 있는 경우에도 처리 가능함
    • 자세한 내용은 Clojure의 스레딩 매크로 가이드 참조
  • 이 용어를 유창한 인터페이스라고 배웠음. 파이프라이닝은 다른 것임

  • 파이프라인 연산자는 부분 적용의 일종으로, 여러 인수를 바인딩하여 새로운 함수를 만들고 그 출력을 다른 함수에 전달할 수 있음

    • 부분 적용은 프로그램 작성에 매우 유용하며, 언젠가 (비-Haskell) 언어들이 이를 프로그램 구성의 기본으로 사용할 것임
  • R의 tidyverse 사용자들은 이미 이를 사용하고 있음

  • 파이프라이닝은 디버깅이 어려움. 예외 처리가 어려워 파이프라인에 분기를 추가해야 함

    • 파이프라인은 행복한 경로를 프로그래밍할 때만 유용함
  • SQL 문법이 불필요하게 복잡함

    • SQL은 이미 연산자 언어지만 역사적 이유로 제약이 많음
    • 새로운 문법을 허용할 거라면 더 간단하게 작성할 수 있음
    • |> 문법은 표현력이 없고 시각적 잡음을 추가함
  • 작성자는 "의미가 문법을 이긴다"고 주장하지만, 문법 선호에 초점을 맞추고 있음

    • 파이프라이닝은 체인이 길어질수록 디버깅이 어려워짐
    • Python에 대해 비판적이지만 구체적인 이유는 제시하지 않음
    • "pipelining"의 정의가 명확하지 않음
  • effect-ts는 파이프라인과 명령형 코드를 모두 작성할 수 있게 해줌

    • 파이프라인 작성과 제너레이터 사용에 대한 문서 제공
    • 대부분의 커뮤니티가 명령형 스타일의 제너레이터를 선호하게 되었음
    • 디버깅과 유지보수가 더 쉬운 것으로 보임