라벨이 Scala인 게시물 표시

Monad Transformer In Scala

안녕하세요~ 오늘은 Monad Transformer 에 대해서 포스팅해보려고 합니다 ㅎㅎ Monad Transformer 란? 자, 다음과 같이 간단한 코드가 있습니다. case class User ( id : String , bestFriendId : String ) def getUser ( userId : String ) : Future [ Option [ User ] ] = ? ? ? def getBestFriendOfUser ( userId : String ) : Future [ Option [ User ] ] = for { userOpt <- getUser ( userId ) bestFriendIdOpt = userOpt . map ( _ . bestFriendId ) bestFriendOpt <- bestFriendIdOpt match { case Some ( bestFriendId ) => getUser ( bestFriendId ) case None => Future . successful ( None ) } } yield bestFriendOpt getBestFriendOfUser 함수를 보면 Future 와 Option 이 함께 쓰이고 있는 것을 볼 수 있습니다. User 가 Option 과 Future 에 의해 2중으로 감싸져있기 때문에 실제 User 값에 대해 뭔가 연산을 수행하려면 상당히 성가시고 가독성도 떨어지게 됩니다. 결국 문제가 되는 부분은 “2중으로 감싸져있다” 는 점입니다. 즉, Future 와 Option 을 하나로 합친 타입을...

꼬리 재귀와 Trampoline In Scala

안녕하세요! 오늘은 스칼라 초심자를 대상으로 Tail Recursion (꼬리 재귀) 와 Trampoline 에 대해 포스팅하려고 합니다. 함수형 프로그래밍이나 모나드를 몰라도 이해할 수 있도록 노력해봤습니다~~ 간단하게 1부터 n 까지 더해주는 함수를 아래와 같이 작성한 뒤 실행 해봅시다. 스택오버플로우 에러가 뜨는 것을 확인할 수 있습니다. def unsafeSum ( n : Int ) : Int = if ( n == 1 ) 1 else n + unsafeSum ( n - 1 ) println ( s "sum = ${unsafeSum(100000)}" ) // 실행결과 // Exception in thread "main" java.lang.StackOverflowError // at dogs.MyApp$.unsafeSum(Main.scala:8) // at dogs.MyApp$.unsafeSum(Main.scala:8) // at dogs.MyApp$.unsafeSum(Main.scala:8) // at dogs.MyApp$.unsafeSum(Main.scala:8) 이번에는 아래와 같이 함수를 수정한 뒤에 실행 해봅시다. 스택오버플로우 없이 잘 동작하는 것을 확인할 수 있습니다. def safeSum ( n : Int , acc : Int ) : Int = if ( n == 0 ) acc else safeSum ( n - 1 , n + acc ) println ( s "sum = ${safeSum(100000, 0)}" ) // 실행결과 // sum = 705082704 대체 무슨 차이점 때문일까요? unsafeSum(5) 가 값을 반환하려면 일단 unsafeSum(4) 를 호출해서 결과를 얻은다음에 그 결과에 5 를 더해야합니다. ...

Akka typed 소개

안녕하세요~ 오늘은 akka 의 새로운 인터페이스 (API) 인 akka typed 에 대해서 소개시켜드리는 시간을 가져볼까 합니다! Akka 및 액터 모델에 대한 기본적인 내용은 이미 알고 있다고 가정하며 scala 를 기반으로 설명하겠습니다. 기존 akka 에서의 문제점 akka 는 훌륭한 프레임워크이지만 인터페이스 (API) 상으로 아쉬운 부분들이 있습니다. class EchoStringActor extends Actor { def receive = { case str : String => sender ( ) ! str case _ => sender ( ) ! "Unexpected message" } } 메세지의 타입이 Any 입니다. Java/scala 는 정적 타이핑 언어로서 컴파일타임에 타입시스템을 이용해 많은 오류를 사전에 차단시켜줍니다. 그러나 akka 의 인터페이스에서는 액터가 받는 메세지의 타입이 Any 입니다. 따라서 정적 타이핑의 이점을 전혀 누릴수가 없습니다. 만약에 개발자가 실수로 특정 타입의 메세지를 처리하는 것을 깜박하더라도 컴파일 에러가 나지 않습니다. 액터들이 어떤 메세지를 서로 주고받는지가 명확하게 드러나지 않아서 저는 전체 액터 시스템을 분석하고 유지보수할 때 상당히 복잡하고 머리속에 정리가 잘 안된다는 느낌을 많이 받았습니다. 함수형 스타일이 아닙니다. Actor 를 정의하기위해서는 Actor 클래스를 상속받아서 새로운 클래스를 만들어줘야 합니다. 메세지 처리 함수를 변경하기 위해서 become() 을 사용해야 하고 액터 내부의 상태를 mutable ( var ) 로서 관리해야 합니다. 저는 이로 인해 액터 코드가 상당히 복잡하고 스파게티처럼 꼬여있는 것 같다는 느낌을 많이 받았고 코드를 분석하고 유지보수하는게 까다롭다고 느꼈습니다. 그러면 akka typed 은 이러한 문제들을 어떠...

Purely Functional Business Logic In Scala

안녕하세요~ 오늘은 스칼라에서 비지니스 로직을 purely functional 하게 설계하는 방법에 대해서 소개해볼까 합니다. 함수형 프로그래밍, 스칼라, cats, DDD 에 대해서 알고 계시면 이해가 수월하시겠지만 모르시는 분들을 위해서 기본적인 설명도 같이 첨부해두었습니다. 다루는 내용 cats 의 RWST (ReaderWriterStateT) 를 활용해서 핵심 비지니스 로직을 purely functional 하게 작성하는 방법 그렇게 작성된 비지니스 로직을 DDD (Domain Driven Development) 설계에서 사용하는 방법 비지니스 로직에 대한 고찰 소프트웨어 설계와 개발에 있어서 가장 중요한 건 요구사항 분석이라고 생각합니다. 그리고 그러한 요구사항을 처리하기 위한 로직 (즉, 비지니스 로직) 을 잘 구현하고 테스트하는 것이 개발에 있어서 가장 우선순위라고 생각합니다. DDD (Domain Driven Development) 에서는 이러한 비지니스 로직들을 도메인 레이어에 위치시키고 핵심 도메인 엔티티와 규칙을 나타내는 코드는 세부 구현 (어떤 DB 를 사용하는지, 어떤 라이브러리를 사용하는지, 외부와 어떻게 통신하는지 등등) 에 의존하지 않도록 설계합니다. 자, 그렇다면 비지니스 로직을 도메인 레이어에 따로 분리시키고 세부 구현사항들과의 의존성을 제거하면 실질적으로 어떤 장점들이 있을까요? 인터넷에 검색해보시면 많은 이야기들을 보실 수 있는데요. 제가 경험한 장점들을 살짝 나열하자면 다음과 같습니다. 비지니스 로직과 요구사항들이 한눈에 들어오고 관리가 용이해집니다. 세부구현과의 의존성이 적으므로 테스트가 용이해집니다. 추후에 프레임워크나 기반 인프라를 변경하는 것이 용이해집니다. (보통 프레임워크나 인프라 위에서 비지니스 로직을 구현하는 것이 자연스럽다고 생각하실 수도 있지만 DDD 에서는 비지니스 로직이 가장 안쪽에 레이어에 위치하고 프레임워크나 인프라는 바깥 레이어에 위치하도록 하기때문에 이런...