<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: MOmentum</title>
    <description>The latest articles on DEV Community by MOmentum (@migrosonline).</description>
    <link>https://dev.to/migrosonline</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F10801%2Ff85767db-c850-4d2c-994d-7359d0e8051a.png</url>
      <title>DEV Community: MOmentum</title>
      <link>https://dev.to/migrosonline</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/migrosonline"/>
    <language>en</language>
    <item>
      <title>How Migros Online protects its assets with Cloudflare - a DDoS Story</title>
      <dc:creator>Marc Schär</dc:creator>
      <pubDate>Thu, 29 Jan 2026 07:35:48 +0000</pubDate>
      <link>https://dev.to/migrosonline/how-migros-online-protects-its-assets-with-cloudflare-a-ddos-story-2n8j</link>
      <guid>https://dev.to/migrosonline/how-migros-online-protects-its-assets-with-cloudflare-a-ddos-story-2n8j</guid>
      <description>&lt;p&gt;Nowadays, attackers are more and more eager to get your website down, to gather your data, to exploit every little vulnerability you might have. It has become a major concern for every company to protect itself against any malicious activity.&lt;/p&gt;

&lt;p&gt;When thinking about what to put in place to improve your security, you have mainly two situations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're big enough and have the knowledge in-house to manage the whole security stack&lt;/li&gt;
&lt;li&gt;You don't have the expertise or you don't want to spend a huge human effort on setting up the security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the first case, you need to have one or multiple teams dedicated to the security to build a safe and secure infrastructure and to keep it up to date with the latest vulnerabilities found. Knowing that you should ask yourself "when" and not "if" you're going to be attacked, this team should also know how to react when something goes south at each security level.&lt;/p&gt;

&lt;p&gt;For small companies or companies that don't want to invest in a highly-skilled security team, you will probably search for market solutions and providers that are able to handle these concerns for you, or at least that are going to ease the management of many security aspects. Nevertheless, it won’t prevent you from having security dedicated people to manage the selected solutions as well as other security aspects, like people awareness to prevent phishing for example.&lt;/p&gt;

&lt;p&gt;Beware that choosing a third party comes with its downsides: you become, at a certain level, dependent of their infrastructure, their partners and their problems (availability, security). Thus, you can encounter issues over which you have no control.&lt;/p&gt;

&lt;h1&gt;
  
  
  Migros Online and Cloudflare
&lt;/h1&gt;

&lt;p&gt;At Migros Online, we decided a few years back to work with &lt;a href="https://www.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare&lt;/a&gt; to have a unique entrypoint for our infrastructure (on-premises back then, in the cloud today).&lt;/p&gt;

&lt;p&gt;Using such a tool brought us many security and performance aspects for our &lt;a href="https://www.migros.ch/" rel="noopener noreferrer"&gt;website&lt;/a&gt; and our mobile applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Content Delivery Network (CDN)&lt;/strong&gt;: edge caching allows us to serve assets without hitting the backend on every requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Application Firewall (WAF)&lt;/strong&gt;: we are able to protect our public endpoints with simple rules in a few clicks (or a few Terraform line of code ;-))&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Basic sets of rules&lt;/strong&gt; that are managed by Cloudflare directly allowing us to fix deeper issues with serenity (as an example, the &lt;a href="https://en.wikipedia.org/wiki/Log4Shell" rel="noopener noreferrer"&gt;log4Shell&lt;/a&gt; vulnerability was automatically handled by Cloudflare, giving us the time to patch our backend systems without pressure)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bot protection&lt;/strong&gt;: automatic categorization of the traffic and possibility to easily act on requests based on the rating done by the platform&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed Denial of Service (DDoS) protection&lt;/strong&gt;: automatic discovery of DDoS attacks and direct mitigation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Trust mechanisms&lt;/strong&gt;: we are able to expose private endpoints, but secure them behind the Zero Trust product, bound with our authentication provider&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare Warp&lt;/strong&gt;: a tunneling solution to access internal resources that we don't want to expose publicly, even behind Zero Trust&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to Cloudflare, we were able to consolidate our public exposure, simplify its management and get confidence that we are in good hands when problems arise.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cloudflare Immerse 2025
&lt;/h1&gt;

&lt;p&gt;As an example of Cloudflare's usage for Migros Online, I went on stage (for the first time!) during the Cloudflare Immerse 2025 event in Zurich to present how Cloudflare helped us in mitigating DDoS attacks we faced in the past.&lt;/p&gt;

&lt;p&gt;The recording is available below and outlines the Migros Online context, what issues we faced and how Cloudflare was a key element in solving the problem.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/QKKEg8uVDSo"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

</description>
      <category>cloudflare</category>
      <category>security</category>
      <category>productivity</category>
      <category>tooling</category>
    </item>
    <item>
      <title>English - the hottest programming language of the future</title>
      <dc:creator>Sven Scheffel</dc:creator>
      <pubDate>Fri, 10 Oct 2025 17:26:33 +0000</pubDate>
      <link>https://dev.to/migrosonline/english-the-hottest-programming-language-of-the-future-a8n</link>
      <guid>https://dev.to/migrosonline/english-the-hottest-programming-language-of-the-future-a8n</guid>
      <description>&lt;p&gt;We are all passionate engineers who love to follow our favorite frontend or backend framework, keeping up with new features, releases, or additions. Using various methods, we like to stay up-to-date, attend conferences, read blog posts, and even engage in communities that revolve around a specific framework. However, most frameworks are also tied to a specific language, a programming language most of us (hopefully) have learned to love and are fluent in.&lt;/p&gt;

