<?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>Forem: Tomaz Lemos</title>
    <description>The latest articles on Forem by Tomaz Lemos (@tomazfernandes).</description>
    <link>https://forem.com/tomazfernandes</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%2Fuser%2Fprofile_image%2F49331%2F98258257-d506-435b-972d-de482c111ebf.jpg</url>
      <title>Forem: Tomaz Lemos</title>
      <link>https://forem.com/tomazfernandes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tomazfernandes"/>
    <language>en</language>
    <item>
      <title>What Happens Between @SqsListener and Your Method in Spring Cloud AWS SQS</title>
      <dc:creator>Tomaz Lemos</dc:creator>
      <pubDate>Mon, 20 Apr 2026 05:13:54 +0000</pubDate>
      <link>https://forem.com/tomazfernandes/what-happens-between-sqslistener-and-your-method-in-spring-cloud-aws-sqs-36e7</link>
      <guid>https://forem.com/tomazfernandes/what-happens-between-sqslistener-and-your-method-in-spring-cloud-aws-sqs-36e7</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://tomazfernandes.dev/posts/from-sqslistener-to-your-method/" rel="noopener noreferrer"&gt;tomazfernandes.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You write a method, add &lt;code&gt;@SqsListener&lt;/code&gt;, and messages start arriving. It is easy to see that as a simple annotation-to-method shortcut.&lt;/p&gt;

&lt;p&gt;In practice, &lt;strong&gt;Spring Cloud AWS SQS&lt;/strong&gt; assembles a listener container at startup based on that annotation, and at runtime the container holds an async pipeline between the queue and your code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That pipeline controls how messages are polled, dispatched, processed, and acknowledged.&lt;/strong&gt; It influences throughput, failure handling, and whether processing actually results in the message being removed from the queue.&lt;/p&gt;

&lt;p&gt;Making it look simple is exactly what a framework is supposed to do. &lt;strong&gt;Understanding what happens underneath gives you leverage for the hard parts.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This post builds a practical model of that system by showing how &lt;code&gt;@SqsListener&lt;/code&gt; annotations become configured containers, how the runtime pipeline shapes message outcomes, and which concrete components implement each stage.&lt;/p&gt;

&lt;p&gt;Companion resources&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/README.md" rel="noopener noreferrer"&gt;Architectural overview&lt;/a&gt;: A deeper reference with diagrams in the Spring Cloud AWS repository.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tomazfernandes/tomazfernandes-dev/tree/main/examples/from-sqslistener-to-your-method" rel="noopener noreferrer"&gt;Example project&lt;/a&gt;: Runnable scenarios for assembly, interception, error handling, and acknowledgement; also a playground for experimenting with the framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Table of contents&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two phases: assembly and runtime&lt;/li&gt;
&lt;li&gt;Assembly: how listener behavior is built&lt;/li&gt;
&lt;li&gt;
Runtime: how the container pipeline shapes message outcomes

&lt;ul&gt;
&lt;li&gt;Ingress: polling under backpressure&lt;/li&gt;
&lt;li&gt;Dispatch: delivery strategy&lt;/li&gt;
&lt;li&gt;Processing: handling the message&lt;/li&gt;
&lt;li&gt;Acknowledgement: turning processing into deletion&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The async runtime model&lt;/li&gt;
&lt;li&gt;Seeing it in action&lt;/li&gt;
&lt;li&gt;Takeaways&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Two phases: assembly and runtime
&lt;/h2&gt;

&lt;p&gt;To start building this model, the first useful distinction is between &lt;strong&gt;assembly&lt;/strong&gt; and &lt;strong&gt;runtime&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose you write this listener method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SqsListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"orders-queue"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderCreated&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;strong&gt;assembly phase&lt;/strong&gt;, the framework turns that method into a configured container with the components that define its runtime behavior. In the &lt;strong&gt;runtime phase&lt;/strong&gt;, messages begin to flow through that container’s asynchronous pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assembly: how listener behavior is built
&lt;/h2&gt;

&lt;p&gt;The assembly phase follows a common pattern in Spring messaging projects, with the work split across two parts of Spring startup.&lt;/p&gt;

&lt;p&gt;During bean post-processing, &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/annotation/SqsListenerAnnotationBeanPostProcessor.java" rel="noopener noreferrer"&gt;&lt;code&gt;SqsListenerAnnotationBeanPostProcessor&lt;/code&gt;&lt;/a&gt; &lt;strong&gt;detects &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/annotation/SqsListener.java" rel="noopener noreferrer"&gt;&lt;code&gt;@SqsListener&lt;/code&gt;&lt;/a&gt; annotations and turns each one into an &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/config/Endpoint.java" rel="noopener noreferrer"&gt;&lt;code&gt;Endpoint&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; that describes the listener: queues, listener method, and configuration. These endpoints are then collected by the &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/config/EndpointRegistrar.java" rel="noopener noreferrer"&gt;&lt;code&gt;EndpointRegistrar&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At a high level, the first part of the assembly flow looks like this:&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%2Ff2ee1cotoxtpsuij06tl.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%2Ff2ee1cotoxtpsuij06tl.png" alt="Diagram 1" width="800" height="53"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, the listener has been described as an &lt;strong&gt;endpoint&lt;/strong&gt;. The next step is to turn that endpoint into a container.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;afterSingletonsInstantiated()&lt;/code&gt; is invoked, the &lt;code&gt;EndpointRegistrar&lt;/code&gt; processes the collected endpoints. For each endpoint, it resolves the &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/config/SqsMessageListenerContainerFactory.java" rel="noopener noreferrer"&gt;&lt;code&gt;MessageListenerContainerFactory&lt;/code&gt;&lt;/a&gt; to use, creates the corresponding container, and registers it in the &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/MessageListenerContainerRegistry.java" rel="noopener noreferrer"&gt;&lt;code&gt;MessageListenerContainerRegistry&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The second part of the assembly flow looks like this:&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%2F7l33j8ft84itpozjrpw5.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%2F7l33j8ft84itpozjrpw5.png" alt="Diagram 2" width="800" height="46"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By the time startup completes, &lt;strong&gt;each &lt;code&gt;@SqsListener&lt;/code&gt; method is represented by a message listener container&lt;/strong&gt; with its own identity, queue bindings, and runtime configuration.&lt;/p&gt;

