Zwei zum Verlieben

Spring Boot und Vue.js im eigenen Projekt praktisch nutzen – das Tutorial

Jonas Hecht

© Shutterstock / Charcompix

Mit Vue.js gibt es schon wieder einen neuen Stern am JavaScript-Himmel? Aber wie lässt sich der denn nun wieder in den eigenen Toolstack integrieren? Am Beispiel von Spring Boot als populärem Vertreter moderner Java-Frameworks lässt sich sehr gut zeigen, wie das geht. Eine Einführung in alles, was man zum Leben mit Spring Boot und Vue.js braucht.

Das JavaScript-Framework Vue.js ist gerade in aller Munde. Das kommt natürlich nicht von ungefähr, bietet es doch einen schnellen Einstieg in die Welt der modernen, komponentenbasierten Webframeworks. So hat sich Vue.js schon einen Platz in der Riege der ganz Großen erarbeitet und bietet damit eine Alternative zu Angular und React [1]. Speziell die flachere Lernkurve sowie die höhere Entwicklungsgeschwindigkeit im Vergleich zu den bekannten Vertretern scheint die Entscheidung für Vue.js in vielen Projekten zu begünstigen [2].

Doch in der Praxis stellt sich natürlich die Frage, wie sich der neue Stern am JavaScript-Himmel in bereits vorhandene Stacks integrieren lässt – allen voran mit dem beliebten Java-Microservices-Framework Spring Boot. Außerdem muss ein vernünftiger (lokaler) Entwicklungsprozess her, damit das Entwickeln flott von der Hand geht. Nicht zuletzt sollten sich beide Frameworks nahtlos in bestehende Continuous-Integration- und -Delivery-Pipelines integrieren und entsprechend automatisiert deployed werden können.

Projekt-Set-up

Um dem Leser möglichst umfassend die Nachvollziehbarkeit jedes beschriebenen Punkts zu ermöglichen, findet sich auf GitHub ein vollständiges Beispielprojekt [3]. Es kann auch als Vorlage für erste eigene Projekte auf Basis von Spring Boot und Vue.js dienen. Den Erstkontakt mit den Frameworks hat man als Entwickler meist mit dem Projekt-Set-up. Eine klare Struktur kann hier den Einstieg erleichtern. Das Beispielprojekt bildet eine gewohnte Maven-Projektstruktur ab (Abb. 1).

Abb. 1: Eine klare Projektstruktur kann beim Einstieg helfen

Die pom.xml [4] im Hauptordner der Beispielanwendung spring-boot-vuejs enthält somit im Wesentlichen die beiden Maven-Module backend und frontend:

<modules>

<module>frontend</module>

<module>backend</module>

</modules>

Die Build-Reihenfolge der beiden Module ist dabei wichtig und sollte nicht geändert werden. Zuerst wird das frontend-Modul gebaut, danach das backend-Modul.

Vue.js Frontend

Um die nächsten Schritte nachvollziehen zu können, wird eine funktionierende Node.js-Installation [5] vorausgesetzt. Mithilfe eines Paketmanagers ist das schnell erledigt. So installiert beispielsweise ein brew install node alles Nötige auf einem Mac. Zusätzlich wird das Vue.js Command Line Interface (CLI) vue-cli (Abb. 2) benötigt, das einfach mit dem Node.js-Paketmanager npm [6] installiert wird: npm install –global vue-cli. Nun kann im frontend-Verzeichnis der Rumpf eines Vue.js-Projekts angelegt werden: vue init webpack frontend. Auf den Befehl folgt eine Reihe an Fragen, die interaktiv beantwortet werden wollen. Das generierte Rumpfprojekt hält alles bereit, um mit den ersten eigenen Vue.js-Experimenten zu starten.

Abb. 2: Das Vue.js CLI hilft beim Erstellen neuer Vue.js-Projekte

Betrachtet man die Welt der Webframeworks sonst eher aus gemessenem Abstand, kann einem ob der dort vorherrschenden Entwicklungsgeschwindigkeit schon etwas flau im Magen werden. Begriffe wie npm Builds [6], ESLint [7], webpack [8] usw. hören sich dann im ersten Moment vielleicht nach Raketentechnik an. Und ein wenig ist das ja auch so.

