Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Automatisierte Migrationen und Refactorings mit...

Automatisierte Migrationen und Refactorings mit OpenRewrite - Spring Meetup 15.03.2023

Viele von uns kennen die Herausforderung, die das Aktualisieren größerer Codebases mit sich bringt. Insbesondere das Aktualisieren von Frameworks oder Bibliotheken kostet viel Zeit, die mit der Weiterentwicklung von Features oder Behebung von Bugs konkurriert.
OpenRewrite ist ein Open Source Projekt, das genau solche Upgrades und Migrationen automatisiert umsetzen kann.
In meinem Vortrag möchte euch zeigen, wie OpenRewrite unter der Haube funktioniert, und wie ihr selbst Rezepte erstellen und in euren Organisationen verteilen könnt.

Avatar for Johannes Jank

Johannes Jank

March 16, 2023

More Decks by Johannes Jank

Other Decks in Technology

Transcript

  1. Häufige Gründe für Software-Migrationen: 1. Sicherheit oder Compliance 2. Performance-Verbesserungen

    3. Produktivitätsgewinn 4. … Oft keine wertschöpfenden Gründe für Unternehmen - eher ein ein notwendiges Übel Upgrades und Migrationen – why bother?
  2. • Spring Boot 1.x à 2.x à 3.x • javax

    à jakarta • Java 8 à Java 11 à Java 17 • Logj4 à Slf4j (Log4Shell) • Firmen-interne Libraries • Kubernetes Manifeste • … Upgrades und Migrationen – konkrete Beispiele
  3. Wem kommt so etwas bekannt vor? One or more dependencies

    were identified with known vulnerabilities in $application: LatencyUtils-2.0.3.jar (pkg:maven/org.latencyutils/[email protected], cpe:2.3:a:utils_project:utils:2.0.3:*:*:*:*:*:*:*) : CVE-2021-4277 // mehr Zeilen… cpe:2.3:a:apache_tomcat:apache_tomcat:9.0.46:*:*:*:*:*:*:*) : CVE-2021-33037, CVE-2021-42340, CVE-2021- 43980 // …endlich: See the dependency-check report for more details. Dependency-Scanner
  4. • Dependency-Checker, Linter oder statische Analysetools erstellen nur Reports •

    Viele Reports… • …wir ersticken in Reports • Reports und Vorschläge alleine lösen keine Probleme Nur Reports – keine Actions
  5. Wir erinnern uns an diese Metrik: • Nur ein beliebiges

    Beispiel für ein Repository – das Problem wird viel schlimmer “at scale” • Es muss nicht Netflix-Style Scale sein – auch kleinere und mittlere Firmen haben viel Code • Wir alle führen unabhängig voneinander die exakt gleichen Migrationen (Spring Boot 3.x, Java 17) durch • …Automatisierung? Wir brauchen bessere Tools
  6. • Open-Source Projekt (Apache 2.0) - https://github.com/openrewrite • Ursprünge bei

    Netflix: Ablösung eines internen Logging-Frameworks durch Slf4j • Perfekte Transformation war notwendig • Sollte minimale Änderungen produzieren • Lösung: AST- (Abstract Syntax Tree) Parser und Manipulator, implementiert in Java • Der Gründer Jonathan Schnéider hat um OpenRewrite die Firma Moderne gegründet – die: • Primär die Entwicklung auf Github vorantreibt • OpenRewrite-as-a-Service anbietet Anmerkung: Moderne hat sich dazu commited, OpenRewrite immer Apache 2.0 zu belassen Enter OpenRewrite
  7. Früher Fokus auf Java und die JVM (Sprachen, Build-Tools, etc)

    • Support für mehr Sprachen ist in Arbeit (Javascript, Typescript, Python & C#) • Schon heute gibt es viele Recipes - die Grundbausteine von OpenRewrite • Ausführung durch Maven- oder Gradle-Plugins – alternativ auch ohne Build-Tool Was ist unterstützt
  8. • Der von OpenRewrite aufgebaute AST hat mehr Informationen als

    ein “gewöhnlicher” AST • OpenRewrite nennt diese Datenstruktur einen Losless Semantic Tree (LST) • Enthält exakte und vollständige Typinformationen • Kennt spezifische Formattierung • Azyklisch – kann serialisiert werden Recipes under the hood – Lossles Semantic Trees Quelle: https://docs.openrewrite.org/concepts-and-explanations/lst-examples
  9. • Recipes manipulieren den AST und schreiben die Veränderungen zurück

    in die betroffenen Files • Werden mit dem Visitor Pattern implementiert: • Code finden (match) • ggf. Ersetzten (modifiy) • Konkretes Beispiel: Use the new requestMatchers with Spring Security 5.8 • Hintergrund: mvcMatchers(..), antMatchers(..) und regexMatchers(..) sind deprecated seit Spring Security 5.8 – der Ersatz ist requestMatchers(..) Recipes under the hood
  10. • Source auf Github • Weiter gehts interaktiv in der

    IDE J Recipes under the hood – UseNewRequestMatchers
  11. • Die gute Nachricht: Oft wird man keine eigenen Recipes

    implementieren müssen 😅 • Recipes sind composable - viele kleine Schritte ergeben zusammen eine (große) Migration • Dieser Ansatz ist deklarativ – die Recipes werden als YAML-Files geschrieben und so auch verteilt werden • In einem Jar sucht OpenRewrite unter /META-INF/rewrite/ nach YAML Recipes Eigene Recipes
  12. Yaml Recipes - Spring Boot 2.0 type: specs.openrewrite.org/v1beta/recipe name: org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_0

    displayName: Upgrade to Spring Boot 2.0 from 1.x description: 'Upgrade to Spring Boot 2.0 from prior 1.x version.' recipeList: type: specs.openrewrite.org/v1beta/recipe name: org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_0 displayName: Upgrade to Spring Boot 2.0 from 1.x description: 'Upgrade to Spring Boot 2.0 from prior 1.x version.' recipeList: # Upgrade 2.0.x from 1.x - org.openrewrite.maven.UpgradeDependencyVersion: groupId: org.springframework.boot artifactId: "*" newVersion: 2.0.x <-- Semantic versioning! overrideManagedVersion: true type: specs.openrewrite.org/v1beta/recipe name: org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_0 displayName: Upgrade to Spring Boot 2.0 from 1.x description: 'Upgrade to Spring Boot 2.0 from prior 1.x version.' recipeList: # Upgrade 2.0.x from 1.x - org.openrewrite.maven.UpgradeDependencyVersion: groupId: org.springframework.boot artifactId: "*" newVersion: 2.0.x overrideManagedVersion: true - org.openrewrite.maven.UpgradeParentVersion: groupId: org.springframework.boot artifactId: spring-boot-starter-parent newVersion: 2.0.x - org.openrewrite.maven.RemoveProperty: propertyName: thymeleaf.version - org.openrewrite.maven.RemoveDependency: groupId: org.webjars artifactId: webjars-locator - org.openrewrite.java.spring.framework.UpgradeSpringFramework_5_0 # Update properties - org.openrewrite.java.spring.boot2.SpringBootProperties_2_0 # …
  13. Wir haben hier eine Anwendung aus bestehend ~30 Microservices. Die

    sind alle noch auf Boot 1.5.x und müssen dringend aktualisiert werden… Mit vergleichbaren Aufgaben sind einige von uns vermutlich schon konfrontiert worden • Da kommt einiges an Arbeit zusammen: • Spring Boot 1.x auf 2.x • Deployment Descriptoren • diverse andere Konfiguration • Properties, die via Spring Cloud Configserver bezogen werden • … • Wenn man mit ~1 Tag pro Service rechnet (nur für Code- und Konfigration) ~30 Tage • Kein Wunder, dass das so lange herausgezögert wurde Case Study einer Migration (angepasst)
  14. OpenRewrite to the rescue type: specs.openrewrite.org/v1beta/recipe name: com.acme.migrate.SomeMigration recipeList: #

    Tomcat statt Jetty - org.openrewrite.maven.RemoveDependency: groupId: org.springframework.boot artifactId: spring-boot-starter-jetty # Log4J entfernen - org.openrewrite.maven.RemoveDependency: groupId: org.springframework.boot artifactId: spring-boot-starter-log4j - org.openrewrite.DeleteSourceFiles: filePattern: src/main/resources/log4j.properties # Elastic Logback Appender - org.openrewrite.maven.AddMavenDependency: groupId: co.elastic.logging artifactId: logback-ecs-encoder version: latest - org.openrewrite.text.CreateTextFile: relativeFileName: src/main/resources/logback-spring.xml fileContents: '<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="co.elastic.logging.logback.EcsEncoder" /> </appender> <root level="INFO"> <appender-ref ref="STDOUT" /> </root> </configuration>' - org.openrewrite.properties.AddProperty: property: spring.application.name value: $$CHANGE-ME$$ <-- Custom visitor…? fileMatcher: src/main/resources/application.properties # Zu guter letzt: Spring Boot 2.x - org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_7
  15. Die Verteilung ist im Java-Umfeld sehr einfach: • Deklarative YAML

    Recipes unter /META-INF/rewrite/ • Custom Code wie bei jedem anderen Jar • Publizieren, z.b. ins firmeneigene Maven Repository • Konsumenten können solche Jars dann als Abhängigkeit bei der Migration angeben (vgl. Demo): mvn org.openrewrite.maven:rewrite-maven-plugin:run \ -Drewrite.recipeArtifactCoordinates=com.acme.migrate:rewrite-custom:1.0.0 \ -DactiveRecipes=com.acme.migrate.SomeMigration Recipes verteilen
  16. • POC erfolgreich: • Die Ausführung des Rezeptes für einen

    Service (= ein Repository) dauert ~ eine Minute • Keine Gefahr von Copy & Paste-Fehlern • Mehr Zeit um die Migration inhaltlich zu verifizieren – Semantik > Syntax Erfahrungen aus Proof-of-Concept
  17. “A fool with a tool is still a fool” •

    OpenRewrite hilft und unterstützt bei der Migration durch Automatisierung • Änderungen müssen trotzdem bewertet bzw. getestet werden Disclaimer zum Abschluss
  18. Meinung: OpenRewrite wird sich rasch verbreiten – und das ist

    auch gut so! • Wünschenswert: Library- und Framework-Entwickler liefern bei Updates selbst die Recipes mit aus • Das Spring-Team ist ganz vorne mit dabei und arbeitet aktiv an Recipes und ist Teil der Community ❤ • Egal ob ”legacy” oder frisches Cloud native Projekt – Updates kommen immer • Mit OpenRewrite bleibt mehr Zeit für die wesentlichen Dinge: • Fachlichkeit • Architektur • Kommunikation • …alles, was glückliche User oder Kunden bringt Ausblick
  19. Call to Action: Probiert OpenRewrite aus und werdet Teil der

    Community • Offizielle Dokumentation: • Recipe catalog • Running recipes – getting started • Writing a Java refactoring recipe • Concepts and explanations • OpenRewrite Slack - die Leute dort sind unfassbar schnell und hilfsbereit • Code auf Github • Moderne.io - Login mit Github, kostenlos für öffentliche Repositories Next Steps
  20. Professional Technical Consultant Johannes Jank bbv Software Services GmbH Elsenheimerstr.

    9 80687 München Email: [email protected] LinkedIn: Johannes Jank Github: jjank Speakerdeck: jjank Telefon: +49 89 452 4383 43 Kontakt