&lt;p&gt;To customize the assembly phase, for example, setting a default factory or configuring endpoint registration, &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/config/SqsListenerConfigurer.java" rel="noopener noreferrer"&gt;&lt;code&gt;SqsListenerConfigurer&lt;/code&gt;&lt;/a&gt; is the main entry point. It provides access to the &lt;code&gt;EndpointRegistrar&lt;/code&gt; before endpoints are processed into containers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Runtime: how the container pipeline shapes message outcomes
&lt;/h2&gt;

&lt;p&gt;If you have used other Spring messaging projects such as Spring for Apache Kafka, the assembly side of this model will feel familiar. &lt;strong&gt;The runtime phase is where Spring Cloud AWS SQS takes a different approach.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Typically, runtime behavior in these projects is centered in a single container class. In Spring Cloud AWS SQS, &lt;strong&gt;the container runs a composable asynchronous pipeline&lt;/strong&gt; built around the AWS SDK’s &lt;a href="https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/SqsAsyncClient.html" rel="noopener noreferrer"&gt;&lt;code&gt;SqsAsyncClient&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At runtime, the focus shifts to how messages enter the container, move through the processing pipeline, and eventually get deleted or made visible again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That gives us a runtime model built around four responsibilities&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ingress&lt;/strong&gt;: balance polling and backpressure as messages enter the container&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dispatch&lt;/strong&gt;: route polled messages into processing according to the delivery strategy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Processing&lt;/strong&gt;: run the message through the processing pipeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Acknowledgement&lt;/strong&gt;: decide and execute message deletion based on processing outcomes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this level, the runtime flow looks like this:&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%2Fj49rihfp1ofqhkxjktww.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%2Fj49rihfp1ofqhkxjktww.png" alt="Diagram 3" width="739" height="94"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/MessageListenerContainer.java" rel="noopener noreferrer"&gt;&lt;code&gt;MessageListenerContainer&lt;/code&gt;&lt;/a&gt; uses the &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/ContainerComponentFactory.java" rel="noopener noreferrer"&gt;&lt;code&gt;ContainerComponentFactory&lt;/code&gt;&lt;/a&gt; to create the components used in these stages at startup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ingress: polling under backpressure
&lt;/h3&gt;

&lt;p&gt;At the ingress boundary, &lt;strong&gt;throughput depends on the balance between polling and backpressure&lt;/strong&gt;. This is one of the main controls over resource usage: if ingress is too permissive, the application can consume too much memory or compute resources; if it is too restrictive, messages can accumulate in the queue even though the application could safely handle more messages.&lt;/p&gt;

&lt;p&gt;The ingress cycle looks like this at a high level:&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%2Fyq1zm6jufrj9r95lexsi.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%2Fyq1zm6jufrj9r95lexsi.png" alt="Diagram 4" width="800" height="65"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Spring Cloud AWS SQS, the &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/source/MessageSource.java" rel="noopener noreferrer"&gt;&lt;code&gt;MessageSource&lt;/code&gt;&lt;/a&gt; controls ingress into the pipeline and converts SQS messages into Spring &lt;code&gt;Message&lt;/code&gt; instances. It keeps polling as long as the &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/backpressure/BackPressureHandler.java" rel="noopener noreferrer"&gt;&lt;code&gt;BackPressureHandler&lt;/code&gt;&lt;/a&gt; signals that more messages can be admitted in flight.&lt;/p&gt;

&lt;p&gt;Polling behavior is configurable, including batch size and long polling settings that balance throughput and efficiency. As long as backpressure allows and the queue has enough messages available, &lt;strong&gt;multiple poll calls can stay in flight in parallel&lt;/strong&gt;. When a queue is empty, the framework falls back to a single-poll model for that queue. As messages finish processing, room opens up and the container can keep polling.&lt;/p&gt;

&lt;p&gt;By default, &lt;strong&gt;backpressure is mainly driven by internal in-flight capacity&lt;/strong&gt;, but the mechanism is composable and can be extended with other signals such as downstream queue pressure or service availability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dispatch: delivery strategy
&lt;/h3&gt;

&lt;p&gt;Once messages enter the container, the next question is how they should be delivered for processing. &lt;strong&gt;Delivery rules vary by queue and listener type&lt;/strong&gt;: standard queues can fan out work in parallel; batch listeners may want one or more batches delivered as a single unit; FIFO queues need dispatch that preserves ordering while still allowing parallelism across message groups.&lt;/p&gt;