&lt;p&gt;These circumstances haven't changed for years, even decades, at least not beyond common tech trends and industry standards in the form of Microservices, Event-Driven Architecture, Domain-Driven Design, Serverless, you name it. Our beloved frameworks and languages eventually adapted to the needs of the industry, and we were able to keep using the tools and languages that we hold dear. Picking a different language or framework with similar features remained a matter of preference and personal bias, about which we have probably all, at some point, spent hours arguing over a hot coffee or cold beer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Brace yourselves: Changes are coming!
&lt;/h2&gt;

&lt;p&gt;Dark clouds of unknowns emerge and a storm of change is brewing. Visible on our horizon are changes that scare us and threaten our existing ways of working and comfort. It’s not a new language syntax or the 100th web framework that I am referring to, but an established language: English. English?? You might ask yourself: how is that a new programming language? English is the language that makes up the training data of most state‑of‑the‑art large language models (LLMs) (1). It’s one of the languages that every LLM is able to speak, but more importantly, it's the language spoken and understood by most people in the world (2). It is the language of humans. Why should it not also be the language of developing software?&lt;/p&gt;

&lt;p&gt;Programming languages have evolved and changed over the past decades. The overall trend in these developments is an increased level of abstraction. Programming languages opened their doors to wider audiences, requiring less deep technical knowledge in the field of computer science. We usually do not need to worry about low‑level hardware optimization like manual memory management with pointers or hand‑crafting registers and stack frames for function calls. Just like me, you probably last heard all these things in university and did a small demo application on a microcontroller to let some LEDs blink like a Christmas tree, beautiful!&lt;/p&gt;

&lt;p&gt;The language used was Assembler, which, by my standards, especially while also learning Java and C# in other lectures, seemed quite cumbersome. That's just one of the reasons why C and later languages like Java and C#, gained popularity. The profession of a software developer quickly shifted toward being able to focus on solving business problems by writing good and clean code, without worrying too much about the underlying low-level details. Heck, we even call it craftsmanship, that's how proud we are of our "craft"!&lt;/p&gt;

&lt;p&gt;Once again, a new, much more drastic layer of abstraction has emerged: Large Language Models (LLMs)! More specifically, with the tools evolving around using LLMs to support engineers and other professionals to “craft” applications. However, this time the evolution is very different, as we are not only changing our flight level and the level of abstraction. We are also moving sideways into non-determinism at the same time (at least at the moment; there are experiments of LLMs being deterministic (3)).&lt;/p&gt;

&lt;p&gt;Determinism, especially, is important for us engineers to ease our logic-oriented minds. Running an instruction twice with different outputs is not something we like. Overall, we have achieved a fair amount of abstraction with various frameworks but have not reached the level of being close to human thinking. This changes if we use our native tongue (for example, English) to express our thoughts and turn them into code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyoyrp6d5vifre0l0cwgu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyoyrp6d5vifre0l0cwgu.png" alt="Higher abstraction and non-determinism shift" width="800" height="442"&gt;&lt;/a&gt; &lt;strong&gt;Illustration&lt;/strong&gt;: Birgitta Böckeler (source: &lt;a href="https://martinfowler.com/articles/2025-nature-abstraction.html" rel="noopener noreferrer"&gt;LLMs bring new nature of abstraction&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Coding disappoints us?
&lt;/h2&gt;

&lt;p&gt;Hopefully by now you've dipped your feet into AI coding using LLMs to supercharge your development workflow. On one day, you're one‑shotting results for tasks we expected AI to fail (and that would have taken quite some time if done manually); and on another day, you're trying to solve what seems (to us) like a pretty obvious bug, but the AI completely derails and suggests bits and bytes of garbage.&lt;/p&gt;

&lt;p&gt;Overall, our trust and confidence in AI coding tools is dominated by these pivotal (but sometimes first) impressions. We try to wrap our heads around how "good" or "ready" the AI models are and how mature the tooling that uses LLMs is, when we do this only to give ourselves peace of mind and protect our software engineering craftsmanship. Studies show that at the moment software engineers are even less productive due to a high skill ceiling and the learning required when using AI coding agents (4). I am pretty sure all of us went through the same rollercoaster of emotions, for which I have a good analogy displayed as an illustration below. There are various resources on how to get the best results out of AI coding.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiith98cqng9hcyrpl1ln.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiith98cqng9hcyrpl1ln.png" alt="Six stages of AI adoption by software developers" width="800" height="321"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Illustration&lt;/strong&gt;: Geoffrey Huntley (source: &lt;a href="https://ghuntley.com/ngmi/" rel="noopener noreferrer"&gt;What do I mean by some software devs are "ngmi"?&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;However, most of the time the simplest advice is to clearly specify your thoughts by translating them to English as input for an LLM. That's the point I want to touch on: our abilities as software engineers to express our thoughts and plans in English, to make them understandable.&lt;/p&gt;

&lt;p&gt;Various memes make fun of the different languages that software engineers and business speak, often cited as reasons for missed deadlines, failed projects, or abandoned products. To cure this, we came up with Domain‑Driven Design practices to align on a so‑called "Ubiquitous Language" inside a domain or "Bounded Context" of our application and system. While speaking at the same level with business, we as software engineers are still translating the domain models, business rules, and specifications into a different language (hopefully the one we are so passionate about!). Need good startup performance and a low memory footprint? It's fine, we can use a language that has not been specifically designed for that and adjust it so that we do not need to learn a new language. Worst case, it's a language we were even arguing about in the past years of our professional life.&lt;/p&gt;