Aber es gibt Abhilfe, insbesondere wenn man eher der Riege der Backend-Entwickler entstammt. Denn dann ist Maven [9] eines der täglich genutzten Werkzeuge. Mithilfe des Frontend-Maven-Plug-ins [10] behält man den gesamten Zoo der Web-Frontend-Build-Tools im Griff. Alles, was dazu nötig ist, findet sich beispielhaft in der Konfiguration der pom.xml im frontend-Verzeichnis des Beispielprojekts [11] (Listing 1).

<build>
  <plugins>
    <plugin>
      <groupId>com.github.eirslett</groupId>
      <artifactId>frontend-maven-plugin</artifactId>
      <version>${frontend-maven-plugin.version}</version>
      <executions>
        <execution>
          <id>install node and npm</id>
          <goals>
            <goal>install-node-and-npm</goal>
          </goals>
          <configuration>
            <nodeVersion>v9.11.1</nodeVersion>
          </configuration>
          </execution>
          <execution>
            <id>npm install</id>
            <goals>
              <goal>npm</goal>
            </goals>
            <configuration>
              <arguments>install</arguments>
            </configuration>
            </execution>
          <execution>
            <id>npm run build</id>
            <goals>
              <goal>npm</goal>
            </goals>
          <configuration>
            <arguments>run build</arguments>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Die Konfiguration von frontend-maven-plugin gliedert sich dabei in drei Abschnitte. Zuerst wird mithilfe des Maven Goals install-node-and-npm sichergestellt, dass die korrekte Version von Node.js installiert wird. Ist die Version von Node.js dabei höher als die (abgekündigte) 4.0.0, installiert frontend-maven-plugin praktischerweise auch gleich die korrespondierende npm-Version.

Das zweite Maven Goal npm mit dem optionalen Argument install kümmert sich dann um die Installation aller im Vue.js Frontend benötigten Dependencies. Vom Prinzip her ähnlich einer pom.xml, werden diese Abhängigkeiten in der package.json [12] beschrieben – inklusive der expliziten Angabe aller verwendeten Versionen. Die inital durch den Befehl vue init webpack frontend angelegte package.json enthält schon eine recht umfangreiche Liste an Abhängigkeiten. Werden zusätzliche Dependencies mithilfe des Befehls npm install dependency-name installiert, wird die package.json automatisch erweitert.

Im dritten und letzten Maven Goal npm mit den Argumenten run build wird schließlich der vollständige Frontend-Build-Prozess ausgeführt. Alle drei Schritte bleiben dabei für den Entwickler transparent. Im Grunde wird dabei für die Nutzung des Projekts ausschließlich Maven-Know-how für den Einstieg benötigt. Mit steigender Erfahrung kann sich dann Schritt für Schritt dem vollständigen Frontend-Build-Prozess genähert und einzelne oder alle Teile können den Projektanforderungen entsprechend angepasst werden.

Spring Boot Backend

Einer der einfachsten Wege, eine neue Spring-Boot-Anwendung zu erstellen, ist die Nutzung der Seite https://start.spring.io/. Dabei vergibt man Maven-typisch Namen für Group und Artifact, wählt die Web-Dependency aus und klickt auf Generate Project. Die generierte .zip-Datei kann dann einfach im backend-Verzeichnis entpackt werden. Für die Integration mit Vue.js sind hier nur zwei Dinge anzupassen: Zuerst wandert der spring-boot-starter-parent in die pom.xml [4] des Hauptverzeichnisses, denn diese ist ja die Parent-POM für das backend-Modul.

Der zweite Punkt hat es dann in sich. Denn hier wird das maven-resources-plugin [13] genutzt, um die später aus dem Vue.js-Code generierten HTML-, JavaScript- und CSS-Dateien aus dem frontend- in das backend-Modul zu kopieren. Damit kann der integrierte Webserver von Spring Boot nämlich neben den üblichen (REST-)Schnittstellen des Backends auch gleich das gesamte Frontend ausliefern. Wie das konkret funktioniert, zeigt ein Ausschnitt der pom.xml des backend-Moduls [14] (Listing 2).

<plugin>
  <artifactId>maven-resources-plugin</artifactId>
  <executions>
    <execution>
      <id>Copy Vue.js frontend assets</id>
      <phase>generate-resources</phase>
      <goals>
        <goal>copy-resources</goal>
      </goals>
      <configuration>
        <outputDirectory>src/main/resources/public</outputDirectory>
        <overwrite>true</overwrite>
        <resources>
          <resource>
           <directory>${project.parent.basedir}/frontend/target/dist</directory>
            <includes>
              <include>static/</include>
              <include>index.html</include>
            </includes>
          </resource>
        </resources>
      </configuration>
    </execution>
  </executions>