&lt;p&gt;In Spring Cloud AWS SQS, &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/sink/MessageSink.java" rel="noopener noreferrer"&gt;&lt;code&gt;MessageSink&lt;/code&gt;&lt;/a&gt; components are responsible for applying that strategy reliably. When the container starts, the &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/ContainerComponentFactory.java" rel="noopener noreferrer"&gt;&lt;code&gt;ContainerComponentFactory&lt;/code&gt;&lt;/a&gt; selects and composes sink implementations based on queue semantics and configuration. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A standard queue listener gets a &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/sink/FanOutMessageSink.java" rel="noopener noreferrer"&gt;&lt;code&gt;FanOutMessageSink&lt;/code&gt;&lt;/a&gt;, which delivers each message to the processing pipeline in parallel. This is why a single &lt;code&gt;@SqsListener&lt;/code&gt; can process multiple messages concurrently without any threading configuration.&lt;/li&gt;
&lt;li&gt;A FIFO queue listener gets a &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/sink/adapter/MessageGroupingSinkAdapter.java" rel="noopener noreferrer"&gt;&lt;code&gt;MessageGroupingSinkAdapter&lt;/code&gt;&lt;/a&gt; composed with an &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/sink/OrderedMessageSink.java" rel="noopener noreferrer"&gt;&lt;code&gt;OrderedMessageSink&lt;/code&gt;&lt;/a&gt;, which partitions messages by group and enforces sequential delivery within each group, preserving ordering while still allowing parallelism across groups.&lt;/li&gt;
&lt;li&gt;A batch listener gets a &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/sink/BatchMessageSink.java" rel="noopener noreferrer"&gt;&lt;code&gt;BatchMessageSink&lt;/code&gt;&lt;/a&gt;, which delivers them as a single unit to the listener method.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Sinks and adapters share the same interface&lt;/strong&gt; and can be composed without changing the upstream source or downstream processing pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Processing: handling the message
&lt;/h3&gt;

&lt;p&gt;Message processing involves several connected concerns. A message may need to be enriched with headers, failures in listener logic may trigger fallback behavior, intermediate outcomes may need to be observed, and the result of these steps determines whether the message should be acknowledged or redelivered.&lt;/p&gt;

&lt;p&gt;In Spring Cloud AWS SQS, &lt;strong&gt;the message processing stage is structured as an inner processing pipeline&lt;/strong&gt;. Each stage in that pipeline is built around a user-provided component that can influence the next.&lt;/p&gt;

&lt;p&gt;At a high level, the processing pipeline is structured like this:&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%2Ftmbw732ls0ksjkx66hfr.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%2Ftmbw732ls0ksjkx66hfr.png" alt="Diagram 5" width="800" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each stage can observe, transform, or react to the current processing state before passing control to the next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/interceptor/MessageInterceptor.java" rel="noopener noreferrer"&gt;&lt;code&gt;MessageInterceptor&lt;/code&gt;&lt;/a&gt; (before): can enrich the message with headers or validate preconditions before the listener runs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/MessageListener.java" rel="noopener noreferrer"&gt;&lt;code&gt;MessageListener&lt;/code&gt;&lt;/a&gt;: invokes the method behind &lt;code&gt;@SqsListener&lt;/code&gt;, where the actual business logic runs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/errorhandler/ErrorHandler.java" rel="noopener noreferrer"&gt;&lt;code&gt;ErrorHandler&lt;/code&gt;&lt;/a&gt;: catches listener exceptions and decides whether to swallow, transform, or propagate them, which directly affects whether the message gets acknowledged or redelivered&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/interceptor/MessageInterceptor.java" rel="noopener noreferrer"&gt;&lt;code&gt;MessageInterceptor&lt;/code&gt;&lt;/a&gt; (after): sees the final outcome including any exception, making it a natural point for logging, metrics, or cleanup&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/acknowledgement/handler/AcknowledgementHandler.java" rel="noopener noreferrer"&gt;&lt;code&gt;AcknowledgementHandler&lt;/code&gt;&lt;/a&gt;: bridges the processing result into the acknowledgement stage, deciding whether the message should be deleted or left for redelivery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While the pipeline is built on an asynchronous foundation, &lt;strong&gt;the framework accepts combinations of synchronous and asynchronous variants of these components&lt;/strong&gt; without extra configuration. Asynchronous variants enable an end-to-end non-blocking pipeline, while synchronous ones are adapted on the fly to a message-per-thread or batch-per-thread model.&lt;/p&gt;

&lt;p&gt;Once the final stage of the processing pipeline completes, backpressure capacity is released. &lt;strong&gt;The message then either proceeds to acknowledgement or becomes visible again after the visibility timeout.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Acknowledgement: turning processing into deletion
&lt;/h3&gt;

&lt;p&gt;As the message moves through the previous stages, it still sits in the queue, invisible until the visibility timeout expires. &lt;strong&gt;Acknowledgement is the stage that turns processing results into actual deletion.&lt;/strong&gt; That mechanism has to balance several cross-cutting concerns at once: efficiency, throughput, ordering guarantees, observability, and extensibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Acknowledgement performance must keep up with polling and processing throughput.&lt;/strong&gt; If it falls behind, completed messages can accumulate waiting for deletion. That increases the chance of visibility timeouts expiring before the delete call happens, which can lead to redelivery, duplicate work, and degraded performance.&lt;/p&gt;

