본문으로 건너뛰기
cccskills
무료GitHub에 공개

nw-fp-scala

Scala 3 language-specific patterns with ZIO, Cats Effect, and opaque types

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(1)

  • SKILL.md6.5 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

FP in Scala 3 -- Functional Software Crafter Skill

Cross-references: fp-principles | fp-domain-modeling | property-based-testing

When to Choose Scala

  • Best for: JVM with full FP power | large-scale systems | data engineering | richest effect ecosystem
  • Not ideal for: small teams wanting simplicity | Android (use Kotlin) | teams allergic to OO/FP duality

[STARTER] Quick Setup

cs install scala3-compiler scala3-repl sbt
sbt new scala/scala3.g8 && cd order-service
# Add zio, zio-test, scalacheck to build.sbt
sbt compile && sbt test

[STARTER] Type System for Domain Modeling

Choice Types and Record Types

enum PaymentMethod:
  case CreditCard(cardNumber: String, expiryDate: String)
  case BankTransfer(accountNumber: String)
  case Cash

case class Customer(
  customerId: CustomerId,
  customerName: CustomerName,
  customerEmail: EmailAddress
)

Case classes provide structural equality, copy, and pattern matching for free.

[STARTER] Domain Wrappers (Opaque Types) -- Zero Cost

object OrderDomain:
  opaque type OrderId = Int
  object OrderId:
    def apply(value: Int): OrderId = value
  extension (id: OrderId) def value: Int = id

  opaque type EmailAddress = String
  object EmailAddress:
    def from(raw: String): Either[ValidationError, EmailAddress] =
      if raw.contains("@") then Right(raw)
      else Left(InvalidEmail(raw))

Inside defining scope, alias is transparent. Outside, only exported operations available.

[INTERMEDIATE] Composition Style

For-Comprehensions (Monadic Chaining)

def placeOrder(raw: RawOrder): Either[OrderError, Confirmation] =
  for
    validated <- validateOrder(raw)
    priced    <- priceOrder(validated)
    confirmed <- confirmOrder(priced)
  yield confirmed

Error Accumulation (Cats Validated or ZIO)

import cats.data.Validated
import cats.syntax.all.*

def validateCustomer(raw: RawCustomer): ValidatedNel[ValidationError, Customer] =
  (validateName(raw.name), validateEmail(raw.email), validateAddress(raw.address))
    .mapN(Customer.apply)

[ADVANCED] Effect Management

ZIO vs Cats Effect

ZIO: ZIO[R, E, A] with built-in typed errors, DI (ZLayer), batteries-included. Cats Effect: IO[A], minimal type-class-based, Typelevel ecosystem (http4s, FS2, Doobie). Pick one and stay consistent.

ZIO Hexagonal Architecture

trait OrderRepository:
  def findOrder(id: OrderId): Task[Option[Order]]
  def saveOrder(order: Order): Task[Unit]

def placeOrder(raw: RawOrder): ZIO[OrderRepository & PricingService, OrderError, Confirmation] =
  for
    repo      <- ZIO.service[OrderRepository]
    validated <- ZIO.fromEither(validateOrder(raw))
    priced    <- ZIO.fromEither(priceOrder(validated))
    _         <- repo.saveOrder(priced)
  yield Confirmation(priced.orderId)

// Adapter
class PostgresOrderRepository(ds: DataSource) extends OrderRepository:
  def findOrder(id: OrderId): Task[Option[Order]] = ZIO.attemptBlocking { /* query */ }
  def saveOrder(order: Order): Task[Unit] = ZIO.attemptBlocking { /* insert */ }

val appLayer: ZLayer[Any, Nothing, OrderRepository & PricingService] =
  PostgresOrderRepository.layer ++ PricingServiceLive.layer

Cats Effect / Tagless Final

trait OrderRepository[F[_]]:
  def findOrder(id: OrderId): F[Option[Order]]