</plugin>

Hier findet sich die Antwort auf die Frage nach der Build-Reihenfolge der Maven-Module frontend und backend. Denn damit die Daten kopiert werden können, müssen sie natürlich auch vorhanden sein. Das maven-resources-plugin [13] kopiert dabei einfach die Ergebnisse des Frontend-Build-Prozesses aus /frontend/target/dist nach /backend/src/main/resources/public. So kann mithilfe eines simplen Befehls wie java -jar backend-0.0.1-SNAPSHOT.jar nicht nur wie gewohnt die gesamte Spring-Boot-Anwendung gestartet werden. Es wird auch gleich das komplette Frontend unter demselben Port ausgeliefert.

Um für spätere Anwendungsfälle gewappnet zu sein, sollte noch ein einfacher RESTful Web Service erstellt werden. Die Klasse BackendController.java [15] des Beispielprojekts bietet dafür eine extrem simple Ressource namens /api/hello an, deren Aufruf natürlich innerhalb der Testklasse BackendControllerTest.java [16] getestet wird. Dafür bietet sich beispielsweise das Tool REST Assured [17] an (Listing 3).

@RunWith(SpringRunner.class)
@SpringBootTest(
  classes = SpringBootVuejsApplication.class,
  webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
public class BackendControllerTest {
  @LocalServerPort
  private int port;

  @Test
  public void saysHello() {
    when()
      .get("http://localhost:" + port + "/api/hello")
    .then()
      .statusCode(HttpStatus.SC_OK)
      .assertThat()
        .body(is(equalTo(BackendController.HELLO_TEXT)));
  }
}

Build-Output-Verzeichnis des Vue.js Frontends konfigurieren

Dem geneigten Leser ist es wahrscheinlich schon aufgefallen: Das maven-resources-plugin [13] kopiert die Frontend-Dateien aus einem Verzeichnis, in das webpack normalerweise gar nichts schreibt – nämlich nach frontend/target. Da man es aber mit einem Standard-Maven-Projekt zu tun hat, soll doch bitte schön webpack auch entsprechend konfiguriert werden. Dazu kann die Datei frontend/config/index.js [18] angepasst werden. Die Zeilen

 

// Template for index.html

index: path.resolve(__dirname, ‚../dist/index.html‘),

// Paths

assetsRoot: path.resolve(__dirname, ‚../dist‘),

 

können einfach durch die folgenden ausgetauscht werden:

 

// Template for index.html

index: path.resolve(__dirname, ‚../target/dist/index.html‘),

// Paths

assetsRoot: path.resolve(__dirname, ‚../target/dist‘),

 

Schon landen die generierten HTML-, JavaScript- und CSS-Files im Verzeichnis frontend/target/dist und stehen so auch für den Zugriff durch das maven-resources-plugin in der pom.xml des Backend-Moduls [14] bereit.

Und los!

Das war schon alles. Im Grunde steht jetzt das gesamte Projekt-Set-up mit Spring Boot und Vue.js bereit. Ein einfaches Ausführen des Maven Builds im Hauptverzeichnis der Anwendung [3] per mvn clean install sollte jetzt fehlerfrei durchlaufen. Danach kann, wie von einer Spring-Boot-Anwendung gewohnt, alles mit diesem Befehl gestartet werden: java -jar backend/target/backend-0.0.1-SNAPSHOT.jar. Nun kann der Browser geöffnet und unter http://localhost:8088 die erste lauffähige Version der Anwendung betrachtet werden (Abb. 3).

Listing 3: REST Assured

Falls hierbei statt des Beispielprojekts ein neu erstelltes Projekt zum Einsatz kommt, muss eventuell noch der Port angepasst werden, sonst kann die Seite nicht geladen werden. Im Beispielprojekt wird über die Datei backend/src/main/resources/application.properties [19] der Port auf 8088 konfiguriert.

Der Entwicklungsprozess mit Spring Boot und Vue.js

Nachdem die ersten Hürden genommen sind und die Anwendung läuft, könnte sich ein Blick auf den Entwicklungsprozess mit Spring Boot und Vue.js lohnen. Natürlich funktioniert der Maven-Build-Prozess vorbildlich, und einem späteren Deployment sollte so nichts mehr im Wege stehen, aber trotzdem wäre der Entwicklungsprozess sehr zäh. Denn so müsste jedes Mal ein vollständiger Maven Build inklusive integriertem Frontend Build durchlaufen und danach auch noch die Spring-Boot-Anwendung hochfahren – und das bei jeder kleinen Codeänderung im Frontend.

Auch wenn diese Prozesse vollständig automatisiert sind, sollte das Ziel ein viel schnellerer Roundtrip während der Entwicklung sein. Glücklicherweise bietet webpack genau dafür den sogenannten webpack-dev-server an [20]. Die Beliebtheit dieses Tools ist entsprechend groß. Es sorgt dafür, dass ein Update der Frontend Sources sofort im Hintergrund durch den gesamten Frontend-Build-Prozess geschleust wird und direkt im Browser sichtbar wird. Das erstellte Projekt-Set-up bringt bereits vorkonfiguriert alles mit, was dazu nötig ist. Nur der folgende Befehl muss im Verzeichnis frontend ausgeführt werden: npm run dev. Dabei wird der webpack-dev-server vorkonfiguriert hochgefahren und der Browser geöffnet. Für diesen Schritt lohnt es sich, einmal im Beispielprojekt in den Frontend Sources [21] eine Kleinigkeit zu ändern und den Befehl selbst auszuführen.

Neben dem webpack-dev-server können natürlich noch weitere Tools das Entwicklerleben erleichtern. Besonders die Vue.js-Browsererweiterung [22] für die Entwicklertools in Chrome [23] oder Firefox [24] bietet sich hier an. Erstere erleichtert beispielsweise die Arbeit mit den Vue.js-Komponenten (Abb. 4).

Abb. 4: Vue.js-Browsererweiterung für die Entwicklertools

Um auch im Spring Boot Backend Codeänderungen im Entwicklungsprozess schneller nutzbar zu machen, lässt sich zusätzlich das Modul spring-boot-devtools [25] nutzen. Es muss dazu in der pom.xml des backend-Moduls [14] eingebunden werden:

 

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-devtools</artifactId>

<optional>true</optional>

</dependency>

 

Wird nun das Spring Boot Backend in der IDE gestartet, z. B. durch Klick auf Run der Main-Klasse SpringBootVuejsApplication.java [26], führen Codeänderungen zu einem Hot Reload des Backends. Mithilfe der hier vorgestellten Tools sollte die Entwicklung mit Spring Boot und Vue.js nun deutlich schneller von der Hand gehen.

Springs RESTful Web Services in Vue.js nutzen

Werden Spring Boot und Vue.js integriert, muss selbstverständlich auch der Datenaustausch zwischen beiden Frameworks stattfinden können. Dazu bieten sich RESTful Web Services an, die das Spring Boot Backend gewohnt schnell zur Verfügung stellt. Im Beispielprojekt auf GitHub wurde bereits eine Ressource /api/hello bereitgestellt. Die entsprechende Klasse BackendController.java [15] und die passende Testklasse BackendControllerTest.java [16] wurden angelegt. Doch wie können RESTful Web Services aus dem Vue.js Frontend aufgerufen werden? Ähnlich den Build-Tools gibt es unzählige Frameworks für diese Aufgabe. Ein aktuell beliebter Vertreter ist das Framework axios [27], das einen auf dem Promise-API basierenden HTTP-Client bereitstellt und nicht ohne Grund bereits einige GitHub-Stars einsammeln konnte. Um axios im Projekt verwenden zu können, genügt es, die entsprechende npm Dependency zu installieren. Das gelingt im frontend-Verzeichnis mit dem Befehl npm install axios –save. Nun kann axios innerhalb des Projekts zum Einsatz kommen (Listing 4). Die Nutzung ist dabei schnell erlernt. In einer beliebigen Vue.js-Komponente, wie der Service.vue [28] des Beispielprojekts, wird der in Listing 4 dargestellte Code innerhalb des <script>-Tags ergänzt.

import axios from 'axios'

data () {
  return {
    response: [],
    errors: []
  }
},
callRestService () {
  axios.get(`/api/hello`)
    .then(response => {
      this.response = response.data
    })
    .catch(e => {
      this.errors.push(e)
    })
}}

Dabei wird die Bibliothek axios per import-Anweisung verfügbar gemacht. Danach folgt die Definition von benötigten Datenstrukturen wie response und errors. In der Methode callRestService() findet dann der eigentliche Aufruf des RESTful Web Service des Spring Boot Backends statt. Dazu wird basierend auf impliziter Host- und Portangabe eine Ressource per /api/hello angesteuert. In der von axios bereitgestellten then()-Methode wird dann der Body der Response in das zuvor angelegte response-Array geschrieben, was natürlich asynchron passiert.

Der letzte Schritt zum Aufruf des RESTful Web Services ist der Aufruf der Methode callRestService() irgendwo im Code des Vue.js-Templates. In der Beispielanwendung ist das ein Button in der Datei Service.vue [28], der entsprechend benannt ist:

 

<button class=”Search__button” @click=“callRestService()“>CALL Spring Boot REST backend service</button>

<h3>{{ response }}</h3>

 

Der Einfachheit halber werden die Daten des HTTP-Response-Bodys direkt in ein <h3>-Tag geschrieben und dem Nutzer angezeigt. Bei laufender Beispielanwendung lässt sich das einfach per Aufruf des URL http://localhost:8088/#/callservice/ im Browser nachvollziehen. Der Klick auf den Button CALL Spring Boot REST backend service zeigt dann den in der Klasse BackendController.class [15] des Spring Boot Backends codierten String Hello from Spring Boot Backend! im Browser an (Abb. 5).