&lt;p&gt;In Spring Cloud AWS SQS, the acknowledgement flow is split across four main components:&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%2F0ngoyisy5n1rx9y054in.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%2F0ngoyisy5n1rx9y054in.png" alt="Diagram 6" width="800" height="61"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/acknowledgement/handler/AcknowledgementHandler.java" rel="noopener noreferrer"&gt;&lt;code&gt;AcknowledgementHandler&lt;/code&gt;&lt;/a&gt; in the final stage of the processing pipeline decides whether a message should proceed to deletion or stay in the queue for redelivery. If it should be acknowledged, &lt;strong&gt;the &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/acknowledgement/AcknowledgementProcessor.java" rel="noopener noreferrer"&gt;&lt;code&gt;AcknowledgementProcessor&lt;/code&gt;&lt;/a&gt; applies a strategy that varies by queue type&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;standard queues&lt;/strong&gt;, &lt;strong&gt;acknowledgements are batched by default and executed in parallel&lt;/strong&gt; based on configurable batch thresholds and scheduling.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;FIFO queues&lt;/strong&gt;, acknowledgements respect message-group ordering: &lt;strong&gt;they can run in ordered parallel batches across groups&lt;/strong&gt;, or &lt;strong&gt;synchronously after each message&lt;/strong&gt; when out-of-order reprocessing must be avoided.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/acknowledgement/AcknowledgementExecutor.java" rel="noopener noreferrer"&gt;&lt;code&gt;AcknowledgementExecutor&lt;/code&gt;&lt;/a&gt; issues the actual delete calls, which can succeed fully, fail partially, or fail completely. The &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/acknowledgement/AcknowledgementResultCallback.java" rel="noopener noreferrer"&gt;&lt;code&gt;AcknowledgementResultCallback&lt;/code&gt;&lt;/a&gt; observes the outcome, enabling custom recovery strategies as well as instrumentation. When partial failures occur, &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/SqsAcknowledgementException.java" rel="noopener noreferrer"&gt;&lt;code&gt;SqsAcknowledgementException&lt;/code&gt;&lt;/a&gt; exposes which acknowledgements succeeded and which failed, so the callback can inspect and react to each case.&lt;/p&gt;

&lt;h2&gt;
  
  
  The async runtime model
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;At runtime, SQS interaction is mostly I/O-bound&lt;/strong&gt;: polling is a network call, and acknowledgement eventually becomes a delete request back to SQS. In a synchronous design, threads would spend much of their time waiting on those operations.&lt;/p&gt;

&lt;p&gt;Spring Cloud AWS SQS is built on &lt;a href="https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/SqsAsyncClient.html" rel="noopener noreferrer"&gt;&lt;code&gt;SqsAsyncClient&lt;/code&gt;&lt;/a&gt;, where operations such as &lt;code&gt;receiveMessage()&lt;/code&gt; and &lt;code&gt;deleteMessageBatch()&lt;/code&gt; return &lt;code&gt;CompletableFuture&lt;/code&gt;. That lets the container track in-flight work without tying progress to blocked threads. &lt;strong&gt;Internally, &lt;code&gt;CompletableFuture&lt;/code&gt; composition gives the framework declarative control over parallelism and non-blocking orchestration throughout the pipeline.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The framework provides both synchronous and asynchronous variants of message processing components, and users can provide their own &lt;code&gt;TaskExecutor&lt;/code&gt; for full control of what threads their code runs on. &lt;strong&gt;This threading model allows users to write regular blocking code without worrying about the underlying async complexity&lt;/strong&gt;, and choose where and when to work with asynchronous code when it fits their use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seeing it in action
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/tomazfernandes/tomazfernandes-dev/tree/main/examples/from-sqslistener-to-your-method" rel="noopener noreferrer"&gt;example project&lt;/a&gt; makes these stages concrete through a set of toggleable scenarios. It runs with Docker only, so you do not need a local Java setup.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;make run-assembly&lt;/code&gt;: logs container metadata at startup&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;make run-interceptor&lt;/code&gt;: shows before/after interceptor hooks around each message&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;make run-error-handler&lt;/code&gt;: shows failure handling and SQS redelivery&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;make run-ack-callback&lt;/code&gt;: shows acknowledgement results after delete requests&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;make run-all&lt;/code&gt;: runs all scenarios together&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;Spring Cloud AWS SQS aims at making &lt;code&gt;@SqsListener&lt;/code&gt; simple to use, while underneath it is transparently assembling a container that handles ingress, dispatch, processing, and acknowledgement at runtime. &lt;strong&gt;Each of these concerns is mapped to a dedicated set of components&lt;/strong&gt; that can be swapped or extended to adapt to queue semantics and user requirements.&lt;/p&gt;

&lt;p&gt;With that model in mind, each layer gives a clear starting point for understanding or changing behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To customize how listeners are built and configured, the &lt;strong&gt;assembly phase&lt;/strong&gt; and its components are the first candidates.&lt;/li&gt;
&lt;li&gt;If throughput is not matching expectations, the relevant layer is usually &lt;strong&gt;ingress and backpressure&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;To observe, enrich, or react to messages at different points, the &lt;strong&gt;processing pipeline and its extension points&lt;/strong&gt; are the place to start.&lt;/li&gt;
&lt;li&gt;If messages are not being deleted or getting redelivered unexpectedly, that naturally points to the &lt;strong&gt;acknowledgement flow&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the full architectural reference, including the original diagrams and component map, see the &lt;a href="https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sqs/README.md" rel="noopener noreferrer"&gt;architectural overview&lt;/a&gt;. For the user-facing module reference, including configuration and runtime options, see the &lt;a href="https://docs.awspring.io/spring-cloud-aws/docs/4.0.0/reference/html/index.html#sqs-integration" rel="noopener noreferrer"&gt;Spring Cloud AWS SQS documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>spring</category>
      <category>aws</category>
      <category>sqs</category>
    </item>
    <item>
      <title>An IoC pattern to avoid repetitive if statements</title>
      <dc:creator>Tomaz Lemos</dc:creator>
      <pubDate>Tue, 31 Dec 2019 05:30:10 +0000</pubDate>
      <link>https://forem.com/tomazlemos/let-s-talk-tradeoffs-between-an-ioc-factory-and-a-traditional-if-based-one-nhp</link>
      <guid>https://forem.com/tomazlemos/let-s-talk-tradeoffs-between-an-ioc-factory-and-a-traditional-if-based-one-nhp</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fencrypted-tbn0.gstatic.com%2Fimages%3Fq%3Dtbn%253AANd9GcQ9ndTpjh9i2J9-ASUgUm80Fo95T1ax82ctvG6c9x-EHuMGFXQv" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fencrypted-tbn0.gstatic.com%2Fimages%3Fq%3Dtbn%253AANd9GcQ9ndTpjh9i2J9-ASUgUm80Fo95T1ax82ctvG6c9x-EHuMGFXQv" alt="Clean factory"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my &lt;a href="https://dev.to/tomazlemos/keeping-your-code-clean-by-sweeping-out-if-statements-4in8"&gt;previous post&lt;/a&gt; I shared two patterns that helped avoiding repetitive if statements, and we had a great discussion about imperative, if-based styles and declarative ones.&lt;/p&gt;

