Start / Seminare / Quarkus-Training

Modul

Quarkus - Kernkonzepte: DI, Persistenz, Konfiguration, Tests

4 Kapitel in diesem Modul-Video · Laufzeit

Vertonung mit synthetischer Stimme · Inhalte redaktionell verantwortet · © 2026 HECKER CONSULTING, alle Rechte vorbehalten

Transkript

Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.

Quarkus – Kernkonzepte

0:00 Im ersten Seminar haben wir einen REST-Service gebaut, der Kurse ausliefert – ein hübscher Prototyp, aber noch keine echte Anwendung. Denn richtig ernst wird es erst mit vier Dingen: Wie organisiere ich meinen Code sauber? Wo bleiben die Daten, wenn ich neu starte? Wie stelle ich die App für verschiedene Umgebungen ein? Und woher weiß ich, dass sie noch funktioniert, wenn ich etwas ändere?

0:24 Genau darum geht es heute – Dependency Injection, Persistenz, Konfiguration und Tests. Am Ende des Tages ist aus dem Prototyp eine belastbare, getestete Anwendung geworden. Behalten Sie im Kopf: Diese vier Bausteine sind das Fundament jeder ernsthaften Software.

Kernkonzepte

0:40 Der rote Faden bleibt dieselbe Kurs-API – wir bauen sie Schritt für Schritt aus. Vier Blöcke: Erst bringen wir mit Dependency Injection Ordnung in die Struktur. Dann geben wir den Daten mit Hibernate und Panache ein dauerhaftes Zuhause. Anschließend machen wir die App über Konfiguration und Validierung fit für unterschiedliche Umgebungen.

1:00 Und zuletzt sichern wir alles mit automatisierten Tests ab. Jeder Block baut auf dem vorigen auf – am Abend läuft eine Anwendung, der Sie vertrauen können.

CDI & Dependency Injection mit ArC

1:10 Beginnen wir mit der Frage, wie unsere Bausteine überhaupt zueinanderfinden. Dependency Injection klingt sperrig, löst aber ein sehr menschliches Problem: Wer besorgt eigentlich, was eine Komponente zum Arbeiten braucht? Die Idee lässt sich mit einem Restaurant erklären. Sie kochen nicht selbst und gehen auch nicht einkaufen – Sie bestellen, und das fertige Gericht kommt an den Tisch.

1:33 Genauso sagt eine Komponente nur, was sie braucht, und ein Container liefert das passende Objekt fertig geliefert. Das ist Dependency Injection, und in der Java-Welt heißt der Standard dafür CDI. Das Besondere an Quarkus: Seine Umsetzung namens ArC erledigt diese Verdrahtung schon zur Build-Zeit. Klassische Frameworks durchsuchen dafür beim Start den ganzen Classpath.

1:55 ArC klärt vorab, wer mit wem verbunden wird – die fertige Sitzordnung liegt vor, bevor der erste Gast kommt. Warum diese Vorab-Auflösung ein echter Gewinn ist, zeigt sich an mehreren Stellen. Weil die Verdrahtung schon beim Bauen passiert, startet die Anwendung schneller, braucht kaum Reflection und ist damit native-tauglich.

2:14 Noch wichtiger für den Alltag: Fehlt eine Bean oder gibt es zwei mögliche Kandidaten, fällt das schon beim Build auf – nicht erst nachts um drei in der Produktion. Fehler wandern also nach vorn, wo sie billig sind. Und keine Sorge: Das vertraute CDI-Modell bleibt – `@Inject`, Scopes, Producer funktionieren wie gewohnt. Weniger Laufzeit-Magie bedeutet vor allem eines: Sie können nachvollziehen, warum sich Ihre App verhält, wie sie sich verhält.

2:41 Der Weg zur ersten Bean ist kurz und immer gleich. Zuerst geben Sie einer Klasse einen Scope – mit `@ApplicationScoped` sagen Sie: Von diesem Objekt genügt eine Instanz für die ganze App. Dann deklarieren Sie eine Abhängigkeit per `@Inject` – das ist die Bestellung ans Restaurant. Beim Scope lohnt kurzes Nachdenken: lebt das Objekt für die ganze Anwendung oder nur für eine einzelne Anfrage?

