class: center, middle, inverse # Regenesca Refactoring Generator of Source Code for Scala --- # Who am I? Sakib HadΕΎiavdiΔ - Based in Bosnia π§π¦ - Software Engineer @ [Snowplow](https://snowplow.io) - Doing OSS work: FlowRun, Hepek, Sharaf... https://github.com/sake92 --- # Approaches to Generating Source Code 1. **Generate once**, and later.. overwrite (β―Β°β‘Β°)β―οΈ΅ β»ββ» 1. Generate with marker **comments/annotations** or **do-not-touch files** 1. Generate **interfaces that user extends** 1. **Macros** 1. **AI** tools π€ 1. Regenesca, **generate and then refactor** --- # Generate once - giter8/sbt/mill/maven/gradle templates - [OpenAPITools/openapi-generator](https://github.com/OpenAPITools/openapi-generator) - generating JPA code from IDEs - protoc - Ruby on Rails, Django, JS frameworks scaffolds -- ... β Pros: **simple to implement** -- β Cons: **hard to evolve**, overwrites your code ??? Some note. --- # Generate with marker comments/annotations - yeoman - JHipster ```scala * //
class MyGeneratedClass() { ... } * //
def otherCustomCode... ``` -- ... β Pros: simple(ish) to implement -- β Cons: rarely works well in practice --- # Generate interfaces that user extends/use - https://guardrail.dev - GRPC -- ... β Pros: simple to implement -- β Cons: code is hidden from you --- # Macros - scala macros - dotnet source generators - ... -- ... β Pros: simple to use -- β Cons: hard to write, sometimes limited, increase compile time, hard to debug, obscure error messages --- # AI tools - ChatGPT - Copilot - Claude - Cursor - ... -- ... β Pros: easy to use, explains code etc. -- β Cons: none π -- (just kidding) -> expensive, can hallucinate, not always available... --- # Demo 0: quill generator --- class: center, middle, inverse # Regenesca: generate and then refactor What if there was a tool that would update code **as if you did it by hand**? Not just a mere boilerplate generator, but a **boilerplate maintainer**. --- # How Regenesca works  --- class: middle ```scala // imagine these are pulled from a file/db/api * val sqlTables = Seq("user", "item", "customer") val generatedSources = for { sqlTable <- sqlTables } yield { val filePath = Paths.get(s"example/src/generated/${sqlTable}.scala") * GeneratedFileSource(filePath, generateSource(sqlTable)) } // here it does diffing and writing to disk val generator = RegenescaGenerator(SourceMerger()) * generator.generate(generatedSources) def generateSource(sqlTable: String): Source = { val typeName = Type.Name(sqlTable) val termName = Term.Name(sqlTable) val tableNameLit = Lit.String(sqlTable) * source""" * case class ${typeName}() * * object ${termName} { * val tableName = ${tableNameLit} * } * """ } ``` --- class: middle user.scala : ```scala case class User() object User { val tableName = "user" } ``` item.scala : ```scala case class Item() object Item { val tableName = "item" } ``` customer.scala : ```scala // you can add your own code here case class Customer() // or here object Customer { val tableName = "customer" // or here } // or here ``` --- # Demo 1: simple generator --- # Demo 2: *recursive* generator --- # Demo 3: db + openapi generator - [squery](https://github.com/sake92/squery) SQL models+DAO generator - [openapi4s](https://github.com/openapi4s/openapi4s) OpenAPI server generators
See https://github.com/sake92/sharaf-api-starter --- class: center, middle # \# humblebrag  ??? People find it very powerful, and even mistake it for AI-generated tool. --- # Regenesca Limitations - expressions are hard to refactor - rules are a bit adhoc - writing scalameta is not *that fun* --- class: center, middle # Conclusion How can you help? Try regenesca/squery/openapi4s, report issues, suggest features.
See https://github.com/sake92
Thanks for listening!