&lt;p&gt;In this post I want to share another pattern which I think is great to expand our programming toolset.&lt;/p&gt;

&lt;p&gt;I'll address some of the tradeoffs I see in it against the more traditional if-based approach, and I'd really like you to tag along and share what pros and cons you see in them in the comments. Let's do this together?&lt;/p&gt;

&lt;p&gt;The examples are in Java but it should translate well to any other OO language.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you prefer, skip right to the code&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The pattern
&lt;/h3&gt;

&lt;p&gt;This pattern is based on Java's Spring framework, and it's main point is that it offloads from the main class to the instances themselves the responsibility of knowing whether or not it is capable of, or should, handle a specific input, thus inverting the flow control.&lt;/p&gt;

&lt;p&gt;It's widely used by Spring to find out which converter or mapper to use for a given input. Part of its value derives from being able to use unknown custom implementations of the interfaces provided by the user, but I do find value in using it for known types as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  The context
&lt;/h3&gt;

&lt;p&gt;For context, let's say we have an application that has to handle lots of different kinds of data, based on a what's the data's url’s country passed as a path parameter. Something like &lt;code&gt;https://dev.to/myapp/data?url=http://www.google.com.br&lt;/code&gt; (I didn't escape the path param's url to make it clearer).&lt;/p&gt;

&lt;p&gt;The application's job would be to retrieve the IncomingData from the url, and then pass it to the proper DataHandler provided by the Selector.&lt;/p&gt;

&lt;p&gt;We might have a DataHandler interface that would be implemented by many classes, such as BrazilianDataHandler, SpanishDataHandler, FrenchDataHandler, etc, and a Selector to provide the correct instances.&lt;/p&gt;

&lt;p&gt;Looking at the code should make it more clear, so let's do just that.&lt;br&gt;
&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The usual if-based approach
&lt;/h3&gt;

&lt;p&gt;Let’s start with an interface such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ProcessedData&lt;/span&gt; &lt;span class="nf"&gt;handleData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IncomingData&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A concrete implementation of the interface might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Other countries' handlers could be implemented the same way&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BrazilianDataHandler&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ProcessedData&lt;/span&gt; &lt;span class="nf"&gt;handleData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IncomingData&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// do stuff;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s add the if-based selector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataHandlerSelector&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="n"&gt;brazilianDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="n"&gt;argentinianDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="n"&gt;australianDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="n"&gt;frenchDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Lots of other countries...&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;DataHandlerSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BrazilianDataHandler&lt;/span&gt; &lt;span class="n"&gt;brazilianDataHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                        &lt;span class="nc"&gt;ArgentinianDataHandler&lt;/span&gt; &lt;span class="n"&gt;argentinianDataHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                        &lt;span class="nc"&gt;AustralianDataHandler&lt;/span&gt; &lt;span class="n"&gt;australianDataHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                        &lt;span class="nc"&gt;FrenchDataHandler&lt;/span&gt; &lt;span class="n"&gt;frenchDataHandler&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;brazilianDataHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;brazilianDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;argentinianDataHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argentinianDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;australianDataHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;australianDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;frenchDataHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;frenchDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="nf"&gt;obtainDataHandlerFor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Url is null!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".br"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;brazilianDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".ar"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argentinianDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".au"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;australianDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".fr"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;frenchDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Lots of other countries...&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Url not supported: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Assert&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;notNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;errorMessageSupplier&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorMessageSupplier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then a factory to instantiate the selector and it’s dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataHandlerSelectorFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;DataHandlerSelector&lt;/span&gt; &lt;span class="nf"&gt;createSelector&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DataHandlerSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BrazilianDataHandler&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArgentinianDataHandler&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AustralianDataHandler&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FrenchDataHandler&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple, right? This pattern has the great benefit of having a straightforward logic, which often leads to easier reasoning as it's a very common pattern.&lt;/p&gt;

&lt;p&gt;There are some drawbacks I see, tough:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Selector logic has to be modified every time we need to include another country&lt;/li&gt;
&lt;li&gt;Lots of language specific words and symbols obscuring the business logic, which would be the condition - handler correlation&lt;/li&gt;
&lt;li&gt;It tends to get huge over time, with lots of copying and pasting, possibly leading to bugs and poorer comprehensibility and maintainability&lt;/li&gt;
&lt;li&gt;It is a single point of failure, meaning if some logic gets messed up you can mess several or all countries at once (think if you accidentally delete an "else if" line and the line above it...)&lt;/li&gt;
&lt;li&gt;You may need to see both the Selector and the implementation class to get the big picture about what the implementation class does&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What do you think, do you agree with these points?&lt;/p&gt;

&lt;h3&gt;
  
  
  The IoC Selector pattern
&lt;/h3&gt;

&lt;p&gt;In this Selector pattern the interface gets a new shouldHandle method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ProcessedData&lt;/span&gt; &lt;span class="nf"&gt;handleData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IncomingData&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;shouldHandle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the Selector becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataHandlerSelector&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dataHandlerList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;DataHandlerSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DataHandler&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="n"&gt;dataHandlers&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;dataHandlerList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataHandlers&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="nf"&gt;obtainDataHandlerFor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Url is null!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dataHandlerList&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;shouldHandle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findFirst&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Url not supported: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// You can also check if more than one instance has been found by using List.size() on the list returned by a collect(toList()) at the end of the stream call.&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Assert&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;notNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;errorMessageSupplier&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorMessageSupplier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take a look at a sample implementation of the new interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BrazilianDataHandler&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ProcessedData&lt;/span&gt; &lt;span class="nf"&gt;handleData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IncomingData&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// do stuff;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;shouldHandle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".br"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example we have changed the centralized approach of the first Selector into a decentralized approach, handing down to the implementations the responsibility of knowing whether or not it should act on a given input.&lt;/p&gt;

&lt;p&gt;Overall, I like designs that forces us to make our intentions clear and makes it easy to figure out which are the business rules and exceptional cases.&lt;/p&gt;

&lt;p&gt;I think this approach brings as advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No modification needed in the Selector class when adding a new implementation&lt;/li&gt;
&lt;li&gt;The condition and the logic itself are together, allowing for better clarity and cohesion&lt;/li&gt;
&lt;li&gt;No cluttered language specific words clouding business rules&lt;/li&gt;
&lt;li&gt;No copying and pasting&lt;/li&gt;
&lt;li&gt;No single point of failure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And as drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We loose sight of the greater picture of conditions&lt;/li&gt;
&lt;li&gt;May take longer to reason about the first time you see it&lt;/li&gt;
&lt;li&gt;One condition may interfere with the other if it is greedy and comes before the other&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What about you, can you see any other advantages or drawbacks?&lt;/p&gt;

&lt;h3&gt;
  
  
  The wicked new requirement
&lt;/h3&gt;

&lt;p&gt;Ok, now a new requirement has arrived, and there are some classes that will have to be verified first. &lt;/p&gt;