3:04 Für Fremdtypen, die Sie nicht selbst annotieren können, gibt es Producer-Methoden als Brücke. Und das Beste: Im Dev Mode meldet der Build sofort, wenn eine Bean fehlt – Sie merken es in Sekunden, nicht erst im Betrieb. Worauf es hier ankommt, ist nicht die Syntax, sondern ein Muster, das sich durch die ganze Anwendung zieht. Die Klasse trägt ihren Scope als Markierung – eine Instanz für die App.

3:28 Und statt sich ihr Repository selbst zu beschaffen, sagt sie mit einer einzigen Injection-Markierung nur: „Ich brauche ein KursRepository." Woher es kommt, wie es erzeugt wird – das ist nicht ihre Sorge. Der Service arbeitet einfach damit, ruft `listAll()` auf und gibt die Kurse zurück. Genau diese Trennung ist der Gewinn: Jede Komponente kümmert sich um ihre Aufgabe, nicht um die Beschaffung ihrer Werkzeuge. Das macht Code lesbar, austauschbar und testbar.

3:56 Jetzt sind Sie dran, und die Aufgabe hat einen praktischen Kern: Verlagern Sie die Fachlogik aus der REST-Resource in eine eigene CDI-Bean, einen KursService, und verdrahten Sie ihn sauber per `@Inject`. Erfüllt ist das Ziel, wenn die Resource den injizierten Service nutzt und die App ohne DI-Fehler startet. Damit trennen Sie zum ersten Mal „HTTP annehmen" von „Fachlogik erledigen" – ein Prinzip, das jede größere Anwendung trägt.

4:21 Wer schneller fertig ist, nimmt den Stretch: Loggen Sie beim Start ein `@Observes StartupEvent` und beobachten Sie, wie sich Ihre Bean in den Lebenszyklus der App einklinkt. Drei Fallen begegnen einem am Anfang immer wieder. Die erste ist der falsche Scope: Wer etwas Anfrage-bezogenes in eine anwendungsweite Bean packt, teilt versehentlich Zustand zwischen allen Nutzern – ein tückischer Fehler, weil er erst unter Last auffällt.

4:47 Die zweite ist harmloser, weil sie früh knallt: Injizieren Sie eine Bean, die es gar nicht gibt, bricht schon der Build mit „unsatisfied dependency" ab – ärgerlich, aber ehrlich. Und die dritte ist eine Reihenfolge-Empfehlung: Lassen Sie die Finger von Interceptors, solange Scopes und `@Inject` nicht sitzen. Erst das Fundament, dann die Kür – sonst debuggen Sie zwei neue Konzepte gleichzeitig.

5:10 Zwei Werkzeuge lohnen einen kurzen Blick, auch wenn wir sie heute nicht vertiefen. Das erste ist der Lebenszyklus: Mit `@Observes StartupEvent` und `ShutdownEvent` klinken Sie sich in Start und Stopp der App ein – ideal, um beim Hochfahren etwas vorzubereiten oder beim Beenden sauber aufzuräumen. Das zweite sind Interceptors: Sie bündeln Querschnittsthemen wie Logging oder Security rund um Ihre Methoden, ohne dass Sie diesen Code überall verstreuen.

5:35 Behalten Sie aber im Kopf: Build-Time-DI ist eben nicht klassisches CDI mit dynamischem Scannen zur Laufzeit. Und die Faustregel bleibt: erst Scopes und `@Inject` sicher beherrschen, dann Interceptors.

Persistenz mit Hibernate & Panache

5:47 Kommen wir zum Herzstück des Tages – und mit 120 Minuten zum längsten Block: der Persistenz. Denn eine Anwendung, deren Daten beim Neustart verschwinden, ist bestenfalls ein Demo. Persistenz heißt schlicht: Daten überleben den Neustart. In der Java-Welt übersetzt Hibernate seit Jahren zwischen Objekten und Datenbanktabellen – ein bewährter, aber gesprächiger Vermittler, der viel Schreibarbeit verlangt.

6:12 Genau hier setzt Panache an: Es sitzt auf Hibernate 7.2 auf und nimmt Ihnen den größten Teil des immer gleichen Codes ab. Stellen Sie sich Panache als Assistenten vor, der die Standardbriefe schon vorformuliert hat – Sie füllen nur noch das Besondere aus. Panache bietet dabei zwei Stile: Active Record, bei dem die Datenklasse ihre Abfragen gleich selbst mitbringt, oder ein typisiertes Repository, das den Datenzugriff sauber in eine eigene Klasse legt.