def placeOrder[F[_]: Monad](repo: OrderRepository[F])(raw: RawOrder): F[Either[OrderError, Confirmation]] =
  for
    validated <- Monad[F].pure(validateOrder(raw))
    result <- validated match
      case Left(err) => Monad[F].pure(Left(err))
      case Right(v)  => repo.findOrder(v.orderId).map(_.toRight(OrderNotFound))
  yield result

[INTERMEDIATE] Testing

Frameworks: ScalaCheck (PBT) | ZIO Test (integrated PBT + unit) | ScalaTest (BDD) | MUnit (lightweight). See property-based-testing for detailed PBT patterns.

Property Test (ScalaCheck)

import org.scalacheck.Properties
import org.scalacheck.Prop.forAll

object OrderSpec extends Properties("Order"):
  property("serialization round-trips") = forAll { (order: Order) =>
    deserialize(serialize(order)) == Right(order)
  }
  property("validated orders have positive totals") = forAll { (raw: RawOrder) =>
    validateOrder(raw) match
      case Left(_)     => true
      case Right(valid) => valid.total.value > 0
  }

[ADVANCED] Idiomatic Patterns

Enum-Based State Machines

enum OrderState:
  case Unvalidated(raw: RawOrder)
  case Validated(order: ValidatedOrder)
  case Priced(order: PricedOrder)
  case Confirmed(confirmation: Confirmation)

def transition(state: OrderState, command: OrderCommand): Either[OrderError, OrderState] =
  (state, command) match
    case (OrderState.Unvalidated(raw), OrderCommand.Validate) =>
      validateOrder(raw).map(OrderState.Validated(_))
    case (OrderState.Validated(order), OrderCommand.Price) =>
      priceOrder(order).map(OrderState.Priced(_))
    case _ => Left(InvalidTransition(state, command))

Extension Methods for Domain Operations

extension (order: PricedOrder)
  def totalWithTax(taxRate: BigDecimal): Money = Money(order.total.value * (1 + taxRate))
  def isHighValue: Boolean = order.total.value > 1000

Maturity and Adoption

  • Ecosystem fragmentation: ZIO vs Cats Effect creates split ecosystem. Libraries often target one or the other. Mixing is painful.
  • Slow compilation: Scala 3 faster than 2 but still significantly slower than Kotlin or Java. Keep modules small; consider Mill over sbt.
  • Complexity reputation: Scala's power (implicits, type-level programming, macros) creates wildly varying codebases. Establish team conventions early.
  • Migration burden: Scala 2 to 3 migration non-trivial. Ecosystem has mostly caught up by 2025-2026.

Common Pitfalls

  1. Ecosystem fragmentation: Pick one effect ecosystem (ZIO or Cats) and stay consistent. Mixing creates dependency conflicts.
  2. Implicit/given complexity: Keep given instances close to their types. Deep resolution chains produce cryptic errors.
  3. OO/FP tension: Prefer case classes + enums + pure functions over class hierarchies with mutable state.
  4. Slow compilation: Use sbt incremental compilation, keep modules small, consider Mill for faster builds.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Review dimensions for validating agent quality - template compliance, safety, testing, and priority validation

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

nWave-ai/nWave6212026년 9월 16일 업데이트

Review dimensions for validating agent quality - template compliance, safety, testing, and priority validation

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

nWave-ai/nWave6212026년 9월 16일 업데이트

Review dimensions for acceptance test quality - happy path bias, GWT compliance, business language purity, coverage completeness, walking skeleton user-centricity, priority validation, observable behavior assertions, traceability coverage, and walking skeleton boundary proof

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

nWave-ai/nWave6212026년 9월 16일 업데이트

Detailed 5-phase workflow for creating agents - from requirements analysis through validation and iterative refinement

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

nWave-ai/nWave6212026년 9월 16일 업데이트

5-layer testing approach for agent validation including adversarial testing, security validation, and prompt injection resistance

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

nWave-ai/nWave6212026년 9월 16일 업데이트

Architectural style selection decision matrices, trade-off analysis, structural enforcement rules, and combination patterns. Load when choosing or evaluating architecture styles.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

nWave-ai/nWave6212026년 9월 16일 업데이트

nWave-ai의 스킬 모두 보기

이 스킬의 문제 신고