{"id":27563,"date":"2025-02-28T22:06:02","date_gmt":"2025-02-28T21:06:02","guid":{"rendered":"https:\/\/blog.mi.hdm-stuttgart.de\/?p=27563"},"modified":"2025-02-28T22:06:04","modified_gmt":"2025-02-28T21:06:04","slug":"die-technische-entwicklung-einer-open-source-losung-zur-bildoptimierung","status":"publish","type":"post","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/02\/28\/die-technische-entwicklung-einer-open-source-losung-zur-bildoptimierung\/","title":{"rendered":"Die technische Entwicklung einer Open-Source-L\u00f6sung zur Bildoptimierung"},"content":{"rendered":"\n<p>Im Rahmen meines Systems Engineering Projektes habe ich die <a href=\"https:\/\/github.com\/shutolabs\/api\" target=\"_blank\" rel=\"noopener\" title=\"\">shuto-api<\/a> entwickelt \u2013 eine in Go geschriebene Open-Source-Bildoptimierungsl\u00f6sung. Mein Ziel war es, eine flexible, self-hostable und erweiterbare API zu erstellen, welche ohne viele Probleme in bereits bestehende Systeme integriert werden kann.<\/p>\n\n\n\n<p>Der Service erm\u00f6glicht es, Bilder zu komprimieren, zu skalieren sowie weiter zu bearbeiten. Diese sind h\u00e4ufig haupts\u00e4chlich relevant, um ihre Ladezeiten zu verbessern. Deshalb werden solche Services sehr h\u00e4ufig f\u00fcr Websites\/ Webanwendungen, aber auch Apps und Content-Delivery-Plattformen verwendet, um die Performance zu steigern, Bandbreite zu reduzieren und eine bessere User-Experience zu gew\u00e4hrleisten. <\/p>\n\n\n\n<p>Neben den Features zur Optimierung der Bilder wollte ich sicherstellen, dass so gut wie m\u00f6glich jeder diesen Service nutzen kann. Deshalb war es mir auch wichtig, so viele Storage-L\u00f6sungen (also Orte, wo die Bilder, welche optimiert werden sollen, gespeichert sind) zu unterst\u00fctzen, damit sie von vielen auch in schon bestehende Systeme mit Storage-L\u00f6sungen eingebunden werden k\u00f6nnen.<\/p>\n\n\n\n<p>Meine Motivation f\u00fcr dieses Projekt war es, eine einfach zu verwendende sowie leistungsstarke L\u00f6sung zu entwickeln, mit der Bilder effizient verarbeitet werden k\u00f6nnen. Der Fokus lag dabei,  bew\u00e4hrte Standards und Prinzipien der Softwareentwicklung anzuwenden, um eine gut funktionierende, skalierbare Architektur zu schaffen, welche langfristig angepasst und weiterentwickelt werden kann. <\/p>\n\n\n\n<p>Wichtig dabei waren unter anderem Punkte wie die Automatisierung von Prozessen bei der Entwicklung oder Bereitstellung durch den Einsatz von CI\/CD-Pipelines, sowie eine automatisierte API-Dokumentation und eine gut dokumentierte Codebasis. Zudem wurden f\u00fcr eine bessere Integration in JavaScript und React Projekte noch zwei NPM-Pakete entwickelt, welche daf\u00fcr gedacht sind, die Developer-Experience auf der Nutzerseite zu verbessern.<\/p>\n\n\n\n<p>Dieser Blogpost soll technische Herausforderungen, getroffene Designentscheidungen sowie wichtige Erkenntnisse aus der Entwicklung dieses f\u00fcr Open-Source gedachten, anpassbaren Services vorstellen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Entwickeln f\u00fcr Open-Source<\/h2>\n\n\n\n<p>Einer der zentralen Aspekte war, das Ganze so anzugehen, dass daraus potenziell ein Open-Source-Projekt entstehen kann. Wichtige Punkte f\u00fcr Open-Source sind unter anderem eine klare und dokumentierte Architektur. Ich habe von Anfang an versucht, die Codebasis modular aufzubauen und zu schauen, dass sie einfach erweitert werden kann. Dabei habe ich zum Beispiel probiert, so gut wie m\u00f6glich auf Standards auch im Umfeld von Go zu setzen. Ich habe daf\u00fcr zum Beispiel entschieden, keine third-party router in Go wie <a href=\"https:\/\/github.com\/gorilla\/mux\" target=\"_blank\" rel=\"noopener\" title=\"\">mux<\/a> oder <a href=\"https:\/\/github.com\/go-chi\/chi\" target=\"_blank\" rel=\"noopener\" title=\"\">chi<\/a> zu verwenden, sondern auf den Go-Standard (net\/http) zu setzen.<\/p>\n\n\n\n<p>F\u00fcr einen transparenten Entwicklungsprozess wurde GitHub als zentrale Plattform gew\u00e4hlt, welche dann f\u00fcr Versionskontrolle, \u00f6ffentliche Dokumentation, die M\u00f6glichkeit f\u00fcr Pull Requests von anderen Entwicklern sowie Automatisierungen mittels der GitHub eigenen CI\/CD-Pipelines genutzt wurde. Die Integration der CI\/CD-Pipelines, speziell zu Beginn des Projektes, erm\u00f6glichte es w\u00e4hrend der Entwicklung dauerhaft automatisierte Tests durchzuf\u00fchren sowie die komplette Anwendung zu bauen. Dies ist im Sinne von Open-Source vorwiegend f\u00fcr externe \u00c4nderungen wichtig, um die Stabilit\u00e4t der Software sicherzustellen sowie es f\u00fcr neue Contributors zu erleichtern, sich sicherer zu f\u00fchlen. <\/p>\n\n\n\n<p>Ein weiterer eingesetzter Standard ist <a href=\"https:\/\/semver.org\/\" target=\"_blank\" rel=\"noopener\" title=\"Semantic Versioning,\">Semantic Versioning,<\/a> welches eine klare Versionierung der Software erm\u00f6glicht. Dadurch sind \u00c4nderungen und neue Features einfach nachvollziehbar und potenzielle Probleme durch Breaking Changes k\u00f6nnen klar kommuniziert werden. In diesem Falle geschieht die Versionierung \u00fcber Git-Commits, durch klar definierte Commit-Messages wird strukturiert festgehalten, um was f\u00fcr eine Art \u00c4nderung (Feature, Fix oder Breaking Change) es sich handelt. Diese wird durch <a href=\"https:\/\/github.com\/semantic-release\/semantic-release\" target=\"_blank\" rel=\"noopener\" title=\"\">Semantic-Release<\/a> erm\u00f6glicht, welches den Release steuert. Der Release wird \u00fcber eine CI-Pipeline ausgef\u00fchrt, Semantic-Release schaut sich die Commits seit dem letzten Release an und bestimmt dadurch die n\u00e4chste Version. Sind zum Beispiel seit dem letzten Release nur Commits mit &#8220;fix(&#8230;)&#8221; get\u00e4tigt worden, w\u00fcrde die Version von 1.4.3 auf 1.4.4 erh\u00f6ht werden. Beinhaltet eine Commit-Nachricht den Inhalt BREAKING CHANGE wird von 1.4.3 auf 2.0.0 erh\u00f6ht. Neben der Bestimmung der Versionsnummer k\u00fcmmert sich Semantic-Release auch noch zum Beispiel um das korrekte Setzen eines Git-Tags sowie die automatische Generierung von Release Notes. Die Release Notes k\u00f6nnen dann etwa direkt in GitHub hinterlegt werden. <a href=\"https:\/\/github.com\/shutolabs\/api\/releases\" title=\"\">Hier<\/a> k\u00f6nnen zum Beispiel alle Releases inkl. Release Notes der shuto-api eingesehen werden. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-17.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"446\" data-attachment-id=\"27585\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/02\/28\/die-technische-entwicklung-einer-open-source-losung-zur-bildoptimierung\/image-102\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-17.png\" data-orig-size=\"1156,503\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-17-1024x446.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-17-1024x446.png\" alt=\"\" class=\"wp-image-27585\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-17-1024x446.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-17-300x131.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-17-768x334.png 768w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-17.png 1156w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Ein letzter kleiner Fokus war es direkt im <a href=\"https:\/\/github.com\/shutolabs\/api\/blob\/main\/README.md\" title=\"\">GitHub-Readme<\/a> sicherzustellen, dass die wichtigsten Informationen, um zum Projekt beizusteuern oder es selbst zu nutzen, direkt einsehbar und verst\u00e4ndlich sind. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Eine flexible und erweiterbare API bauen<\/h2>\n\n\n\n<p>Ein Fokus war ja, einen flexiblen und erweiterbaren Service zu schaffen, welcher sich einfach in verschiedene Umgebungen integrieren l\u00e4sst. Ziel war es also, bew\u00e4hrte API-Prinzipien zu gew\u00e4hrleisten, um eine konsistente und verst\u00e4ndliche Schnittstelle bereitzustellen. Dies stellte sich an vielen Punkten als kompliziert und herausfordernd dar. Eine erste Version, API Entwurf, war meist schnell gefunden, beim Testen oder eigenen Ausprobieren fallen dann doch immer wieder Ungereimtheiten auf, welche f\u00fcr andere Benutzer, welche nicht den gleichen Kenntnisstand haben, unklar sein k\u00f6nnten. Ein zentraler Punkt des Services ist es, einfach \u00fcber <em>Query Parameter<\/em> die gew\u00fcnschten Komprimierungen, Gr\u00f6\u00dfen etc. des Bildes anzupassen. Es ist also m\u00f6glich, wenn das Bild mit einer Breite und H\u00f6he von 500px gew\u00fcnscht ist dieses folgenderma\u00dfen anzufragen <code class=\"\" data-line=\"\">\/v2\/images\/example-image.jpeg?w=500&amp;h=500<\/code> Das Ausw\u00e4hlen und Festlegen der Bezeichnungen und Funktionen der Query Parameter schien auf den ersten Blick leicht, ich ertappte mich aber selbst bei eigenen Testen zwischen <code class=\"\" data-line=\"\">width<\/code> und <code class=\"\" data-line=\"\">w<\/code> zu wechseln sowie die genaue Bezeichnung anderer Parameter zu vergessen. Schlie\u00dflich legte ich mich fest, mich an der API von imgix (<a href=\"https:\/\/docs.imgix.com\/en-US\/apis\/rendering\/size\/image-width\" title=\"\">API Dokumentation)<\/a>, einer weitverbreiteten \u00e4hnlichen L\u00f6sung (wird zum Beispiel von <a href=\"https:\/\/unsplash.com\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Unsplash<\/a> verwendet) zu orientieren. Generell nahm ich w\u00e4hrend der Entwicklung und auch bei sp\u00e4teren Versionen immer wieder \u00c4nderungen an Bezeichnungen und API-Strukturen vor. Diese Entscheidungen traf ich stets mit dem Gedanken im Hinterkopf, dass es sich um ein Open-Source-Projekt handelt und andere es m\u00f6glichst einfach nutzen und verstehen sollten.<\/p>\n\n\n\n<p>Ein anderer Fokus bestand in der modularen Auswahlm\u00f6glichkeit der Storage-L\u00f6sung, um damit m\u00f6glichst viele Speicheranbieter wie AWS S3, Google Cloud Storage, Nextcloud, aber auch FTP und viele weitere zu erm\u00f6glichen. Dies wurde nach viel trial-and-error und verschiedenen Ans\u00e4tzen schlie\u00dflich durch die Integration eines weiteren Open-Source-Tools <a href=\"https:\/\/rclone.org\/\" target=\"_blank\" rel=\"noopener\" title=\"\">rclone<\/a> gel\u00f6st. Dieses erm\u00f6glicht es, \u00fcber 70 verschiedene Storage-L\u00f6sungen zu integrieren und f\u00fcr den Service zu nutzen, ohne dass individuelle Implementierungen f\u00fcr jeden Anbieter notwendig waren und unterst\u00fctzt zudem den Open-Source-Charakter.<\/p>\n\n\n\n<p>Ein weiterer wichtiger Aspekt bei der Entwicklung des Services war die Sicherheit der Bilder. Eine Implementierung, bei der alle Bilder ohne Zugriffskontrollen verf\u00fcgbar waren, stellte ein erhebliches Sicherheitsrisiko dar, besonders f\u00fcr sensible oder private Inhalte. Da die Pfade zu den Bildern Teil der URL sind, bestand die Gefahr, dass Unbefugte systematisch nach vorhandenen Bildern scannen k\u00f6nnten. Gleichzeitig wollte ich keine komplexen Authentifizierungsmechanismen wie User-Sessions erzwingen, da dies die einfache Einbindung von Bildern, beispielsweise in Nachrichtenartikeln, erschweren w\u00fcrde. Nach Abw\u00e4gung verschiedener Sicherheitsoptionen \u2013 Client-seitige Authentifizierung (mit Sessions), API-Keys oder pre-signed URLs \u2013 entschied ich mich f\u00fcr einen flexiblen Ansatz mit optionalen pre-signed URLs. Diese L\u00f6sung erm\u00f6glicht es, URLs mit allen Parametern kryptografisch zu signieren, wodurch das systematische Scannen nach Bildpfaden verhindert wird. Zus\u00e4tzlich k\u00f6nnen die Signaturen mit einem Zeitstempel versehen werden, um den Zugriff zeitlich zu begrenzen, oder ohne Zeitstempel f\u00fcr dauerhafte Verf\u00fcgbarkeit konfiguriert werden. Diese Implementierung bietet einen guten Kompromiss zwischen Sicherheit und Benutzerfreundlichkeit, w\u00e4hrend sie gleichzeitig die Flexibilit\u00e4t bewahrt, die f\u00fcr verschiedene Anwendungsf\u00e4lle erforderlich ist.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Technische Herausforderungen meistern<\/h2>\n\n\n\n<p>Bei der Entwicklung stie\u00df ich auf verschiedene technische Herausforderungen, die kreative L\u00f6sungsans\u00e4tze erforderten. Das \u00dcberwinden dieser H\u00fcrden war nicht nur f\u00fcr die Funktionalit\u00e4t der API entscheidend, sondern auch eine wertvolle Lernerfahrung.<\/p>\n\n\n\n<p>Eine der gr\u00f6\u00dften Herausforderungen war die Latenz zwischen dem Service und den verschiedenen Storage-L\u00f6sungen, insbesondere beim Auflisten von Bildern. Die Anfragen mittels rclone an die Storage-L\u00f6sungen verursachten sp\u00fcrbare Verz\u00f6gerungen, die die Benutzererfahrung beeintr\u00e4chtigten. Um dieses Problem zu l\u00f6sen, implementierte ich schlussendlich einen <a href=\"https:\/\/en.wikipedia.org\/wiki\/Cache_replacement_policies#Least_Recently_Used_(LRU)\" target=\"_blank\" rel=\"noopener\" title=\"\">LRU-Cache (Least Recently Used)<\/a> mit dem <a href=\"https:\/\/web.dev\/articles\/stale-while-revalidate\" target=\"_blank\" rel=\"noopener\" title=\"\">&#8220;Stale-While-Revalidate&#8221;-Muster<\/a>. Dieser Ansatz erm\u00f6glicht es, zun\u00e4chst zwischengespeicherte (m\u00f6glicherweise veraltete) Daten sofort zur\u00fcckzugeben, w\u00e4hrend im Hintergrund eine Aktualisierung der Daten stattfindet. Dadurch werden Antwortzeiten drastisch reduziert, ohne auf aktuelle Daten verzichten zu m\u00fcssen. Dies stellt den klassischen Kompromiss zwischen Geschwindigkeit und Aktualit\u00e4t dar. Ich setzte am Ende auf den LRU-Cache welcher in-Memory gespeichert wird, da er die einfachste und effektivste Methode war, die keinerlei externe Abh\u00e4ngigkeiten erzeugte. Klassisch h\u00e4tte ich f\u00fcr solch einen Einsatzzweck eine In-Memory-Datenbank als Cache (wie z.B: Redis) oder einen externen Key-Value-Store herangezogen. Diese Komponenten h\u00e4tten aber die Komplexit\u00e4t des Aufbaus f\u00fcr Nutzer, die es selbst hosten m\u00f6chten, erh\u00f6ht. Es w\u00e4re aber denkbar, solche M\u00f6glichkeiten in der Zukunft als optionale Komponente zu erm\u00f6glichen.  <\/p>\n\n\n\n<p>Eine weitere Herausforderung bestand darin, die Zuverl\u00e4ssigkeit des Services durch umfassende Tests zu gew\u00e4hrleisten. Da der Service stark von externen Libraries \/ Kommandozeilen Tools wie rclone und libvips abh\u00e4ngt, war es entscheidend, diese Komponenten in Testumgebungen zu simulieren. Ich setzte auf das \u201eMocking\u201c der Libraries, um isolierte und reproduzierbare Tests zu erm\u00f6glichen, ohne tats\u00e4chliche Verbindungen zu externen Diensten herstellen zu m\u00fcssen. Zus\u00e4tzlich verwendete ich feste (pinned) Versionen aller Abh\u00e4ngigkeiten, um sicherzustellen, dass unerwartete \u00c4nderungen in externen Bibliotheken nicht zu Problemen f\u00fchren. Diese Teststrategien waren besonders wertvoll, da sie fr\u00fchzeitig Probleme aufdeckten und die Stabilit\u00e4t des Services \u00fcber verschiedene Umgebungen w\u00e4hrend des ganzen Entwicklungsprozesses immer wieder sicherzustellen<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Developer-Experience und Integration<\/h2>\n\n\n\n<p>Auch wichtig bei der Entwicklung war es f\u00fcr mich, nicht nur einen leistungsf\u00e4higen API-Service, sondern auch eine gute Integration f\u00fcr Entwickler zu schaffen, da dies meiner Meinung nach genauso wichtig f\u00fcr den Erfolg eines Projektes, insbesondere eines Open-Source-Projekts, ist.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">NPM-Pakete f\u00fcr einfache Integration<\/h3>\n\n\n\n<p>Um dies zu erm\u00f6glichen, habe ich f\u00fcr JavaScript- und React-basierte Projekte jeweils zwei dedizierte NPM-Pakete erstellt, <code class=\"\" data-line=\"\">&lt;a href=&quot;https:\/\/www.npmjs.com\/package\/@shuto-img\/api&quot; title=&quot;&quot;&gt;@shuto-img\/api&lt;\/a&gt;<\/code> und <a href=\"https:\/\/www.npmjs.com\/package\/@shuto-img\/react\" target=\"_blank\" rel=\"noopener\" title=\"\"> <code class=\"\" data-line=\"\">@shuto-img\/react<\/code><\/a>.<\/p>\n\n\n\n<p>Das API-Paket bietet eine schlanke Abstraktionsschicht \u00fcber die API, welche die Komplexit\u00e4ten der HTTP-Anfragen sowie der URL-Generierung kapselt. Besonders die Funktionalit\u00e4t der pre-signed URLs, welche in ihrem Aufbau der Signatur identisch zu der erwarteten Signatur der API sein muss, ist durch das Paket deutlich leichter in der Integration. Hier ein kleiner Ausschnitt, wie mithilfe des API-Pakets die API integriert werden kann:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\" data-line=\"\">import { ShutoClient } from &#039;@shuto-img\/api&#039;;\n\nconst client = new ShutoClient({\n  baseUrl: &#039;https:\/\/your-shuto-instance.com&#039;,\n});\n\n\/\/ Generiert eine optimierte Bild-URL\nconst imageUrl = client.getImageUrl(&#039;path\/to\/image.jpg&#039;, {\n  width: 800,\n  height: 600,\n  format: &#039;webp&#039;\n});<\/code><\/pre>\n\n\n\n<p>F\u00fcr React-Entwickler bietet das <code class=\"\" data-line=\"\">@shuto-img\/react<\/code>-Paket eine nahtlose Integration durch spezialisierte Komponenten und Hooks welche eine einfache Integration in das React-Ecosystem erm\u00f6glichen.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-tsx\" data-line=\"\">import { ShutoImage } from &#039;@shuto-img\/react&#039;;\n\nfunction MyComponent() {\n  return (\n    &lt;ShutoImage\n      path=&quot;folder\/image.jpg&quot; \/\/ Path relative to your storage root\n      w={800} \/\/ Width\n      h={600} \/\/ Height\n      fit=&quot;crop&quot; \/\/ Resize mode\n      fm=&quot;webp&quot; \/\/ Output format\n      q={80} \/\/ Quality\n      alt=&quot;My optimized image&quot;\n      className=&quot;my-image-class&quot;\n      loading=&quot;lazy&quot; \/\/ Enable lazy loading\n      responsive \/\/ Enable responsive sizing\n      fallback={&lt;Placeholder \/&gt;} \/\/ Fallback component for errors\n      onError={(error) =&gt; console.error(error)}\n    \/&gt;\n  );\n}<\/code><\/pre>\n\n\n\n<p>Um die Funktionalit\u00e4t dieser Pakete sowie der API zu demonstrieren, habe ich eine Demoseite erstellt, die auch als Referenzimplementierung dient. Diese kann unter <a href=\"https:\/\/shuto-demo.lg-apps.tech\" target=\"_blank\" rel=\"noopener\" title=\"\">shuto-demo.lg-apps.tech<\/a> eingesehen werden. Die Entwicklung dieser Pakete begann ich erst sp\u00e4t im Entwicklungsprozess, was ich im Nachhinein fr\u00fcher angegangen w\u00e4re, dennoch erwiesen sie sich als entscheidend f\u00fcr die Benutzerfreundlichkeit des gesamten Projekts.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/screenshot.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"785\" data-attachment-id=\"27623\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/02\/28\/die-technische-entwicklung-einer-open-source-losung-zur-bildoptimierung\/screenshot-2\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/screenshot.png\" data-orig-size=\"1400,1073\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"screenshot\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/screenshot-1024x785.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/screenshot-1024x785.png\" alt=\"Eine Demo-Galerie der React-Bibliothek 'shuto-img'. Die Benutzeroberfl\u00e4che zeigt eine Bildergalerie mit verschiedenen Kategorien wie 'Travel', 'Minimalist', 'Nature' und 'Gradients', wobei 'Travel' ausgew\u00e4hlt ist. Die Galerie enth\u00e4lt mehrere Bilder: links ein Feld mit bunten Wildblumen in Rosa, Rot und Gelb; in der Mitte ein Bild eines Backsteinhauses mit einem bl\u00fchenden Garten im Vordergrund; rechts eine antike schwarze K\u00fccheneinrichtung mit kupfernen T\u00f6pfen und Kesseln. Am oberen Rand befinden sich Links zu GitHub, API-Paket und React-Paket. Die gesamte Anwendung demonstriert eine elegante Bildergalerie-Komponente f\u00fcr React-Entwickler.\" class=\"wp-image-27623\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/screenshot-1024x785.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/screenshot-300x230.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/screenshot-768x589.png 768w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/screenshot.png 1400w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">API-Dokumentation<\/h3>\n\n\n\n<p>F\u00fcr Entwickler, welche die NPM-Pakete nicht nutzen wollen oder k\u00f6nnen, sich aber trotzdem intensiv mit der API-Dokumentation besch\u00e4ftigen m\u00f6chten, aber auch generell ist eine gute API-Dokumentation unerl\u00e4sslich. Nachdem ich diese Dokumentation am Anfang manuell gepflegt hatte, was sich schnell als kompliziert und aufwendig sowie fehleranf\u00e4llig erwies, stellte ich die API-Dokumentation von manueller <a href=\"https:\/\/swagger.io\/specification\/\" target=\"_blank\" rel=\"noopener\" title=\"\">OpenAPI\/Swagger-Dokumentation<\/a> auf eine automatisch generierbare Dokumentation im selben Format um. Mithilfe des Tools <a href=\"https:\/\/github.com\/swaggo\/swag\" target=\"_blank\" rel=\"noopener\" title=\"\">swag<\/a> wird jetzt die Dokumentation in der OpenAPI-Spezifikation automatisch mithilfe von Code-Annotationen generiert. Diese Dokumentation ist dann \u00fcber die <a href=\"https:\/\/api.shuto.lg-apps.tech\/docs\/index.html\" target=\"_blank\" rel=\"noopener\" title=\"\">interaktive Swagger-UI (hier am Beispiel von shuto)<\/a> zug\u00e4nglich. Um dies zu erm\u00f6glichen, werden die Annotationen im Code an passenden Stellen, in diesem Fall direkt im Zusammenhang mit den jeweiligen HTTP-Handlern hinzugef\u00fcgt und k\u00f6nnen somit bei \u00c4nderungen direkt aktualisiert werden. <\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-go\" data-line=\"\">\/\/ ListHandler handles directory listing requests\n\/\/ @Summary List contents of a directory\n\/\/ @Description Get a list of files and directories at the specified path\n\/\/ @Tags list\n\/\/ @Accept  json\n\/\/ @Produce  json\n\/\/ @Security ApiKeyAuth\n\/\/ @Param   path     path    string     true        &quot;Path to list contents from&quot;\n\/\/ @Success 200 {array}  utils.RcloneFile &quot;List of files and directories&quot;\n\/\/ @Failure 400 {object} utils.ErrorResponse &quot;Invalid request parameters&quot;\n\/\/ @Failure 401 {object} utils.ErrorResponse &quot;Unauthorized - Invalid or missing API key&quot;\n\/\/ @Failure 404 {object} utils.ErrorResponse &quot;Path not found&quot;\n\/\/ @Failure 500 {object} utils.ErrorResponse &quot;Internal server error&quot;\n\/\/ @Router \/list\/{path} [get]\nfunc ListHandler(w http.ResponseWriter, r *http.Request, imgUtils utils.ImageUtils, rclone utils.Rclone, domainConfig config.DomainConfigManager) {<\/code><\/pre>\n\n\n\n<p>Die Dokumentation bleibt dann im Idealfall immer synchron mit dem Code, die Entwickler k\u00f6nnen zus\u00e4tzlich direkt mit der Dokumentation testen sowie die OpenAPI-Spezifikation mit Client-Generatoren verwenden.<\/p>\n\n\n\n<p>In diesem Fall hat die Automatisierung nicht nur den Wartungsaufwand, sondern auch die Qualit\u00e4t und Aktualit\u00e4t der Dokumentation verbessert. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Key Learnings<\/h2>\n\n\n\n<p>Die Entwicklung hat mir vor allem verdeutlicht, wie stark sich die Anforderungen an \u00f6ffentliche APIs von internen L\u00f6sungen unterscheiden. Die Balance zwischen Flexibilit\u00e4t und Einfachheit war eine st\u00e4ndige Herausforderung. Ich habe gelernt, dass die richtigen Abstraktionsebenen wichtig f\u00fcr die Erweiterbarkeit und die Wartbarkeit sind. So reduzierte die Integration von rclone als Abstraktionsschicht den Implementierungsaufwand im Vergleich zu anderen getesteten L\u00f6sungen erheblich.<\/p>\n\n\n\n<p>Ein weiteres Learning war generell so fr\u00fch wie m\u00f6glich, die Software im Komplettzustand zu testen. Damit meine ich alle Komponenten, von der Verbindung und damit bestehenden Latenzen zu Storage-L\u00f6sungen bis zu den geplanten Frontend-Paketen, w\u00e4re es sinnvoll gewesen, alles so fr\u00fch wie m\u00f6glich zusammen zu testen. Damit h\u00e4tten einige Punkte fr\u00fcher durchdacht und geplant werden k\u00f6nnen. Bei der Implementierung und vor allem Nutzung der Frontendpakete sind mir wieder m\u00f6gliche Verbesserungen f\u00fcr die API eingefallen. H\u00e4tte man fr\u00fcher die Verbindung zu mehreren verschiedenen Storage-L\u00f6sungen getestet, h\u00e4tte der Cache fr\u00fcher integriert werden k\u00f6nnen. Generell macht ein End-to-End Testing in allen F\u00e4llen so fr\u00fch wie m\u00f6glich Sinn und bringt wahrscheinlich sinnvolle Erkenntnisse.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Von der Theorie zur Praxis<\/h2>\n\n\n\n<p>Im Rahmen des Projektes wurde mein Verst\u00e4ndnis von Themen wie modularer Architektur, CI\/CD sowie API-Design vertieft, aber auch von Aspekten, die in diesem Blogpost nicht beschrieben worden sind, wie Infrastructure-as-Code (mit Terraform), verschiedene Formen des Loggens. Die Herausforderung, eine Applikation, die von Anfang an f\u00fcr Open Source gedacht ist und auch anderen Entwicklern zug\u00e4nglich sein soll, zwang mich des \u00d6fteren erneut und anders \u00fcber Themen nachzudenken.<\/p>\n\n\n\n<p>Ich habe erneut gemerkt, wie wichtig eine Sammlung an verstandenen und einsetzbaren Techniken ist. Gleichzeitig darf man das Gesamtbild der Anwendung sowie weitere Aspekte wie die Entwickler und die zugrundeliegende Architektur nicht aus den Augen verlieren. Die Balance zwischen Vision und Implementierung und die Einschr\u00e4nkungen dadurch nehme ich f\u00fcr die Weiterentwicklung von shuto (was fest geplant ist) sowie andere Projekte mit. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Im Rahmen meines Systems Engineering Projektes habe ich die shuto-api entwickelt \u2013 eine in Go geschriebene Open-Source-Bildoptimierungsl\u00f6sung. Mein Ziel war es, eine flexible, self-hostable und erweiterbare API zu erstellen, welche ohne viele Probleme in bereits bestehende Systeme integriert werden kann. Der Service erm\u00f6glicht es, Bilder zu komprimieren, zu skalieren sowie weiter zu bearbeiten. Diese sind [&hellip;]<\/p>\n","protected":false},"author":1223,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[651,2],"tags":[150,3,1019],"ppma_author":[1094],"class_list":["post-27563","post","type-post","status-publish","format-standard","hentry","category-system-designs","category-system-engineering","tag-ci-cd","tag-docker","tag-system-engineering"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":21683,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/18\/ynstagram-cloud-computing-mit-aws-serverless\/","url_meta":{"origin":27563,"position":0},"title":"Ynstagram &#8211; Cloud Computing mit AWS &amp; Serverless","author":"ns144","date":"18. September 2021","format":false,"excerpt":"Im Rahmen der Vorlesung \u201cSoftware Development for Cloud Computing\u201d haben wir uns hinsichtlich des dortigen Semesterprojektes zum Ziel gesetzt einen einfachen Instagram Klon zu entwerfen um uns die Grundkenntnisse des Cloud Computings anzueignen. Grundkonzeption \/ Ziele des Projektes Da wir bereits einige Erfahrung mit React aufgrund anderer studentischer Projekte sammeln\u2026","rel":"","context":"In &quot;Cloud Technologies&quot;","block_context":{"text":"Cloud Technologies","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/cloud-technologies\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Prasentation_CC_01.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Prasentation_CC_01.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Prasentation_CC_01.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Prasentation_CC_01.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Prasentation_CC_01.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Prasentation_CC_01.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":28372,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2026\/02\/18\/safeguards-in-der-ki-unterstutzten-softwareentwicklung\/","url_meta":{"origin":27563,"position":1},"title":"Safeguards in der KI-unterst\u00fctzten Softwareentwicklung","author":"Christoph Merck","date":"18. February 2026","format":false,"excerpt":"KI gest\u00fctzte Werkzeuge und autonome Agenten machen Softwareentwicklung schneller, schaffen aber neue Sicherheitsrisiken, weil sie eigenst\u00e4ndig Entscheidungen treffen und externe Tools nutzen k\u00f6nnen. Der Artikel zeigt, warum deshalb ein mehrschichtiges Safeguard Konzept n\u00f6tig ist, das klassische Ma\u00dfnahmen wie Code Reviews, Tests und statische sowie dynamische Analysen mit KI spezifischen Schutzmechanismen\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":20593,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/25\/herzlichen-gluckwunsch-sie-haben-gewonnen\/","url_meta":{"origin":27563,"position":2},"title":"HERZLICHEN GL\u00dcCKWUNSCH &#8211; Sie haben gewonnen!","author":"Eric Prytulla","date":"25. September 2021","format":false,"excerpt":"\u00dcber Social Engineering und wie man sich sch\u00fctzen kann. Jeder kennt E-Mails mit Titeln wie diesem. Eine wildfremde Person verspricht Gewinne in Millionenh\u00f6he. Und alles, was daf\u00fcr ben\u00f6tigt wird, sind ein paar pers\u00f6nliche Daten. Ein Traum vieler Menschen wird wahr und man will dem Titel glauben. Doch was passiert, wenn\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Spam.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":27382,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/02\/27\/tools-zur-automatischen-erstellung-von-software-bill-of-materials-sbom\/","url_meta":{"origin":27563,"position":3},"title":"Tools zur automatischen Erstellung von Software Bill of Materials (SBOM)","author":"Dorina Sobiecki","date":"27. February 2025","format":false,"excerpt":"Anmerkung: Dieser Blogpost wurde f\u00fcr das Modul Enterprise IT (113601a) verfasst. 1. Einleitung Die fortschreitende Digitalisierung und die zunehmende Vernetzung von Softwaresystemen haben Cybersicherheit zu einem zentralen Thema f\u00fcr Unternehmen, Beh\u00f6rden und Endnutzer gemacht. Transparenz \u00fcber die eingesetzten Softwarekomponenten ist dabei essenziell, um Sicherheitsl\u00fccken zu identifizieren und regulatorische Anforderungen zu\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":27583,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/02\/28\/einsatz-von-kunstlicher-intelligenz-zur-automatischen-skalierung-von-kubernetes-clustern\/","url_meta":{"origin":27563,"position":4},"title":"Einsatz von K\u00fcnstlicher Intelligenz zur automatischen Skalierung von Kubernetes-Clustern","author":"Lars Gerigk","date":"28. February 2025","format":false,"excerpt":"Anmerkung:\u00a0Dieser Blogpost wurde f\u00fcr das Modul Enterprise IT (113601a) verfasst.Aus Gr\u00fcnden der besseren Lesbarkeit wird in dieser Arbeit auf eine geschlechtsneutrale Differenzierung verzichtet. S\u00e4mtliche Personenbezeichnungen gelten gleicherma\u00dfen f\u00fcr alle Geschlechter. Kurzfassung Die Branche der fortschreitenden Cloud Digitalisierung und die steigenden Anforderungen an hochverf\u00fcgbaren, skalierbaren Anwendungen haben Kubernetes zu einer der\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-27.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-27.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-27.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/image-27.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":22395,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2022\/02\/27\/applikationsinfrastruktur-einer-modernen-web-anwendung\/","url_meta":{"origin":27563,"position":5},"title":"Applikationsinfrastruktur einer modernen Web-Anwendung","author":"Jannik Smidt","date":"27. February 2022","format":false,"excerpt":"ein Artikel von Nicolas Wyderka, Niklas Schildhauer, Lucas Cr\u00e4mer und Jannik Smidt Projektbeschreibung In diesem Blogeintrag wird die Entwicklung der Applikation- und Infrastruktur des Studienprojekts sharetopia beschrieben. Als Teil der Vorlesung System Engineering and Management wurde besonders darauf geachtet, die Anwendung nach heutigen Best Practices zu entwickeln und dabei kosteneffizient\u2026","rel":"","context":"In &quot;Interactive Media&quot;","block_context":{"text":"Interactive Media","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/interactive-media\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/Bildschirmfoto_2022-02-27_um_18.59.07.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/Bildschirmfoto_2022-02-27_um_18.59.07.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/Bildschirmfoto_2022-02-27_um_18.59.07.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/Bildschirmfoto_2022-02-27_um_18.59.07.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/02\/Bildschirmfoto_2022-02-27_um_18.59.07.png?resize=1050%2C600&ssl=1 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"authors":[{"term_id":1094,"user_id":1223,"is_guest":0,"slug":"lennart_gastler","display_name":"Lennart Gastler","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/cf47e4b8a08d9b249bebfd7cefa3f39c5cefa5ed7682cf04144bcf6cdc767ade?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/27563","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/users\/1223"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/comments?post=27563"}],"version-history":[{"count":8,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/27563\/revisions"}],"predecessor-version":[{"id":27632,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/27563\/revisions\/27632"}],"wp:attachment":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/media?parent=27563"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/categories?post=27563"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/tags?post=27563"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/ppma_author?post=27563"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}