&lt;p&gt;Instead of focusing on the mere translation into a more technical language, we often let other aspects like observability, testing, and resilience draw the short straw during prioritization. This leads to them inevitably ending up in the "Do eventually" section of our backlogs.&lt;/p&gt;

&lt;p&gt;If you followed the last paragraphs, you’re hopefully asking yourself why we translate from English into Programming Language XYZ. We are aligned with our business on a shared language; we put effort into building our architecture to mirror our product domain. Why do we keep translating? Can’t we develop using only English?&lt;/p&gt;

&lt;h2&gt;
  
  
  Spec-Driven Development
&lt;/h2&gt;

&lt;p&gt;If you feel your software engineer heart hurt when you hear the term "Vibe Coding," the next lines are especially for you! By Vibe Coding I am referring to the viral idea of a less technical user quickly building and deploying products by conversing with an AI Agent. Vibe Coding scratches the same no-code-utopia itch that has been promised for a long time: making software development accessible in a reliable and scalable way to a wider and less technical audience. "Build me a chat application" as a command rather than a suitable prompt leaves too many questions unanswered.&lt;/p&gt;

&lt;p&gt;However, we all know software engineering usually goes beyond what's achieved in a simple vibe-coding session. Especially if the product matures from an MVP state to a product that requires maintainability and resilience, Vibe Coding quickly reaches its limits and leads to frustration. Bugs are introduced, fixed and then reintroduced. The application is vulnerable to attacks and proves to be unreliable.&lt;/p&gt;

&lt;p&gt;How can we keep the language English and use it to generate software in a more reliable way? That’s where the idea of “Spec-Driven Development” comes in (5)(6). AI is (thankfully) bad at mind reading, so we need to be clear when expressing our intent in terms of technical requirements to fulfill the needs of our application and covering our business/domain rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  So how do we achieve this?
&lt;/h2&gt;

&lt;p&gt;The key difference is that we no longer separate the language used for describing the specifications and the language we use for implementation; instead, we leverage LLMs to do the translation into code for us. We are in charge of outlining the architecture and implementation details by clearly stating our intent as specifications rather than code. By doing this, we stay true to a real shared language across our product development lifecycle, as well as making sure that the technical requirements are documented in a central place and in the language everyone understands.&lt;/p&gt;

&lt;p&gt;We are moving from code being the source of truth to intent being the source of truth, staying truly faithful to Domain-Driven Design.&lt;/p&gt;

&lt;p&gt;Instead of "vibing" our applications together in a Ping Pong session commanding a new fancy Agent what to do or playing whack-a-mole on bugs, we want to properly outline the specifications of our application. We need to put our analytical and technical thoughts in words and clearly specify our intent to eliminate any ambiguity. The specifications need to be as clear as code and it is up to us to learn how to write them. We implement new features by adjusting the specifications, no longer by touching the code. In contrast to vibe coding where we usually start hitting walls and move to operate on the code level instead.&lt;/p&gt;

&lt;p&gt;How about rewriting your application, or, more likely, a part of your system, to another programming language? If done right, and using Spec-Driven Development correctly, this should, in theory, be effortless, at least on a per-component level. You probably guessed it, but that goes hand in hand with the idea of Test-Driven Development (TDD)! It's even an abstraction of TDD since we should always check our product against the created specifications and use them as the source of truth! We mix the native-language advantages from vibe coding but enrich our instructions with clear intent and high-level technical details. This in itself requires the experience of software engineers to build a sustainable application or system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fefu98rmsxhc1p5kewag2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fefu98rmsxhc1p5kewag2.png" alt="Spec driven development workflow" width="797" height="495"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Illustration&lt;/strong&gt;: Dusan Omercevic (source: &lt;a href="https://blog.codeplain.ai/p/beyond-vibe-coding" rel="noopener noreferrer"&gt;Beyond Vibe Coding&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Hopefully, my post inspired you to take a step back from low-level technical details and the specificities of languages or frameworks. We engineers usually have brains more tinkered towards logical thinking, and sometimes we have trouble expressing our thoughts in words. Work on your communication skills and how you express your thoughts in a natural language like English. Bring your technical writing skills to the next level to allow AI Agents to do the language to code translation for you.&lt;/p&gt;

&lt;p&gt;Focus on understanding the foundations of crafting reliable applications and systems, and do not get carried away by a new syntax introduced in your favorite language XYZ. Let the LLM, and your development process with linting and tests, worry about that! Focus on what’s important and what your product has to fulfill, and let the LLM pick the suitable language that is created for that purpose. Most important, as you do by keeping up with new framework and language version releases, stay curious and keep learning how to use AI coding best in your position.&lt;/p&gt;