6:39 Der Nutzen zeigt sich in gesparter Tipparbeit und mehr Klarheit. Active Record ist herrlich kompakt: Die Abfragen stehen direkt auf der Entity, ideal für einfaches Anlegen, Lesen, Ändern, Löschen. Das Repository-Pattern trennt den Datenzugriff von den Daten selbst – das kostet eine Klasse mehr, macht die Sache aber entkoppelt und gut testbar.

6:59 Für beides gilt: Ausdrucksstarke Abfragen, Blättern durch große Ergebnismengen und Sortierung gelingen mit erstaunlich wenig Code. Und ein Komfort, der im Alltag Gold wert ist: Die Dev Services starten Ihnen automatisch eine echte PostgreSQL im Container. Kein manuelles Datenbank-Setup, keine Ausreden – Sie entwickeln sofort gegen die echte Sache.

7:21 Der Weg zur persistenten Kurs-API führt über fünf Stationen. Zuerst holen Sie die passenden Extensions ins Projekt – Panache für die Persistenz, den PostgreSQL-Treiber für die Datenbank. Dann modellieren Sie Ihre Entity: eine schlichte Klasse mit `@Entity` und den Feldern, die ein Kurs eben hat. Das Repository entsteht fast von selbst, indem es `PanacheRepository` erweitert – Sie erben die Standard-Operationen.

7:45 Wichtig sind die Schreibpfade: Sie gehören mit `@Transactional` abgesichert, damit Änderungen wirklich ankommen. Und ein Rat für später: Statt die Datenbank bei jedem Start neu zu erzeugen, verwalten Sie das Schema mit Flyway-Migrationen – kontrolliert und nachvollziehbar. Achten Sie hier auf ein Verhältnis, das fast schon verblüfft: wie wenig Code für wie viel Funktion.

8:08 Die Entity ist eine schlichte Klasse mit ein paar markierten Feldern – die Id-Markierung sagt „das ist der Schlüssel, vergib ihn automatisch". Und das Repository? Eine leere Klasse, die nur `PanacheRepository` für den Typ Kurs erweitert – und trotzdem sofort Speichern, Suchen, Auflisten, Löschen beherrscht. Diese Methoden erben Sie geschenkt. Das ist die Idee hinter Panache: Den immer gleichen Datenzugriffs-Code, den Sie sonst in jedem Projekt neu schreiben, gibt es bereits fertig.

8:37 Sie fügen nur hinzu, was an Ihrer Domäne wirklich besonders ist. Die eigentliche Botschaft dieser Tabelle ist keine Rangliste, sondern eine Abwägung – keiner der beiden Stile ist per se besser. Es geht um eine Kopplungsfrage. Beim Active Record wohnen die Abfragen direkt auf der Entity: eng verzahnt, sehr kompakt, wunderbar für einfache CRUD-Fälle – aber eben nur mäßig testbar, weil Daten und Zugriff verschmelzen.

9:02 Das Repository legt die Abfragen in eine eigene Klasse: lose gekoppelt, gut zu mocken, damit hervorragend testbar – der Preis ist eine Klasse mehr. Die Faustregel dahinter: Für kleine, überschaubare Dinge darf es der kompakte Active Record sein; sobald die Domäne wächst und Tests wichtiger werden, gewinnt das Repository.

9:21 Das ist die zentrale Aufgabe des Tages: Geben Sie der Kurs-API aus dem ersten Seminar ein echtes Gedächtnis. Binden Sie sie an eine Datenbank an – mit Entity, Repository und Transaktion. Der Erfolg ist wunderbar greifbar: Legen Sie einen Kurs an, starten Sie die App neu – und der Kurs ist noch da, ausgeliefert frisch aus PostgreSQL.

9:41 Genau dieser Moment, in dem Daten einen Neustart überleben, macht aus einem Prototyp eine Anwendung. Nehmen Sie sich Zeit dafür. Und wer mag, nimmt den Stretch: Ergänzen Sie Paging mit Panaches `page()`, damit auch hundert Kurse in verdaulichen Häppchen geliefert werden. Drei Klassiker der Persistenz, die fast jeder einmal erlebt. Der erste: Schreiben ohne `@Transactional`.