Abb. 5: Die Response aus dem Aufruf des RESTful Web Service

Die Same-Origin-Policy-Hölle vermeiden

Der Aufruf der RESTful Web Services des Spring Boot Backends funktioniert damit wunderbar, außer während des lokalen Entwicklungsprozesses, der mithilfe des webpack-dev-servers schnelles Feedback liefern soll. Denn der per npm run dev gestartete webpack-dev-server ist so konfiguriert, dass er das Frontend unter http://localhost:8080 bereitstellt. Das in der IDE gestartete Spring Boot Backend bietet die RESTful Web Services allerdings unter http://localhost:8088 an. Hier schlägt ein Kernkonzept der Sicherheitsarchitektur des Web zu: Die Same Origin Policy (SOP) [29] verhindert den Zugriff mit einer entsprechenden Fehlermeldung.

Natürlich gibt es auch hier Abhilfe: Das Cross-Origin Resource Sharing Protocol (CORS) [30] wurde genau für diesen Anwendungsfall entworfen und ermöglicht den Zugriff mit Ausnahmeregeln. Dazu kann der CORS-Support in axios [31] wie auch in Spring Boot [32] entsprechend konfiguriert werden. Doch das zieht einige Codeerweiterungen nach sich, die dann zusätzlich im produktiven Code landen, obwohl sie da gar nicht gebraucht werden. Glücklicherweise hilft auch hier wieder der webpack-dev-server mit seinem Proxying-Feature, die komplexe CORS-Konfiguration zu vermeiden. Dazu reicht es aus, einen Proxy für alle webpack-dev-server Requests zu konfigurieren. Das kann in der Datei frontend/config/index.js [18] im Feld dev.proxyTable umgesetzt werden (Listing 5).

dev: {
  ...
  proxyTable: {
    // proxy all webpack dev-server requests starting with /api to our Spring Boot backend (localhost:8088)
    '/api': {
      target: 'http://localhost:8088',
      changeOrigin: true
    }
  },

Durch diese Konfiguration nutzt der webpack-dev-server die http-proxy-middleware [33], um alle Frontend Requests mit einem vorangestellten /api von http://localhost:8080 auf http://localhost:8088 umzuleiten. Dabei wird auch der Origin HTTP Header entsprechend angepasst, sodass wirklich keine Codeänderung im Vue.js Frontend oder Spring Boot Backend notwendig wird. Da die RESTful Web Services des Spring Boot Backend [15] alle auf Klassenebene auf die Quellressource /api konfiguriert sind, gilt das für alle Aufrufe von Web Services dieser Klasse:

 

@RestController()

@RequestMapping(„/api“)

public class BackendController {

 

  @RequestMapping(path = „/hello“)

  public @ResponseBody String sayHello() {

    return „Hello from Spring Boot Backend!“;

  }

Integration in Continuous-Integration- und -Delivery-Pipelines

Im Verlauf dieses Artikels konnten viele Aspekte der Integration von Spring Boot mit Vue.js beleuchtet werden. Initial wurde aber noch die Frage gestellt, wie sich denn beides vernünftig in bestehende Continuous-Integration- und -Delivery-Pipelines integrieren lässt. Hierzu ist es natürlich nötig, überhaupt eine beispielhafte Continuous-Integration- und -Delivery-Pipeline zur Verfügung zu haben. Das sollte inzwischen kein großes Problem mehr darstellen und ist im Umfeld von Open-Source-Projekten auch recht schnell umgesetzt. Das Beispielprojekt auf GitHub [3] setzt dabei auf Travis CI [34] als Continuous-Integration-Plattform und auf Heroku [35] für das Deployment sowie die Bereitstellung entsprechender Infrastruktur. Die Beispielanwendung ist dementsprechend auch unter diesem URL erreichbar: https://spring-boot-vuejs.herokuapp.com. Die Konfiguration von Travis CI erfolgt über eine YAML-basierte Datei Namens .travis.yml [36], die überaus kompakt ausfällt:

 

language: java

jdk:

– oraclejdk8

script: mvn clean install jacoco:report coveralls:report

 

Hierbei wird bei jedem Git Push in den master-Branch des Projekt-Repositorys auf GitHub ein Maven Build ausgelöst, der dank frontend-maven-plugin gleich die gesamte Anwendung inklusive Vue.js Frontend und Spring Boot Backend baut und am Ende eine lauffähige jar-Datei bereitstellt. Im Anschluss werden noch Reports über die Testabdeckung bzw. Code Coverage mithilfe von JaCoCo [37] und Coveralls [38] erstellt.

Wie auch bei ähnlichen Pipelines üblich, wird ein Deployment auf Heroku nur dann ausgelöst, wenn alle diese Schritte erfolgreich durchlaufen wurden. Das lässt sich einfach mithilfe des Automatic-Deploys-Feature von Heroku umsetzen. Die Konfigurationsansicht bietet zusätzlich zu ihrer eigentlichen Funktion des Deployens der Beispielanwendung auch eine Checkbox namens Wait for CI to pass before deploy. Damit wird der Deploy nur ausgelöst, wenn alle in Travis CI konfigurierten Schritte grünes Licht geben (Abb. 6).

Abb. 6: Heroku deployt das vollständige Beispielprojekt nach jedem Git Push

Die einzige Voraussetzung dafür ist die Verbindung von Heroku mit dem GitHub Repository, die dann auch unter Deployment Method angezeigt wird. Und schon löst jeder Push mit vernünftigem Inhalt ein Deployment auf Heroku aus und beweist somit die Nutzbarkeit von Spring Boot und Vue.js in Continuous-Integration- und -Delivery-Pipelines mithilfe des vorliegenden Projekt-Set-ups.

Fazit

Wir haben gesehen, wie sich die beiden Sternchen am Java- bzw. JavaScript-Himmel optimal integrieren lassen. Dabei wird kein außergewöhnliches Know-how vorausgesetzt, und man findet selbst als JavaScript-Anfänger recht schnell in das Projekt-Set-up hinein, das einfach und klar strukturiert ist. Durch die Nutzung von Maven als bekanntem Build-Tool ist auch die Integration in bestehende Continuous-Integration- und -Delivery-Pipelines schnell erledigt.

Außerdem hat sich gezeigt, wie beispielsweise durch den webpack-dev-server ein schneller lokaler Entwicklungs-Roundtrip sichergestellt werden kann. Die entsprechende Konfiguration eines Proxies sorgt dafür, dass es beim Aufruf der RESTful Web Services des Spring Boot Backends wegen SOP-Verstößen nicht zu Frustration im Projekt kommt. Somit droht dem Entwicklerleben kein Ungemach mehr durch unklare Rahmenbedingungen, und man kann sich wieder hingebungsvoll der Umsetzung fachlicher Features im Projekt widmen.

Viel Spaß dabei!

Geschrieben von
Jonas Hecht
Jonas Hecht
Die Überzeugung, dass Softwarearchitektur und Hands-on-Entwicklung zusammengehören, führte Jonas zu codecentric. Er beschäftigt sich aktuell mit Spring Boot, Ansible, Docker und Infrastructure as Code. Er bloggt gerne, hält Vorträge und ist Organisator der Java User Group Thüringen.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu: