BMAD-METHOD/.claude/rules/scala-kafka-cursorrules-pro.../general-scala-development-p...

53 lines
3.6 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
description: Applies general coding standards and best practices for Scala 3 development, focusing on SOLID, DRY, KISS, YAGNI and idiomatic functional-programming style. Tailored for an sbt project that uses Kafka Streams.
globs: **/*.scala
alwaysApply: true
---
# ========== GENERAL PRINCIPLES ==========
- You are an experienced Senior Scala Developer.
- You always adhere to SOLID, DRY, KISS and YAGNI principles.
- Prefer *pure* functions; minimise side-effects. Where effects are required, make them explicit (e.g. using scala.util.Try, Either, or cats-effect IO/Task if adopted).
- Use *val* over *var*; collections must be immutable unless mutability is proven cheaper & safe.
- Replace *null* with Option, Either or a domain-specific ADT.
- Use pattern matching exhaustively and handle the *default* case only when truly open-ended.
- Prefer for-comprehensions, map/flatMap/fold, and higher-order functions over imperative loops.
- Prefer *case classes* and *sealed traits* for algebraic data types.
- Extract common logic into private or package-private helpers; avoid long methods (> 30 LOC).
- Prefer extension methods or type classes over inheritance when adding behaviour.
- Keep public APIs small, surface only what the module owns.
- Break every task into the smallest composable pure functions before wiring them together.
# ========== NAMING & SYNTAX ==========
- Class / object / trait names are UpperCamelCase nouns (e.g. *NotificationStreamApp*).
- Methods & vals are lowerCamelCase verbs or nouns (e.g. *process*, *serde*, *productKey*).
- Constants use `SCREAMING_SNAKE_CASE`.
- Similar to Javas static final members, if the member is final, immutable and it belongs to a package object or an object, it may be considered a constant.
- Symbolic names (`|>`) are allowed *only* when they align with widespread FP idioms.
- Match expressions use `match`/`case` over nested if/else chains; for simple two-branch logic prefer `if … then … else …` expressions.
# ========== ERROR HANDLING & LOGGING ==========
- Catch the most specific Exception first; convert checked Java exceptions to an ADT or `Try`.
- No empty `catch` blocks; log at *debug* or *error* level with a meaningful message.
- Leverage `scala.util.Using` (or cats-effect `Resource`) for auto-closing resources.
- Avoid “defensive” logging or `println`; use SLF4J (Logback) with the *scala-logging* wrapper.
# ========== TESTING ==========
- Use ScalaTest in a **Given-When-Then** layout with the use of AnyFlatSpec.
- Focus on critical paths and business invariants; do not over-test boilerplate.
- Property-based tests (ScalaCheck) for pure functions with non-trivial invariants.
- Set up integration tests as a subproject named “integration” and treat integration tests as standard tests
# ========== PERFORMANCE & SAFETY ==========
- Avoid blocking calls inside Kafka stream processing; if unavoidable, off-load to a dedicated thread-pool.
- Convert Java collections to Scala equivalents once at the boundary; never bounce back and forth.
- Use underscore-separated digits for large numeric literals (e.g. `val timeoutMs = 30_000`).
# ========== MODERN SCALA 3 FEATURES ==========
- Use *Enums* for finite alternatives instead of Java-style enums.
- Embrace *opaque types* to avoid accidental misuse of primitive wrappers.
- Use *context parameters* (`using`) for type-class evidence instead of classic implicit lists when convenient.
- Prefer `given`/`using` syntax over `implicit` where supported.
# ========== CLEAN BUILD ==========
- The sbt build uses **scalafmt** for formatting; treat any scalafmt violation as a build error.