10:04 Ohne die Transaktions-Klammer landet Ihre Änderung entweder gar nicht in der Datenbank oder quittiert mit einer Exception – ein häufiges „Warum wird nichts gespeichert?". Der zweite ist gefährlicher: `drop-and-create` mag in der Entwicklung bequem sein, aber in der Produktion löscht es bei jedem Start Ihre echten Daten. Dafür gibt es Flyway.

10:24 Und der dritte ist tückisch: Greifen Sie außerhalb der Transaktion auf nachgeladene Daten zu, schlägt die berüchtigte `LazyInitializationException` zu. Merken Sie sich: Was die Datenbank betrifft, gehört sauber in die Transaktion hinein. Ein kurzer Blick über den Tellerrand, denn hier bewegt sich gerade etwas. Jakarta Data ist eine standardisierte, typsichere Alternative zum Repository.

10:48 Die Idee ähnelt Panache: Sie beschreiben Interfaces, und die Query-Methoden werden aus den Namen abgeleitet – kein handgeschriebener Boilerplate. Der entscheidende Unterschied liegt aber in der Herkunft: Jakarta Data ist ein herstellerunabhängiger Standard, nicht Quarkus-spezifisch wie Panache. Das macht es besonders für neue Projekte interessant, die Wert auf Portabilität legen – auf die Freiheit, später den Unterbau wechseln zu können, ohne alles neu zu schreiben.

11:15 Für heute bleibt es ein Ausblick, aber einer, den man im Auge behalten sollte.

Konfiguration & Validierung

11:20 Unsere Anwendung speichert jetzt Daten – aber sie ist noch starr. Im dritten Block machen wir sie beweglich: konfigurierbar für verschiedene Umgebungen und robust gegen falsche Eingaben. Zwei Themen, die zusammengehören, weil beide von außen kommende Werte betreffen. Konfiguration heißt: Ihre App verhält sich anders, je nachdem wo sie läuft – ohne dass Sie den Code anfassen.

11:43 Stellen Sie sich die Schalter und Regler an einem Gerät vor: Dasselbe Gerät, andere Einstellung. In Quarkus liest SmallRye Config diese Werte aus Properties-Dateien, aus Umgebungsvariablen und aus Profilen. Das zweite Thema, die Validierung, ist der Türsteher: Bean Validation prüft eingehende Daten schon am Endpunkt – deklarativ, mit kleinen Markierungen am Feld.

12:04 Zusammen sorgen beide dafür, dass nur passende Einstellungen und saubere Eingaben überhaupt ins Innere Ihrer Anwendung gelangen. Warum lohnt sich dieser Aufwand? Weil dieselbe Anwendung durch viele Umgebungen wandert – Entwicklung, Test, Produktion – und in jeder etwas anders eingestellt sein muss. Profile wie `%dev`, `%test` und `%prod` trennen das sauber, ganz ohne Code-Änderung.

12:28 Dass Umgebungsvariablen die Properties überschreiben, ist kein Zufall, sondern gute Praxis: Es macht Ihre App 12-Factor-tauglich, also fit für die Cloud. Mit `@ConfigMapping` bündeln Sie zusammengehörige Einstellungen typsicher in ein Interface – kein Herumraten mit losen Strings. Und die Validierung hält ungültige Eingaben früh vom System fern. Das ist gelebte Vorsicht: Fehler abfangen, bevor sie sich tief in der Anwendung einnisten.

12:56 Der Weg gliedert sich in zwei Stränge, die ineinandergreifen. Für die Konfiguration schreiben Sie Ihre Werte in die `application.properties` und markieren umgebungsspezifische mit einem Profil-Präfix wie `%dev.`. Gehören mehrere Schlüssel zusammen, bündeln Sie sie in einem `@ConfigMapping`-Interface und nutzen es bequem per `@Inject` – typsicher statt magischer Strings.

13:18 Für die Validierung versehen Sie Ihre DTO-Felder mit Constraints, etwa „darf nicht leer sein" oder „mindestens eins". Der entscheidende Handgriff kommt zum Schluss: Ein `@Valid` am REST-Parameter erzwingt die Prüfung überhaupt erst. Ohne diesen kleinen Schalter bleiben all Ihre schönen Regeln wirkungslos – ein Punkt, den viele übersehen.