&lt;p&gt;In this case we will have the .gov and .org urls that have to be addressed by special handlers regardless of their countries (I know that doesn't make that much sense but just bear with me 😄).&lt;/p&gt;

&lt;p&gt;The if-based Selector's implementation might be something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataHandlerSelector&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Constructor, properties and Assert class omitted for brevity&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="nf"&gt;obtainDataHandlerFor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Url is null!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// .gov and .org must come first&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".gov"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;governmentDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".org"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;organizationDataHandler&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".br"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;brazilianDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".ar"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argentinianDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".au"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;australianDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".fr"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;frenchDataHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Lots of other countries...&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Url not supported!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dataHandlerToReturn&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Easy to implement right? But the way I see it, in this case the new added business rule is enforced only by that comment, which may or may not stand the test of time. We might be able to extract a method to put the first two ones in a different place but I do begin to smell spaghetti... We can discuss better solutions for this pattern in the comments if you have any.&lt;/p&gt;

&lt;p&gt;And what about with the IoC Selector pattern?&lt;/p&gt;

&lt;p&gt;Well, we might just create two lists:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataHandlerSelector&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;firstHandlersList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;secondHandlersList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;DataHandlerSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GovernmentDataHandler&lt;/span&gt; &lt;span class="n"&gt;governmentDataHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                              &lt;span class="nc"&gt;OrganizationDataHandler&lt;/span&gt; &lt;span class="n"&gt;organisationDataHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                              &lt;span class="nc"&gt;BrazilianDataHandler&lt;/span&gt; &lt;span class="n"&gt;brazilianDataHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                              &lt;span class="nc"&gt;ArgentinianDataHandler&lt;/span&gt; &lt;span class="n"&gt;argentinianDataHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                              &lt;span class="nc"&gt;AustralianDataHandler&lt;/span&gt; &lt;span class="n"&gt;australianDataHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                              &lt;span class="nc"&gt;FrenchDataHandler&lt;/span&gt; &lt;span class="n"&gt;frenchDataHandler&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="n"&gt;firstHandlersList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;governmentDataHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;organisationDataHandler&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;secondHandlersList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;brazilianDataHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;argentinianDataHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;australianDataHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                  &lt;span class="n"&gt;frenchDataHandler&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;


    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="nf"&gt;obtainDataHandlerFor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Url is null!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;firstHandlersList&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;shouldHandle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findFirst&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseGet&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getFromSecondHandlerList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt; &lt;span class="nf"&gt;getFromSecondHandlerList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;secondHandlersList&lt;/span&gt;
                           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;shouldHandle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findFirst&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Url not supported!"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Assert&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;notNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;errorMessageSupplier&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorMessageSupplier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It sure is easier to code the first pattern, but in which do you think the new business rule is more clear? In my option, dealing with well reasoned patterns and interfaces usually leads to more reflection than action, and thus probably to better, more maintainable code, and with a clearer set of business rules and responsibilities.&lt;/p&gt;

&lt;p&gt;But, of course, every pattern has its day of glory when applied in the proper situation, right?&lt;/p&gt;

&lt;p&gt;So, what do you think are the pros and cons of each pattern? What points I made do you agree or disagree with? Is there another requirement change we should compare the two patterns against?&lt;/p&gt;

&lt;p&gt;Let's address this in the comments!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks a lot to &lt;a class="mentioned-user" href="https://dev.to/wrldwzrd89"&gt;@wrldwzrd89&lt;/a&gt;, &lt;a class="mentioned-user" href="https://dev.to/khtony"&gt;@khtony&lt;/a&gt;, &lt;a class="mentioned-user" href="https://dev.to/bertilmuth"&gt;@bertilmuth&lt;/a&gt; and @t_dardzhonov for the early feedback on this post!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cleancode</category>
      <category>example</category>
      <category>designpatterns</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Keeping your code clean by sweeping out "if" statements</title>
      <dc:creator>Tomaz Lemos</dc:creator>
      <pubDate>Fri, 27 Dec 2019 22:11:14 +0000</pubDate>
      <link>https://forem.com/tomazlemos/keeping-your-code-clean-by-sweeping-out-if-statements-4in8</link>
      <guid>https://forem.com/tomazlemos/keeping-your-code-clean-by-sweeping-out-if-statements-4in8</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.thespruce.com%2Fthmb%2FgBebAPbDF0FCNqjJVbekBHoVJxs%3D%2F960x0%2Ffilters%3Ano_upscale%28%29%3Amax_bytes%28150000%29%3Astrip_icc%28%29%2Fcleaning-floor_t20_ko9eW4-1d1f250c4c0848edbc4542f94f3c250e.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.thespruce.com%2Fthmb%2FgBebAPbDF0FCNqjJVbekBHoVJxs%3D%2F960x0%2Ffilters%3Ano_upscale%28%29%3Amax_bytes%28150000%29%3Astrip_icc%28%29%2Fcleaning-floor_t20_ko9eW4-1d1f250c4c0848edbc4542f94f3c250e.jpg" alt="Mugging your way towards cleaner code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the most common things I see around that I think makes code more difficult to read is the overuse of "if" statements. It’s one of the first programming tools we learn, and it is usually when we learn that the computer can do pretty much anything we like, “if” we use those statements right. Following usually are long ours of printfs and debugging and trying to figure out why the program isn’t getting into that third nested "if" as we're sure it would do! That’s how many of us have approached programming, and that’s what many of us have grown used to.&lt;/p&gt;

&lt;p&gt;As I studied more about code design and best practices I began noticing how using lots of if statements could be an anti-pattern, making the code worse to read, debug and maintain. And so out I went to find alternative patterns to those if statements, and I think the patterns I've found have improved my code’s readability and maintainability.&lt;/p&gt;

&lt;p&gt;Of course there’s no silver bullet and any pattern should be used where it makes sense. I think it’s important for us developers to have options when attempting to write good quality code.&lt;/p&gt;

&lt;p&gt;To illustrate this point I’ll share two simple examples, and I hope to hear your thoughts on the matter in the comments.&lt;/p&gt;

&lt;p&gt;First let's see the example where we have to handle an incoming message from outside our application boundaries, and the object contains a string property specifying a type. It might be an error type from a mass email marketing, and we would have to translate that to our own domain’s error type.&lt;/p&gt;

&lt;p&gt;Usually I see that implemented like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;ErrorType&lt;/span&gt; &lt;span class="nf"&gt;translateErrorType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;errorString&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Undetermined"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorString&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;UNKNOWN_ERROR&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"NoEmail"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorString&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;INVALID_RECIPIENT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MessageTooLarge"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorString&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;INVALID_CONTENT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ContentRejected"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorString&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;INVALID_CONTENT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AttachmentRejected"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorString&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;INVALID_CONTENT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//      } else if (...)&lt;/span&gt;

        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error type not supported: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;errorTypeString&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You see where this is going, right? It could be a switch statement, and it would be just as cluttered, with much more language specific words than actual business domain language.&lt;/p&gt;

&lt;p&gt;There are a number of approaches to getting rid of this kind of “if” entanglement, but I guess the simplest one is the use of a map.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ErrorTypeTranslator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ErrorType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;errorTypeMap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;errorTypeMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"Undetermined"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;UNKNOWN_ERROR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"NoEmail"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;INVALID_RECIPIENT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"MessageTooLarge"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;INVALID_CONTENT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"ContentRejected"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;INVALID_CONTENT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"AttachmentRejected"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;INVALID_CONTENT&lt;/span&gt;
&lt;span class="c1"&gt;//          (…)&lt;/span&gt;
            &lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ErrorType&lt;/span&gt; &lt;span class="nf"&gt;translateErrorType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;errorTypeString&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;requireNonNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorTypeMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorTypeString&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                    &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Error type not supported: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;errorTypeString&lt;/span&gt; 
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;See the difference? Now the business logic is front and center, and any developer approaching this class should be able to very easily understand what it does and change it should it be needed. Lots of language specific words and symbols have disappeared making way for a much nicer, cleaner and less error prone code.&lt;/p&gt;

&lt;p&gt;This kind of pattern is also very good for simple factories, where you can have a map of singletons, or even suppliers as values. For example, let’s say you have to return a handler bean based on an enum retrieved from the database.&lt;/p&gt;

&lt;p&gt;What I usually see is something like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IntegrationHandlerFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;EmailIntegrationHandler&lt;/span&gt; &lt;span class="n"&gt;emailHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;SMSIntegrationHandler&lt;/span&gt; &lt;span class="n"&gt;smsHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PushIntegrationHandler&lt;/span&gt; &lt;span class="n"&gt;pushHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;IntegrationHandlerFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EmailIntegrationHandler&lt;/span&gt; &lt;span class="n"&gt;emailHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                              &lt;span class="nc"&gt;SMSIntegrationHandler&lt;/span&gt; &lt;span class="n"&gt;smsHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                              &lt;span class="nc"&gt;PushIntegrationHandler&lt;/span&gt; &lt;span class="n"&gt;pushHandler&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;emailHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;emailHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;smsHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;smsHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pushHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pushHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;IntegrationHandler&lt;/span&gt; &lt;span class="nf"&gt;getHandlerFor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Integration&lt;/span&gt; &lt;span class="n"&gt;integration&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;EMAIL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;integration&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;emailHandler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SMS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;integration&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;smsHandler&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;PUSH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;integration&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pushHandler&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No handler found for integration: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;integration&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let´s try using a Map instead:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IntegrationHandlerFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integration&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;IntegrationHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;handlerMap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;IntegrationHandlerFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EmailIntegrationHandler&lt;/span&gt; &lt;span class="n"&gt;emailHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                              &lt;span class="nc"&gt;SMSIntegrationHandler&lt;/span&gt; &lt;span class="n"&gt;smsHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                              &lt;span class="nc"&gt;PushIntegrationHandler&lt;/span&gt; &lt;span class="n"&gt;pushHandler&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

            &lt;span class="n"&gt;handlerMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="no"&gt;EMAIL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;emailHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="no"&gt;SMS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;smsHandler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="no"&gt;PUSH&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pushHandler&lt;/span&gt;
            &lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;IntegrationHandler&lt;/span&gt; &lt;span class="nf"&gt;getHandlerFor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Integration&lt;/span&gt; &lt;span class="n"&gt;integration&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;requireNonNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handlerMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;integration&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                            &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"No handler found for integration: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;integration&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Much neater, isn’t it? Once again a very simple design that gets rid of many if / else if statements and makes it very easy to add new options. &lt;/p&gt;

&lt;p&gt;There are many other patterns such as this, and I might do a post about those soon.&lt;/p&gt;

&lt;p&gt;So, what do you think about this kind of patterns? Have you ever used a pattern like this? Are you more comfortable dealing with "if" statements?&lt;/p&gt;

&lt;p&gt;Please let me know in the comments, I'd love to hear your feedback!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I made a post about another pattern that helps avoiding repetitive ifs, want to &lt;a href="https://dev.to/tomazlemos/let-s-talk-tradeoffs-between-an-ioc-factory-and-a-traditional-if-based-one-nhp"&gt;check it out?&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cleancode</category>
      <category>bestpractices</category>
      <category>examples</category>
    </item>
    <item>
      <title>Approaching software design principles</title>
      <dc:creator>Tomaz Lemos</dc:creator>
      <pubDate>Mon, 15 Oct 2018 20:18:36 +0000</pubDate>
      <link>https://forem.com/tomazfernandes/approaching-software-design-principles-16hm</link>
      <guid>https://forem.com/tomazfernandes/approaching-software-design-principles-16hm</guid>
      <description>&lt;p&gt;The other day a dear colleague asked me where I got my software modelling ideas from, and that led me to think about how I worked on system design principles. I learned a lot about my own process, and would like to share with you.&lt;/p&gt;

&lt;p&gt;You see, I've always had an "always be learning" approach to software development, and the way I usually do it is that I try to impose myself some constraints in order to exercise some principle, and to force myself to learn thinking in different ways.&lt;/p&gt;

&lt;p&gt;Otherwise I would always be tempted to go the way I’m more used to, and I think it would really slow down my learning curve.&lt;/p&gt;

&lt;p&gt;I will share some examples of how that works for me, I’m pretty sure I didn’t invent it, but I hope you might find it useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "composition over inheritance" case
&lt;/h2&gt;

&lt;p&gt;One example is the "favor composition over inheritance" principle. I was pretty happy with my abstract classes and inherited methods, so why would that be attractive? I wanted to find out, so I put in place a constraint not to use any kind of inheritance anymore, even in cases where I thought it could make sense.&lt;/p&gt;

&lt;p&gt;After some very awkward times where I had to think a lot to model requisites with composition that I could easily model with inheritance, the result was pretty awesome: I learned a very different way of structuring my code and saw clearly all the benefits of favouring composition over inheritance.&lt;/p&gt;

&lt;p&gt;Today I’m a lot faster at designing with that principle in mind, and actually I haven’t felt the need for inheritance in a while.&lt;/p&gt;

&lt;h2&gt;
  
  
  The “immutability” principle
&lt;/h2&gt;

&lt;p&gt;The same was true for immutable objects. After reading about it and playing with it for a while, I decided to focus on it, and since then all my objects “have” to be immutable. &lt;/p&gt;

&lt;p&gt;Since I got used to this principle, immutability comes very naturally to me, and I the benefits are so great I just don’t use setters at all anymore (except in DTOs for parsing libraries compatibility).&lt;/p&gt;

&lt;p&gt;The code is far easier to debug and to implement new features, as I don’t have to keep in mind the code parts in which a object’s state changes... It just doesn’t!&lt;/p&gt;

&lt;p&gt;The point being that it started as a constraint, and evolved into a new way for me of thinking and designing software.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "let's wrap it up and keep it short" momentum
&lt;/h2&gt;

&lt;p&gt;This approach has helped me a lot in my journey as a developer, and has made work never boring.&lt;/p&gt;

&lt;p&gt;What about you, how do you keep learning software development principles? Have you ever used such a constraints-based approach? Let us know in the comments!&lt;/p&gt;

</description>
      <category>principles</category>
      <category>coding</category>
      <category>development</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