&lt;p&gt;Will we see more frameworks and languages doing more or less the same things as existing languages but with a different syntax? Unlikely. Most likely we will use the languages the LLM is fluent in and that fit our specifications in the future, and we will need to look for other technical details to argue over hot coffees and cold beers!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2404.11553v2" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2404.11553v2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ethnologue.com/insights/most-spoken-language/" rel="noopener noreferrer"&gt;https://www.ethnologue.com/insights/most-spoken-language/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thinkingmachines.ai/blog/defeating-nondeterminism-in-llm-inference/" rel="noopener noreferrer"&gt;https://thinkingmachines.ai/blog/defeating-nondeterminism-in-llm-inference/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/pdf/2507.09089" rel="noopener noreferrer"&gt;https://arxiv.org/pdf/2507.09089&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/ai-and-ml/generative-ai/spec-driven-development-with-ai-get-started-with-a-new-open-source-toolkit/" rel="noopener noreferrer"&gt;https://github.blog/ai-and-ml/generative-ai/spec-driven-development-with-ai-get-started-with-a-new-open-source-toolkit/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.codeplain.ai/p/beyond-vibe-coding" rel="noopener noreferrer"&gt;https://blog.codeplain.ai/p/beyond-vibe-coding&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: An LLM was fed with cookies 🍪 to find typos and generate the header image of this post.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>programming</category>
      <category>ai</category>
      <category>ddd</category>
    </item>
    <item>
      <title>How to run services locally with no fuss using spring-boot-docker-compose</title>
      <dc:creator>Gabriel Dinant</dc:creator>
      <pubDate>Tue, 02 Sep 2025 05:42:28 +0000</pubDate>
      <link>https://dev.to/migrosonline/how-to-run-services-locally-with-no-fuss-using-spring-boot-docker-compose-4nhb</link>
      <guid>https://dev.to/migrosonline/how-to-run-services-locally-with-no-fuss-using-spring-boot-docker-compose-4nhb</guid>
      <description>&lt;p&gt;Running services locally hasn't always been easy and still has its quirks. As soon as a service is integrated with external systems it can become challenging.&lt;/p&gt;

&lt;p&gt;In this blog post, we will walk through how to set up a Spring Boot application that connects to multiple systems such as a message broker or a database, while using &lt;code&gt;spring-boot-docker-compose&lt;/code&gt; to manage these dependencies as part of the application lifecycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why &amp;amp; When to consider?
&lt;/h2&gt;

&lt;p&gt;Using live environments during development has its own set of pros &amp;amp; cons. &lt;/p&gt;

&lt;p&gt;✅ Common technologies supported by Spring Boot / Spring Cloud such as Kafka, MySQL, Firebase, RabbitMQ, and so on, are technologies that can and should be substituted whenever possible.&lt;/p&gt;

&lt;p&gt;⚠️ On the flip side, mocking the behaviour of upstream services introduces complexity and should be carefully considered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use case
&lt;/h2&gt;

&lt;p&gt;Consider a &lt;code&gt;Blog Application&lt;/code&gt; that &lt;em&gt;consumes&lt;/em&gt; &lt;code&gt;Kafka&lt;/code&gt; events from a topic (&lt;code&gt;blog.updates&lt;/code&gt;), calculates the sentiment of the given blogpost and pushes the final update in a RabbitMQ queue. For this exercise, let's pretend the publisher is also the consumer and eventually &lt;em&gt;saves&lt;/em&gt; the processed result in a &lt;code&gt;MSSQL server&lt;/code&gt; database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qgwjvwq9urcegk5w8vr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qgwjvwq9urcegk5w8vr.png" alt="Architecture" width="800" height="599"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Let's take a look at the complete picture of the project before diving into each part.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── pom.xml 👈🏻
└── src
    ├── main
    │   ├── java
    │   │   └── ch
    │   │       └── migrosonline
    │   │           └── blog
    │   │               ├── BlogApplication.java
    │   │               ├── context
    │   │               │   └── RabbitMQContext.java
    │   │               ├── kafka
    │   │               │   ├── BlogPostUpdateEventListener.java
    │   │               │   └── model
    │   │               │       └── BlogPostUpdateEvent.java
    │   │               ├── processor
    │   │               │   └── BlogProcessor.java
    │   │               ├── rabbitmq
    │   │               │   ├── model
    │   │               │   │   └── ProcessedBlogPostMessage.java
    │   │               │   ├── RabbitMQListener.java
    │   │               │   └── RabbitMQProducer.java
    │   │               └── repository
    │   │                   ├── BlogRepository.java
    │   │                   └── model
    │   │                       └── BlogEntity.java
    │   └── resources
    │       ├── application.yml 👈🏻
    │       ├── application-LOCAL.yml 👈🏻
    │       ├── compose.yml 👈🏻
    │       └── init.sql
    └── &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This guide assumes prior familiarity with some bricks of the Spring Ecosystem such as &lt;code&gt;@SpringBootApplication&lt;/code&gt; main class or &lt;code&gt;@Configuration&lt;/code&gt; contexts. What is important to focus on here is the resources marked with a '👈🏻'.&lt;/p&gt;

&lt;h3&gt;
  
  
  pom.xml
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;key&lt;/strong&gt; dependency that must be added to the dependency management system is &lt;code&gt;spring-boot-docker-compose&lt;/code&gt;. Any important details regarding &lt;code&gt;spring-boot-docker-compose&lt;/code&gt; can be found on the &lt;a href="https://docs.spring.io/spring-boot/reference/features/dev-services.html#features.dev-services.docker-compose" rel="noopener noreferrer"&gt;Spring reference documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;

    ...

    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-docker-compose&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;runtime&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;optional&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/optional&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

    ...

&lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;repackage&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;spring-boot-docker-compose&lt;/code&gt; is primarily a &lt;em&gt;dev tool&lt;/em&gt; therefore  Spring Boot won't be adding this dependency as part of the repackaged application (fat .jar). In other words, it won't be available in production builds unless explicitly &lt;a href="https://docs.spring.io/spring-boot/reference/features/dev-services.html#features.dev-services.docker-compose" rel="noopener noreferrer"&gt;specified&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When starting the application locally via IDE's plugins or the Spring Boot plugin, all runtime dependencies will be available on the classpath.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./mvnw spring-boot:run &lt;span class="nt"&gt;-Dspring-boot&lt;/span&gt;.run.jvmArguments&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-Dspring.profiles.active=LOCAL"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Application properties
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;application.yml&lt;/code&gt; file provides the default, production-grade configuration. By using Spring profiles, we can later define a &lt;code&gt;LOCAL&lt;/code&gt; profile that overrides and leverages the &lt;code&gt;compose.yml&lt;/code&gt; definition.&lt;/p&gt;

&lt;h4&gt;
  
  
  application.yml
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;application&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;blog&lt;/span&gt;

  &lt;span class="na"&gt;datasource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;URI_TO_A_REMOTE_DATABASE&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SA&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DATABASE_PASSWORD}&lt;/span&gt;

  &lt;span class="na"&gt;docker.compose.enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="na"&gt;kafka&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;bootstrap-servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;URI_TO_A_REMOTE_KAFKA_SERVER&amp;gt;&lt;/span&gt;

    &lt;span class="na"&gt;consumer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;group-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ch.migrosonline&lt;/span&gt;
      &lt;span class="na"&gt;key-deserializer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org.apache.kafka.common.serialization.StringDeserializer&lt;/span&gt;
      &lt;span class="na"&gt;properties.spring.json.type.mapping&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;blogpost-update-event:ch.migrosonline.momentum.kafka.model.BlogPostUpdateEvent&lt;/span&gt;

    &lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SASL_SSL&lt;/span&gt;
      &lt;span class="na"&gt;properties.sasl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;mechanism&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PLAIN&lt;/span&gt;
        &lt;span class="na"&gt;jaas.config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;org.apache.kafka.common.security.plain.PlainLoginModule required username='kafka' password='${KAFKA_PASSWORD}'&lt;/span&gt;

  &lt;span class="na"&gt;rabbitmq&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;URI_TO_A_REMOTE_RABBITMQ_SERVER&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5672&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rabbitmq&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${RABBIT_PASSWORD}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  application-LOCAL.yml
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;datasource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:sqlserver://localhost;encrypt=false&lt;/span&gt;

  &lt;span class="na"&gt;docker.compose&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;classpath:/compose.yml&lt;/span&gt;
    &lt;span class="na"&gt;stop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;down&lt;/span&gt; &lt;span class="c1"&gt;# 'docker compose down' on application stop&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;

  &lt;span class="na"&gt;kafka&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;bootstrap-servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost:29092&lt;/span&gt;
    &lt;span class="na"&gt;security.protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PLAINTEXT&lt;/span&gt;

  &lt;span class="na"&gt;rabbitmq&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost&lt;/span&gt;

  &lt;span class="na"&gt;sql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
      &lt;span class="na"&gt;schema-locations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;classpath:init.sql&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, the &lt;code&gt;docker.compose.lifecycle-management&lt;/code&gt; property runs &lt;code&gt;docker compose up&lt;/code&gt; when the application starts and &lt;code&gt;docker compose stop&lt;/code&gt; when it stops. These commands can be customised by redefining the start or stop command as shown in the &lt;code&gt;application-LOCAL.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  compose.yml
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;compose.yml&lt;/code&gt; file is fully customisable and describes services to be substituted. &lt;/p&gt;

&lt;p&gt;In the example below, a Kafka cluster (with a topic and partitions), an MSSQL database service, and a RabbitMQ service are defined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;kafka&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;confluentinc/cp-kafka:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kafka&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;29092:9094"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;CLUSTER_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clusterId&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_PROCESS_ROLES&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;broker,controller&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_NODE_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LISTENERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_ADVERTISED_LISTENERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PLAINTEXT://kafka:9092,EXTERNAL://localhost:29092&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LISTENER_SECURITY_PROTOCOL_MAP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_CONTROLLER_QUORUM_VOTERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0@kafka:9093&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_CONTROLLER_LISTENER_NAMES&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CONTROLLER&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;

  &lt;span class="na"&gt;kafka-initializer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;confluentinc/cp-kafka:latest&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kafka&lt;/span&gt;
    &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/bin/sh'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-c'&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;"&lt;/span&gt;
      &lt;span class="s"&gt;kafka-topics --bootstrap-server kafka:9092 --create --if-not-exists --topic blog.updates --partitions 2 --replication-factor 1&lt;/span&gt;
      &lt;span class="s"&gt;kafka-topics --bootstrap-server kafka:9092 --list&lt;/span&gt;
      &lt;span class="s"&gt;"&lt;/span&gt;

  &lt;span class="na"&gt;mssql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcr.microsoft.com/mssql/server:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mssql&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1433:1433"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ACCEPT_EULA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Y&lt;/span&gt;
      &lt;span class="na"&gt;MSSQL_SA_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DATABASE_PASSWORD}&lt;/span&gt;

  &lt;span class="na"&gt;rabbitmq&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rabbitmq:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rabbitmq&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5672:5672"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;RABBITMQ_DEFAULT_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rabbitmq&lt;/span&gt;
      &lt;span class="na"&gt;RABBITMQ_DEFAULT_PASS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${RABBIT_PASSWORD}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Alternative approach
&lt;/h2&gt;

&lt;p&gt;Testcontainers is an alternative to substitute external services  not only in tests but also in dev mode. If you are interested to know more you can read the official Spring &lt;a href="https://docs.spring.io/spring-boot/reference/features/dev-services.html#features.dev-services.testcontainers" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We saw how to wire production grade technologies all together in a seamless way with &lt;code&gt;Docker&lt;/code&gt; and &lt;code&gt;spring-boot-docker-compose&lt;/code&gt;, why and when this setup should be considered.&lt;/p&gt;

&lt;p&gt;The full source code can be found ➡️ &lt;a href="https://github.com/gdinant/momentum/tree/main/spring-boot-docker-compose" rel="noopener noreferrer"&gt;here&lt;/a&gt; ⬅️.&lt;/p&gt;

&lt;p&gt;Happy coding! 👨🏻‍💻👩🏼‍💻&lt;/p&gt;




&lt;p&gt;Written by Gabriel Dinant, &lt;a href="https://www.linkedin.com/company/migros-online/posts/?feedView=all" rel="noopener noreferrer"&gt;Staff Software Engineer @ MigrosOnline&lt;/a&gt; &lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>docker</category>
    </item>
    <item>
      <title>Green IT: for the planet and the wallet</title>
      <dc:creator>Aurélia Rochat</dc:creator>
      <pubDate>Thu, 07 Aug 2025 09:11:32 +0000</pubDate>
      <link>https://dev.to/migrosonline/green-it-for-the-planet-and-the-wallet-2cna</link>
      <guid>https://dev.to/migrosonline/green-it-for-the-planet-and-the-wallet-2cna</guid>
      <description>&lt;p&gt;&lt;strong&gt;IT systems play a major role in climate change.&lt;br&gt;
What if we could all play a part in reducing the damage? The good news: we can and we’ll show you how.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A few months after witnessing the extreme drought situation in the Drâa Valley, Morocco, I attended Devoxx Conference in Antwerp. This was before the AI wave, full of inspiring sustainability talks which opened my eyes: having already made personal lifestyle changes to reduce my environmental impact, I needed ways to mitigate my professional impact. Devoxx talks—such as &lt;a href="https://www.youtube.com/watch?v=WvoRz5EYR7Y&amp;amp;list=PL5mL8_iVrdv68xr6roOhXikyfiBgNyksY&amp;amp;index=2&amp;amp;ab_channel=Devoxx" rel="noopener noreferrer"&gt;Towards a carbon aware cloud&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=CbYZQl27ko8&amp;amp;list=PL5mL8_iVrdv68xr6roOhXikyfiBgNyksY&amp;amp;index=4&amp;amp;ab_channel=Devoxx" rel="noopener noreferrer"&gt;The Fast and the Sustainable: Unleash the Power of Sustainable IT &amp;amp; High Performance Green Code&lt;/a&gt;—inspired me and motivated me to introduce the Green IT topic at Migros Online.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7wj4vbf6qoohax0ek92.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7wj4vbf6qoohax0ek92.jpg" alt="Drâa River: Morocco’s longest river, where no water can be seen" width="800" height="253"&gt;&lt;/a&gt;&lt;em&gt;&lt;small&gt;&lt;center&gt;Drâa River: Morocco’s longest river, where no water can be seen&lt;/center&gt;&lt;/small&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt; &lt;br&gt;
2030 is just around the corner, leaving us with less than 5 years until the first milestone of the &lt;a href="https://www.un.org/en/climatechange/paris-agreement" rel="noopener noreferrer"&gt;Paris Agreement&lt;/a&gt;. Unfortunately, we are far from being on track to meet the agreement's goal of limiting global temperature rise to a maximum of 2 degrees Celsius compared to pre-industrial levels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.greenit.fr/2020/10/06/4-des-emissions-de-ges/" rel="noopener noreferrer"&gt;Digital technologies are responsible for 4% of the Greenhouse gas (GHG) emissions&lt;/a&gt;, overtaking the aviation industry.&lt;/strong&gt; With increasing access to these technologies, especially in emerging countries, this figure is expected to rise exponentially. However our environmental impact extends beyond GHG emissions, and our digital habits impact various domains. The &lt;a href="https://www.stockholmresilience.org/research/planetary-boundaries.html" rel="noopener noreferrer"&gt;9 planetary boundaries&lt;/a&gt; illustrate what is at stakes: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6wvl9xu2w0uoh2jdh95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6wvl9xu2w0uoh2jdh95.png" alt="The 9 planetary boundaries evolution" width="800" height="354"&gt;&lt;/a&gt;&lt;em&gt;&lt;small&gt;&lt;center&gt;Evolution of the 9 planetary boundaries. Licenced under CC BY-NC-ND 3.0 (Credit: Azote for Stockholm Resilience Centre, Stockholm University. Based on Richardson et al. 2023, Steffen et al. 2015, and Rockström et al. 2009)&lt;/center&gt;&lt;/small&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most of the figures and reports regarding the impact of digital activities were published before generative AI became a thing. The substantial consumption of electricity, water and rare earth metals by AI systems makes any sustainability objective even more difficult to achieve and thus every sustainability effort even more important.&lt;/p&gt;

&lt;p&gt;In this article we will go over the goals of Green IT, the benefits of a sustainable IT strategy and how we started implementing this strategy at Migros Online.&lt;br&gt;
 &lt;/p&gt;

&lt;h3&gt;
  
  
  Why Green IT?
&lt;/h3&gt;

&lt;p&gt;Green IT is a discipline aiming at minimising the environmental impact of digital systems. For an online retailer such as Migros Online, IT systems might only be a small portion of the overall environmental footprint. So why do we consider it to be important?&lt;/p&gt;

&lt;p&gt;As the saying goes, &lt;em&gt;we have to start somewhere&lt;/em&gt;, and green IT is a good starting point because many potential mitigations are easy to enact. Employees will have a positive impact by adapting their digital practices. Raising awareness helps build a broader understanding of sustainability, which in turn leads to lower energy consumption and reduced operational costs.&lt;/p&gt;

&lt;p&gt;As AI becomes part of our daily routine, it is necessary to fully understand the impact of our actions to prevent the environmental impact from skyrocketing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Companies have power, companies have impact. If you have power and impact, hopefully you also take the responsibility that goes with that.&lt;/em&gt;&lt;br&gt;
— Feike Sybesma, Chair of the Supervisory Board, Royal Philips&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After gaining the support of management, a bunch of people ready to roll up their sleeves gathered: &lt;strong&gt;Migros Online’s Green IT Guild was born.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Where do we start?
&lt;/h3&gt;

&lt;p&gt;Since the beginning our objectives were clear: raise awareness among our peers and decrease the environmental impact of Migros Online digital systems.&lt;br&gt;
However, the path to achieving those goals was much fuzzier. How could we make this happen based on some ideas sketched on a Miro board? &lt;/p&gt;

&lt;p&gt;A little research made obvious that we needed a &lt;strong&gt;baseline&lt;/strong&gt;—calculating the environmental impact of an IT system is a complex task that we would not achieve on our own. The digital environmental footprint of a company includes more than just the software it builds and the infrastructure behind it. It also covers all the digital systems and devices the employees use for their daily work: laptops, monitors, internal softwares (business, HR, product related, development, communication, wiki, etc.).&lt;/p&gt;

&lt;p&gt;Additionally, when evaluating the impact of a system, we must consider the following three phases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🏭 Manufacturing: mining of earth metals, hardware production, etc&lt;/li&gt;
&lt;li&gt;💻 Usage: either by end-users or in data centers&lt;/li&gt;
&lt;li&gt;🚮 End-of-life: disposal or recycling of the devices&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;We cannot improve what we cannot measure&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Consequently we searched for experts, ideally a local company familiar with the Swiss market. We decided to partner with &lt;a href="https://mikujy.com/" rel="noopener noreferrer"&gt;Mikujy&lt;/a&gt;, whose CEO and founder is currently the only person in Switzerland certified as a Sustainable IT expert. Our first objective with Mikujy was to conduct an audit which would provide us with the needed baseline and with an actionable plan.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Our action plan
&lt;/h3&gt;

&lt;p&gt;The audit report in hand, we began addressing the most impactful items of the action plan: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Raising awareness&lt;/li&gt;
&lt;li&gt;Cloud processes and data storage&lt;/li&gt;
&lt;li&gt;Hardware renewal and purchases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  Raising awareness
&lt;/h4&gt;

&lt;p&gt;A key outcome of the audit was the need for awareness: empowered people make informed decisions. This can be achieved by providing training, impactful and relevant content, as well as communicating actively on Green IT topics.&lt;/p&gt;

&lt;p&gt;None of us being environment specialists, we decided to involve external parties and rely on existing large-scale events: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inspired by the &lt;a href="https://www.digitalcleanupday.org/" rel="noopener noreferrer"&gt;Digital cleanup day&lt;/a&gt;, we launched the “Digital cleanup week” at Migros Online, encouraging employees to declutter their mailboxes, sharepoint, and other online storage systems. This simple action revealed that deleted emails were, in fact, never removed from the global system.&lt;/li&gt;
&lt;li&gt;Mikujy presented a Green IT webinar open to every office employee&lt;/li&gt;
&lt;li&gt;We started publishing &lt;a href="https://www.isit-academy.org/" rel="noopener noreferrer"&gt;ISIT (Institute for Sustainable IT)&lt;/a&gt; online MOOC in our internal channels&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also started creating our own content and organising internal events: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We gave a talk about the environmental impacts of AI and provided recommendations for a more efficient usage&lt;/li&gt;
&lt;li&gt;We ran a sustainable IT challenge during our internal hack days&lt;/li&gt;
&lt;li&gt;Sustainability was one of the jugement criteria for the internal hack days projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We plan to continue promoting awareness by offering such content and challenges on a regular basis.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  Cloud processes and data storage
&lt;/h4&gt;

&lt;p&gt;The audit revealed a substantial volume of legacy data residing in the cloud, with &lt;strong&gt;357 TB&lt;/strong&gt; of data stored on GCP. Data engineers identified the most costly and environmentally harmful project, cleansed it from Migros Online’s data and processes, and returned it to its rightful owner. &lt;strong&gt;This allows us to save 3000 CHF per month&lt;/strong&gt; and reduce our carbon emissions by &lt;strong&gt;23t CO2eq&lt;/strong&gt;, which is 14% of our systems emissions.&lt;br&gt;
Moving forward, data engineers will revise the tracking data retention policy and evaluate other significant projects to further minimize their footprint.&lt;/p&gt;

&lt;p&gt;In addition to data cleanup, we can apply temporal and spatial shifting to our cloud processes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🕐 &lt;strong&gt;Temporal Shifting&lt;/strong&gt;: Running tasks when electricity is sourced from green energy, such as solar panels or wind turbines.&lt;/li&gt;
&lt;li&gt;☀️ &lt;strong&gt;Spatial Shifting&lt;/strong&gt;: Relocating tasks in regions powered by green energy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/sustainability/region-carbon" rel="noopener noreferrer"&gt;GCP provides a list of their cloud regions&lt;/a&gt; indicating the carbon-free energy ratio and grid carbon intensity. If a low-carbon region can meet our service needs, we should consider relocating our tasks there.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  Hardware renewal and purchases
&lt;/h4&gt;

&lt;p&gt;Renewing hardware at a certain frequency is highly desirable but has a significant impact. The largest part of the environmental impact of an end-user device occurs during manufacturing, while the impact during the usage phase is negligible:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftyyjvm79erzu7op14jdc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftyyjvm79erzu7op14jdc.png" alt="IT Footprint lifecycle by equipment" width="553" height="494"&gt;&lt;/a&gt;&lt;em&gt;&lt;small&gt;&lt;center&gt;IT footprint lifecycle by equipment, from Mikujy's audit report&lt;/center&gt;&lt;/small&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;"Outdated" laptops are resold to a refurbishing company. However, as long as we keep renewing hardware as frequently, new devices must be produced. No matter what happens once the warranty has expired: &lt;strong&gt;whether the laptop is refurbished or thrown away, it has to be replaced with a brand new one.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In our consumer-driven society, &lt;strong&gt;we need to distinguish the wish from the need.&lt;/strong&gt; Who hasn’t eagerly awaited the last MacBook release? Who is not thrilled about unpacking a brand new pristine device? Most of our laptops still run effectively after their warranty expires and we want to encourage our employees to make a sustainable choice by extending the lifespan of their laptop to: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;☁️ Reduce &lt;strong&gt;carbon emissions&lt;/strong&gt;: through research of 230 laptops the average CO² emissions during production of a new laptop is 331kg where the majority of emissions come from production and materials used. More here: &lt;a href="https://circularcomputing.com/news/carbon-footprint-laptop/" rel="noopener noreferrer"&gt;What Is The Carbon Footprint Of A Laptop?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🛠️ Reduce &lt;strong&gt;mining of earth metals&lt;/strong&gt;: half of the greenhouse gas (GHG) emissions in the production of the graphics cards comes from the mining of earth metals&lt;/li&gt;
&lt;li&gt;🌪️ Reduce &lt;strong&gt;pollution&lt;/strong&gt;: producing 1 ton of rare earth elements produces 2000 tons of toxic waste&lt;/li&gt;
&lt;li&gt;🌊 Save &lt;strong&gt;water&lt;/strong&gt;: Approximately 39 million liters of ultra pure water is used daily by an average chip manufacturing facility, which is equivalent to the water used by 125’000 Swiss households daily&lt;/li&gt;
&lt;li&gt;🚮 Avoid producing &lt;strong&gt;e-waste&lt;/strong&gt;: only 17% of global e-waste is documented to be collected and properly recycled. E-waste ends up in landfills where it releases chemicals contaminating water, soil and air, endangering people and wildlife. More about e-waste: &lt;a href="https://www.genevaenvironmentnetwork.org/resources/updates/the-growing-environmental-risks-of-e-waste/" rel="noopener noreferrer"&gt;The Growing Environmental Risks of E-Waste&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This table illustrates how our environmental footprint would decrease when extending the lifespan of laptops beyond the 3 year warranty:  &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Devices lifespan&lt;/th&gt;
&lt;th&gt;4 years&lt;/th&gt;
&lt;th&gt;5 years&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Carbon emissions&lt;/td&gt;
&lt;td&gt;-6 tons co2eq&lt;/td&gt;
&lt;td&gt;-10 tons co2eq&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Water consumption&lt;/td&gt;
&lt;td&gt;-14%&lt;/td&gt;
&lt;td&gt;-22%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Soils pollution&lt;/td&gt;
&lt;td&gt;-17%&lt;/td&gt;
&lt;td&gt;-26%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Abiotic resources consumption&lt;/td&gt;
&lt;td&gt;-4%&lt;/td&gt;
&lt;td&gt;-7%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Next Steps
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Website optimisations
&lt;/h4&gt;

&lt;p&gt;An audit of the 20 most visited pages on our website showed that its footprint is already quite low compared to our overall footprint. However, implementing eco-design principles where possible will be beneficial, and we are eager to dig into the the &lt;a href="https://patterns.greensoftware.foundation/catalog/web/" rel="noopener noreferrer"&gt;green software patterns&lt;/a&gt; recommended by the Green Software Foundation. In addition to reducing the ecological footprint of our website, eco-design principles  should&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;improve the user experience&lt;/strong&gt;: lighter and more efficient pages results in a smoother browsing experience&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;reduce⁠ hosting and maintenance costs&lt;/strong&gt;: less resources and less bandwidth should decrease associated costs&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Governance
&lt;/h4&gt;

&lt;p&gt;In addition to the KPIs provided by Mikujy, we are developing our own set of KPIs to effectively monitor our progress and impact within the company.&lt;br&gt;
We also intend to communicate more frequently about our actions and successes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Roadmap
&lt;/h4&gt;

&lt;p&gt;We drafted a roadmap running until 2027. This roadmap will evolve together with the outcome of the next internal audit we intend to run early next year.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Companies and their employees might be torn between AI and sustainability. However we cannot consider one at the expense of the other. AI has become part of most companies' toolbox, making the need for sustainable actions even more urgent. In addition to making our future possible, those sustainable actions will also reduce operational costs: &lt;strong&gt;usually making a smarter usage of resources leads to lower financial expenditures&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We strongly believe that by fostering awareness and implementing concrete actions we will make sustainability part of Migros Online core values.&lt;br&gt;
As the Green IT guild we hope to be an example within the company but we also hope to influence others in the industry.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  About the author
&lt;/h3&gt;

&lt;p&gt;My name is Aurélia and I’ve been at Migros Online for more than 10 years, first as a front-end engineer, then as a team lead, and today as a staff software engineer. &lt;br&gt;
I gained interest in the impact of digital technologies after attending the Devoxx conference in Antwerp in 2023. Having already made personal lifestyle changes to reduce my environmental impact, I sought ways to mitigate my professional impact and I am glad to lead the Green IT topic at Migros Online.&lt;/p&gt;

</description>
      <category>greenit</category>
      <category>sustainableit</category>
    </item>
  </channel>
</rss>