13:39 Diese Folie zeigt zwei Ideen nebeneinander, beide wunderbar deklarativ. Oben das Konfig-Interface: Sie beschreiben nur, welche Werte es unter einem Präfix gibt – etwa die maximale Platzzahl eines Kurses. Woher der Wert kommt, aus Datei oder Umgebung, bleibt außen vor; Sie greifen ihn typsicher als Methode ab. Unten das Eingabe-Objekt, ein schlanker Record, dessen Felder ihre Regeln gleich mittragen: Der Titel darf nicht leer sein, die Plätze müssen mindestens eins betragen.

14:08 Das Schöne daran: Diese Regeln stehen als Markierung direkt am Feld, nicht in irgendeiner Prüf-Methode weit weg. Man liest die Bedingungen dort, wo die Daten definiert werden. Ihre Aufgabe verbindet beide Themen praktisch. Machen Sie das Verhalten Ihrer App über Profile konfigurierbar und sichern Sie die Eingaben per Bean Validation ab.

14:28 Der Erfolg ist doppelt messbar: Ein ungültiger POST wird sauber mit HTTP 400 abgewiesen – der Türsteher funktioniert. Und ein Wert unterscheidet sich zwischen dem `%dev`- und dem `%prod`-Profil – dieselbe App, unterschiedlich eingestellt. Damit haben Sie beide Mechanismen erlebt, die jede Cloud-Anwendung braucht. Wer noch Luft hat, nimmt den Stretch: Überschreiben Sie einen Wert per Umgebungsvariable und sehen Sie, wie die Einstellung von außen die Datei aussticht – genau so, wie es in einem Container später passiert.

14:59 Drei kleine Ursachen, große Wirkung. Der Klassiker schlechthin: `@Valid` vergessen. Sie haben alle Regeln sauber ans DTO geschrieben – aber ohne diesen einen Schalter am Parameter greift keine einzige davon, und ungültige Daten rutschen durch. Der zweite ist ein Tippfehler mit Folgen: Schreiben Sie `%production` statt `%prod`, wird Ihr Wert stillschweigend ignoriert – kein Fehler, nur falsches Verhalten, das schwer zu finden ist.

15:25 Und der dritte ist ein Sicherheitsthema, das man nie schleifen lassen darf: Secrets – Passwörter, Schlüssel – gehören nicht in die `application.properties`, sondern in Umgebungsvariablen. Sicherheit geht vor Bequemlichkeit.

Testing

15:39 Zum Abschluss des Tages die vielleicht wichtigste Zutat für Vertrauen in Software: Tests. Denn erst automatisierte Tests geben Ihnen die Freiheit, morgen etwas zu ändern, ohne heute Angst haben zu müssen. Testen bedeutet in Quarkus etwas Handfestes: Mit `@QuarkusTest` startet für den Test die echte Anwendung – nicht eine nachgebaute Attrappe. Das ist ein wichtiger Unterschied.

16:02 Sie prüfen nicht, ob Ihre Mocks sich richtig verhalten, sondern ob die Anwendung es tut. RestAssured ist dabei Ihr Werkzeug, um HTTP-Endpunkte anzusprechen und die Antworten zu prüfen – lesbar, fast wie ein Satz. Und weil die Dev Services auch im Test greifen, läuft Ihr Test gegen eine echte Datenbank im Container, per Testcontainers – nicht gegen einen vereinfachten In-Memory-Ersatz.

16:26 Kurz: Sie testen die Realität, nicht eine höfliche Version davon. Das macht die Ergebnisse aussagekräftig. Der Wert dieses Ansatzes liegt in seiner Ehrlichkeit. Weil die Tests gegen die echte App laufen und nicht gegen Framework-Mocks, sagt ein grüner Test wirklich etwas aus – er testet, was Ihre Nutzer erleben. RestAssured beschreibt die HTTP-Erwartungen in einem Dreiklang aus „gegeben, wenn, dann", der sich fast wie natürliche Sprache liest – auch für Kollegen, die den Code später pflegen.

16:55 Die Dev Services liefern eine echte Datenbank statt eines vereinfachten Ersatzes, sodass keine Überraschung im Betrieb wartet. Und das Continuous Testing schließt den Kreis: Bei jeder Änderung laufen sofort genau die betroffenen Tests mit. Sie erfahren in Sekunden, ob Sie etwas kaputtgemacht haben. Der Weg zum ersten Test ist angenehm kurz. Sie markieren eine Testklasse mit `@QuarkusTest` – damit fährt für den Test die echte Anwendung hoch.

17:21 Dann formulieren Sie mit RestAssured einen Aufruf im vertrauten Muster „gegeben, wenn, dann": Sie rufen einen Endpunkt auf und prüfen anschließend Status und JSON der Antwort. Wollen Sie noch näher an die Realität, testet ein `@QuarkusIntegrationTest` gegen das fertig gebaute Artefakt – die App genau so, wie sie später ausgeliefert wird.

17:41 Und der wichtigste Rat für den Alltag: Lassen Sie das Continuous Testing im Dev Mode aktiv, angeschaltet mit der Taste `r`. Dann arbeiten Ihre Tests einfach ständig mit. Achten Sie hier weniger auf die Klammern als auf die Lesbarkeit – das ist der eigentliche Clou. Der Test liest sich fast wie ein Satz auf Deutsch: gegeben eine bestimmte Ausgangslage, wenn ich den Kurs-Endpunkt aufrufe, dann erwarte ich den Status 200.

18:06 Diese „gegeben-wenn-dann"-Struktur ist kein Zufall, sondern Absicht: Ein Test soll auf einen Blick verraten, was er prüft – auch dem Kollegen, der ihn in einem Jahr zum ersten Mal liest. Dahinter läuft die vollständige Anwendung, angestoßen durch die Test-Markierung. Sie prüfen also nicht ein Stück Logik in Isolation, sondern das echte Zusammenspiel bis zur HTTP-Antwort. Genau das gibt einem grünen Test sein Gewicht.

18:31 Zum krönenden Abschluss sichern Sie Ihre Kurs-API ab. Ihr Ziel: einen REST-Endpunkt automatisiert gegen die laufende App testen. Erfüllt ist die Aufgabe, wenn zwei Fälle grün abgedeckt sind – der erfolgreiche Abruf der Kursliste und ein ungültiger POST, der korrekt mit 400 abgewiesen wird – und dabei das Continuous Testing mitläuft.

18:51 Damit haben Sie den Kreis geschlossen: eine Anwendung, die Daten speichert, sich konfigurieren lässt und deren Verhalten durch Tests abgesichert ist. Wer noch mag, nimmt den Stretch: Ergänzen Sie einen Integrationstest mit `@QuarkusIntegrationTest`, der gegen das gebaute Artefakt prüft – die App so, wie sie wirklich ausgeliefert wird.

19:11 Drei Dinge, die beim Testen gern für Verwirrung sorgen. Erstens der feine Unterschied zwischen den Testarten: `@QuarkusIntegrationTest` prüft das fertige Artefakt von außen – und hat deshalb bewusst keinen Zugriff auf die Beans im Inneren. Wer das verwechselt, wundert sich über Injection-Fehler im Test. Zweitens die vertraute Docker-Falle: Läuft kein Docker, starten Dev Services und Testcontainers nicht, und Ihre Datenbank-Tests bleiben stehen.

19:36 Und drittens ein Problem, das schleichend kommt: Wenn Testdaten nicht sauber isoliert sind, beeinflussen sich Tests gegenseitig – dann ist mal alles grün, mal nicht, ohne dass Sie etwas geändert hätten. Sorgen Sie für saubere, unabhängige Ausgangslagen.

Danke & nächste Schritte

19:51 Damit schließt sich der Bogen des Tages: Aus dem schlichten REST-Service ist eine echte Anwendung geworden – strukturiert durch Dependency Injection, dauerhaft durch Persistenz, flexibel durch Konfiguration und abgesichert durch Tests. Das sind die vier Säulen, auf denen jede ernsthafte Software steht. Alle Materialien finden Sie zum Nacharbeiten in der Freigabe.

20:13 Und die Reise geht weiter: Das nächste Seminar widmet sich dem Reaktiven, Microservices und dem Deployment – dem Schritt von der einzelnen Anwendung zum verteilten System in der Cloud. Bei Fragen erreichen Sie uns unter info@HCO.de. Herzlichen Dank für Ihre Aufmerksamkeit und das Mitmachen.

Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →