This plan defines a specification‑driven development methodology for Scala. The methodology separates intent, structural specification, and implementation into distinct layers. Implementation artifacts are generated from machine‑readable specifications and automatically verified against architectural constraints. Development proceeds in phases, each phase committing a fixed premise (versioned specification + dependencies) for recursive refinement.
All principles are mapped to executable Scala constructs and toolchain integrations.
| Principle | Scala Implementation | Tooling |
|---|---|---|
| Intent–Structure–Implementation Separation | Opaque types, package layering, traits (specification) + concrete classes (implementation) | Scala 3 compiler |
| Generative Conformance | Code generation from Smithy IDL / OpenAPI / Protobuf | Smithy4s, OpenAPI Generator, sbt-protoc |
| Skeleton–Tissue Architecture | Abstract classes with final template methods, control‑flow functions, ZIO Layers |
Scala standard library, ZIO |
| Validation Gates | Compiler flags, Scalafix custom rules, sbt-dependency-graph, MiMa, TASTy-MiMa | scalac, Scalafix, MiMa |
| Recursive Refinement | Git tags, semantic versioning, API compatibility checks | Git, sbt‑version‑policy |
The specification is expressed in a machine‑readable format and stored under specification/.
| Scope | Format | Tool |
|---|---|---|
| API boundaries (HTTP/REST) | Smithy IDL (preferred) or OpenAPI 3.0+ YAML | Smithy4s, OpenAPI Generator |
| Internal module contracts | Scala traits + opaque types | Scala 3 compiler |
| Data models | Smithy structures or JSON Schema | Smithy4s, zio‑schema |
Selection rule: Use Smithy IDL for all service boundaries. It is protocol‑agnostic and generates both client and server code. Use opaque types for internal type‑level contracts.
The skeleton owns the invariant control flow and cross‑cutting concerns. It is written once by humans and never modified by generated code.
Pattern A: Template Method (abstract class + final)
// skeleton/PipelineSkeleton.scala
abstract class PipelineSkeleton:
final def execute(input: Input): Output =
val validated = validate(input)
val processed = transform(validated)
val persisted = save(processed)
log(persisted)
protected def validate(input: Input): Validated
protected def transform(validated: Validated): Transformed
protected def save(processed: Transformed): Persisted
protected def log(persisted: Persisted): Output
Pattern B: Control‑Flow Function + Interface (no inheritance)
// skeleton/RunLoop.scala
trait Steps[F[_]]:
def init: F[Unit]
def step: F[Int]
def cleanup: F[Unit]
object RunLoop:
final def run[F[_]: Monad](steps: Steps[F]): F[Int] =
for
_ <- steps.init
result <- steps.step
_ <- steps.cleanup
yield result
Pattern C: Opaque Type for Boundary Enforcement
// specification/Ids.scala
package specification:
opaque type UserId = UUID
object UserId:
def apply(id: UUID): UserId = id
extension (uid: UserId) def value: UUID = uid
The tissue implements the skeleton interfaces. It is fully generated from the structural specification.
// tissue/PipelineImpl.scala (generated)
class PipelineImpl extends skeleton.PipelineSkeleton:
override protected def validate(input: Input): Validated = // generated
override protected def transform(validated: Validated): Transformed = // generated
override protected def save(processed: Transformed): Persisted = // generated
override protected def log(persisted: Persisted): Output = // generated
skeleton → tissue imports.| Tool | Input | Output | Use Case |
|---|---|---|---|
| Smithy4s | Smithy IDL | Service traits, DTOs, client/server stubs | API contracts (preferred) |
| OpenAPI Generator | OpenAPI YAML | Scala client (sttp4 + jsoniter) | External API clients |
| sbt-protoc + ScalaPB | .proto | Case classes, gRPC stubs | Internal RPC |
| zio‑schema | Scala case classes (derived) | Schemas, codecs, migrations | Data contract evolution |
| Scala 3 macros | Inline definitions | Method implementations | Boilerplate reduction |
Recommendation: Use Smithy4s as the primary generator. It produces a complete skeleton (service traits) from a single specification and supports multiple protocols.
// build.sbt
ThisBuild / scalacOptions ++= Seq(
"-Xfatal-warnings", // warnings → errors
"-Xsource:3", // Scala 3 migration warnings
"-language:explicitNulls", // explicit null safety
"-Wconf:cat=scala3-migration:e" // migration warnings as errors
)
Custom rule to enforce skeleton‑tissue dependency direction:
// custom-rules/src/main/scala/fix/LayerEnforcer.scala
class LayerEnforcer extends SyntacticRule("LayerEnforcer") {
override def fix(implicit doc: SyntacticDocument): Patch = {
doc.tree.collect {
case imp @ Importee.Name(Name("tissue"))
if doc.input.syntax.contains("skeleton/") =>
Patch.lint(Diagnostic("", "Skeleton cannot import tissue", imp.pos))
}.asPatch
}
}
Run in CI: sbt "scalafix --check"
Detect circular dependencies using sbt-dependency-graph:
sbt dependencyTree | grep -q "cycle" && exit 1
Standard ScalaTest / Specs2 suites. Generated tissue code must pass all unit and integration tests.
// build.sbt
mimaPreviousArtifacts := Set("com.example" %% "module" % "1.0.0")
tastyMiMaPreviousArtifacts := Set("com.example" %% "module" % "1.0.0")
Each phase follows this sequence:
Rollback: git checkout <previous-tag> && sbt clean compile
Parallel phases: Use Git worktree for concurrent specification branches.
| Phase | Scope | Deliverable | Duration |
|---|---|---|---|
| 0 | Infrastructure | SBT multi‑module layout, Scalafmt, Scalafix base config | 2 weeks |
| 1 | Skeleton design | Abstract classes, control‑flow functions, opaque types | 3 weeks |
| 2 | Structural specification | Smithy IDL files for one module | 2 weeks |
| 3 | Generation pipeline | Smithy4s integration, generated code in tissue/ |
3 weeks |
| 4 | Validation gates | Scalac flags, Scalafix rule, MiMa, CI workflow | 3 weeks |
| 5 | Pilot project | Apply to one service, measure regeneration and bug rates | 4 weeks |
project-root/
├── specification/
│ └── api/
│ └── service.smithy
├── skeleton/
│ └── core/
│ ├── ServiceInterface.scala (generated by Smithy4s)
│ └── TemplateMethodBase.scala (manual)
├── tissue/
│ └── generated/
│ └── ServiceImpl.scala (generated)
├── project/
│ ├── build.sbt
│ └── plugins.sbt
└── .scalafix.conf
| Constraint | Mitigation |
|---|---|
| Scala 3 macros cannot generate top‑level definitions | Use Smithy4s for top‑level generation; macros for intra‑file expansions |
| TASTy‑MiMa is less mature | Combine with manual API review for critical modules |
| ZIO dependency for environment‑type pattern | Provide non‑ZIO alternative (constructor injection) |
| Cross‑build with Scala 2.13 | Restrict to Scala 3.3+; use separate build modules for legacy code |
| Smithy IDL learning curve | Provide templates and tooling documentation |
Scala 3 provides all necessary features to implement a specification‑driven, AI‑assisted development workflow:
final methods or control‑flow functionsThe methodology eliminates implementation‑level bugs caused by interface mismatches, enables safe refactoring through specification‑only changes, and keeps cognitive overhead independent of codebase size. The plan is ready for production use in server‑side Scala, microservices, and data pipeline projects.