함수형 프로그래밍으로 일하면서 1년 동안 배운 3가지

대부분의 프로그래밍 관련 과정과 마찬가지로 객체 지향 패러다임(OOP)을 사용한 프로그래밍을 접하게 되었습니다. 많은 언어가 Python, C++, JavaScript 및 Ruby와 같은 다중 패러다임이지만 여전히 OOP가 표준입니다.

작년에 저는 새로운 직장에서 Elixir 스택을 가지고 일하라는 도전을 받았습니다. 이전에 함수형 프로그래밍으로 작업한 적이 없었기 때문에 새로운 경험이었습니다. 새로운 프로그래밍 패러다임을 배우는 것은 내 경력에서 가장 큰 단계 중 하나였으며, 다음 몇 줄에서 작년에 배운 내용을 공유하려고 합니다.

1. 함수형 프로그래밍을 배우려면 재부팅이 필요합니다.



객체 지향 프로그래머로서 새로운 언어를 배울 때 이미 개념을 알고 있으며 구문, 변수 선언 방법, 클래스, 공개 및 비공개 메서드, 일부 언어별 기능을 배워야 할 수도 있습니다.

당신은 차를 운전할 줄 압니다. 다른 종류의 차를 운전하는 것은 그리 어렵지 않습니다. 그러나 함수형 프로그래밍은 단순한 자동차가 아니라 보트입니다. 모든 자동차 운전 경험을 항해에 사용할 수는 없습니다. 어떤 것은 적용되고 다른 것은 적용되지 않습니다.



함수형 프로그래밍을 배우고 싶다면 모든 것을 다시 배워야 합니다. 공유 상태 없음, 순수성, 관심사 분리, 주요 조작 단위인 기능.

함수형 프로그래밍에 대한 첫 달에 나는 일상적인 문제를 OOP 방식 또는... 내가 아는 유일한 방식으로 해결하려고 했기 때문에 좌절했습니다.

재부팅이 핵심입니다.

2. 부작용은 만병의 근원이다



가변성이 필요합니다. 아무것도 바꾸지 않는 소프트웨어를 만드는 것은 의미가 없습니다. 문제는 이러한 변경 사항을 처리하는 방법입니다.



상태가 많을수록 소프트웨어 유지 관리, 이해 및 디버깅이 더 복잡해집니다. 유용한 완전히 순수한 프로그램(FP의 순수함은 부작용이 없음을 의미함)을 만드는 것은 불가능하지만 소프트웨어의 순수하지 않은 부분(데이터베이스, 외부 API 호출, IO 등)을 분리할 수 있습니다.

Mutation is a source of bugs. Therefore avoiding mutation will reduce the number of bugs that you introduce. Whenever you change a variable, there is always the possibility that you have broken some other piece of code that relied upon it. Avoiding mutation makes certain types of bugs impossible to introduce. - Tom Dalling (source)



공유 상태를 갖지 않음으로써 메모리를 완전히 분리하여 동시 소프트웨어를 더 쉽게 개발하고 유지 관리할 수 있습니다.

In the functional paradigm, due to immutability as a default construct, concurrent programming guarantees deterministic execution, even in the case of a shared state. On the other hand, imperative and OOP use mutable states, which are hard to manage in a multithreaded environment, leading to non-deterministic programs. - Manning (source)



부작용을 피하고 격리할 뿐만 아니라 코드의 가변성도 방지합니다. 함수 개념을 코드에 적용하기 위해 함수 프로그래밍 언어가 필요하지 않습니다. 이 Ruby 스니펫을 확인하십시오.

# Functional-style Ruby
def calculate_clothing_total(items)
  items
    .select(&:clothing?)
    .map(&:amount)
    .reduce(0, :+)
end


# Non-functional Ruby
def calculate_clothing_total(items)
  total = 0
  expenses.each do |e|
    total += e.amount if e.clothing?
  end
  total
end


이 간단한 예제는 total 변수만 변경하지만 더 나빠질 수 있습니다. Ruby에서 가상 값은 변경할 수 없으며 비파괴적인 방법을 사용합니다. 예기치 않은 동작이 발생할 수 있으므로 메서드 인수를 재할당하지 마십시오. 대신 새 값을 반환합니다.

Ruby 개발자라면 RubyPigeon의 멋진 기사(Avoid Mutation – Functional Style In Ruby)를 읽어 보시기 바랍니다.

3. 고민의 분리 = ❤️





어떤 사람들은 FP 소프트웨어가 디버그하기 쉽고 버그가 적으며 함수형 프로그래밍을 제대로 배우면 유지 관리하기가 더 쉽다고 말합니다. 일부 FP 언어에서는 분리 기능이 거의 시행되기 때문에 이는 사실입니다. 순수하지 않은 코드가 암시적으로 순수 코드와 함께 있는 것을 원하지 않습니다.

이는 작동하지 않는 소프트웨어에도 적용할 수 있는 개념입니다. 모든 것이 잘 격리되어 있으므로 테스트, 리팩터링 및 디버그가 더 쉽습니다. Ecto가 데이터 변경 작업을 위한 순수한 접근 방식인 변경 세트로 수행하는 것처럼 지속성과 스키마 변경을 분리할 때 데이터베이스 변경도 순수합니다.

attributes = %{amount_due: 3000, due_date: "2019-04-30", scheduled_send_date: "2019-04-25", closed_at: "2019-05-01"}
changeset = Invoice.changeset(%Invoice{}, attributes)
#=> #Ecto.Changeset<
#     action: nil,
#     changes: %{amount_due: 3000, due_date: ~D[2019-04-30], scheduled_send_date: ~D[2019-04-25]},
#     errors: [],
#     data: #Invoice<>,
#     valid?: true
#   >

changeset.changes
#=> %{amount_due: 3000, due_date: ~D[2019-04-30], scheduled_send_date: ~D[2019-04-25]}



함수형 프로그래밍을 배우고 싶다면 API와 같은 일반 소프트웨어용으로 선택한 FP 언어인 Elixir로 뛰어들기 전에 패러다임의 기초를 다루는 것이 좋습니다.

기본 사항을 이미 알고 있다면 start here with Elixir , 그리고 시작하세요! 🚀

마지막으로 함수형 프로그래밍 언어를 사용할 계획이 없다면 일상적인 코드에 격리, 불변성 및 기타 기능적 이점에 대한 최소한의 개념을 적용하는 것이 좋습니다. Immutable.js for JavaScript 과 같이 이에 도움이 되는 라이브러리가 많이 있습니다.

좋은 웹페이지 즐겨찾기