<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Arquitectura on juanfbermejo.dev</title><link>/tags/arquitectura/</link><description>Recent content in Arquitectura on juanfbermejo.dev</description><image><title>juanfbermejo.dev</title><url>/favicon-32x32.png</url><link>/favicon-32x32.png</link></image><generator>Hugo -- 0.152.2</generator><language>es</language><lastBuildDate>Fri, 13 Mar 2026 20:13:11 +0100</lastBuildDate><atom:link href="/tags/arquitectura/index.xml" rel="self" type="application/rss+xml"/><item><title>Arquitectura por capas en aplicaciones</title><link>/posts/arquitectura-capas-aplicaciones/</link><pubDate>Fri, 13 Mar 2026 20:13:11 +0100</pubDate><guid>/posts/arquitectura-capas-aplicaciones/</guid><description>&lt;p&gt;El &lt;a href="/posts/principio-responsabilidad-unica/"&gt;Principio de Responsabilidad Única&lt;/a&gt; nos dice que clases y funciones deben tener una
responsabilidad clara y específica para conseguir código de mayor calidad. Pero podemos ir un paso más allá aplicando este mismo criterio para &lt;strong&gt;organizar una aplicación completa&lt;/strong&gt;, agrupando componentes según su responsabilidad y definiendo cómo se comunican entre sí.&lt;/p&gt;
&lt;p&gt;Este enfoque permite estructurar el sistema de forma que sea &lt;strong&gt;más robusto, mantenible y fácil de evolucionar&lt;/strong&gt;.&lt;/p&gt;
&lt;h1 id="en-qué-consiste"&gt;En qué consiste&lt;/h1&gt;
&lt;p&gt;La arquitectura por capas consiste en &lt;strong&gt;organizar una aplicación en módulos que comparten una responsabilidad clara&lt;/strong&gt;, estableciendo además una &lt;strong&gt;dirección definida en sus dependencias&lt;/strong&gt;. Cada capa se comunica únicamente con las capas adyacentes.&lt;/p&gt;</description><content:encoded><![CDATA[<p>El <a href="/posts/principio-responsabilidad-unica/">Principio de Responsabilidad Única</a> nos dice que clases y funciones deben tener una
responsabilidad clara y específica para conseguir código de mayor calidad. Pero podemos ir un paso más allá aplicando este mismo criterio para <strong>organizar una aplicación completa</strong>, agrupando componentes según su responsabilidad y definiendo cómo se comunican entre sí.</p>
<p>Este enfoque permite estructurar el sistema de forma que sea <strong>más robusto, mantenible y fácil de evolucionar</strong>.</p>
<h1 id="en-qué-consiste">En qué consiste</h1>
<p>La arquitectura por capas consiste en <strong>organizar una aplicación en módulos que comparten una responsabilidad clara</strong>, estableciendo además una <strong>dirección definida en sus dependencias</strong>. Cada capa se comunica únicamente con las capas adyacentes.</p>
<p>Los objetivos que persigue son:</p>
<ul>
<li>Reducir el acoplamiento.</li>
<li>Facilitar el mantenimiento.</li>
<li>Permitir evolución tecnológica sin afectar al núcleo.</li>
<li>Mejorar la testabilidad.</li>
<li>Aislar la lógica de negocio.</li>
</ul>
<h2 id="estructura-básica">Estructura básica</h2>
<p>Una división mínima podría representarse así:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[    Entrada     ] - Capa de entrada/transporte/salida (HTTP, API...)
</span></span><span class="line"><span class="cl">        ↓
</span></span><span class="line"><span class="cl">[    Negocio     ] - Lógica de negocio
</span></span><span class="line"><span class="cl">        ↓
</span></span><span class="line"><span class="cl">[  Persistencia  ] - Acceso a datos
</span></span><span class="line"><span class="cl">        ↓
</span></span><span class="line"><span class="cl">[  Base de datos ]</span></span></code></pre></div>
<ul>
<li>La <strong>capa de entrada</strong> recibe peticiones y devuelve respuestas.</li>
<li>La <strong>capa de negocio</strong> contiene la lógica que implementa las reglas de la aplicación.</li>
<li>La <strong>capa de persistencia</strong> se encarga del acceso a los datos.</li>
</ul>
<p>Cada capa tiene responsabilidades claras y solo conoce la capa inmediatamente inferior. De esta forma se evita que detalles de infraestructura o transporte se mezclen con la lógica de negocio.</p>
<p>Por ejemplo:</p>
<ul>
<li>Validar que una dirección de correo tiene un formato correcto pertenece a la <strong>capa de entrada</strong>, ya que depende de cómo llegan los datos (JSON, formulario, etc.).</li>
<li>Comprobar si ese correo pertenece a un cliente registrado es una <strong>regla de negocio</strong>, por lo que debe implementarse en la capa de negocio.</li>
</ul>
<p>De la misma forma, el cálculo del importe total de un pedido debería hacerse en la capa de negocio. Si esta lógica se implementara en la base de datos, cambiar de sistema gestor implicaría rehacer parte de la lógica de la aplicación.</p>
<h1 id="cómo-se-rompe-la-arquitectura-por-capas">Cómo se rompe la arquitectura por capas</h1>
<p>Estructurar una aplicación por capas no consiste únicamente en separar el código en carpetas o crear clases llamadas <code>Controller</code>, <code>Service</code> o <code>Repository</code>. Lo importante es <strong>respetar las responsabilidades y la dirección de las dependencias</strong>.</p>
<p>Un ejemplo de una API de gestión de pedidos donde aparentemente existen las tres capas puede ser el siguiente:</p>
<h4 id="controlador">Controlador</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="nd">@RestController</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nd">@RequestMapping</span><span class="p">(</span><span class="s">&#34;/orders&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">OrderController</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nd">@Autowired</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">private</span><span class="w"> </span><span class="n">OrderService</span><span class="w"> </span><span class="n">orderService</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nd">@Autowired</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">private</span><span class="w"> </span><span class="n">CouponRepository</span><span class="w"> </span><span class="n">couponRepository</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nd">@PostMapping</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="n">ResponseEntity</span><span class="o">&lt;</span><span class="n">OrderResponseDto</span><span class="o">&gt;</span><span class="w"> </span><span class="nf">createOrder</span><span class="p">(</span><span class="nd">@RequestBody</span><span class="w"> </span><span class="n">OrderRequestDto</span><span class="w"> </span><span class="n">request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">Coupon</span><span class="w"> </span><span class="n">coupon</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">null</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="na">getCouponCode</span><span class="p">()</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">null</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="o">!</span><span class="n">request</span><span class="p">.</span><span class="na">getCouponCode</span><span class="p">().</span><span class="na">isBlank</span><span class="p">())</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">coupon</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">couponRepository</span><span class="p">.</span><span class="na">findByCode</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="na">getCouponCode</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                    </span><span class="p">.</span><span class="na">orElseThrow</span><span class="p">(()</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">RuntimeException</span><span class="p">(</span><span class="s">&#34;Cupón no encontrado&#34;</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">Order</span><span class="w"> </span><span class="n">order</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">orderService</span><span class="p">.</span><span class="na">createOrder</span><span class="p">(</span><span class="n">request</span><span class="p">,</span><span class="w"> </span><span class="n">coupon</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="n">ResponseEntity</span><span class="p">.</span><span class="na">ok</span><span class="p">(</span><span class="n">mapper</span><span class="p">.</span><span class="na">toResponse</span><span class="p">(</span><span class="n">order</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></td></tr></table>
</div>
</div>
<h4 id="servicio">Servicio</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="nd">@Service</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">OrderService</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nd">@Autowired</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">private</span><span class="w"> </span><span class="n">UserRepository</span><span class="w"> </span><span class="n">userRepository</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nd">@Autowired</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">private</span><span class="w"> </span><span class="n">ProductRepository</span><span class="w"> </span><span class="n">productRepository</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nd">@Autowired</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">private</span><span class="w"> </span><span class="n">OrderRepository</span><span class="w"> </span><span class="n">orderRepository</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="n">Order</span><span class="w"> </span><span class="nf">createOrder</span><span class="p">(</span><span class="n">OrderRequestDto</span><span class="w"> </span><span class="n">request</span><span class="p">,</span><span class="w"> </span><span class="n">Coupon</span><span class="w"> </span><span class="n">coupon</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">User</span><span class="w"> </span><span class="n">user</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">userRepository</span><span class="p">.</span><span class="na">findById</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="na">getUserId</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="p">.</span><span class="na">orElseThrow</span><span class="p">(()</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">RuntimeException</span><span class="p">(</span><span class="s">&#34;Usuario no encontrado&#34;</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">BigDecimal</span><span class="w"> </span><span class="n">totalBeforeDiscount</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BigDecimal</span><span class="p">.</span><span class="na">ZERO</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">OrderItemRequestDto</span><span class="w"> </span><span class="n">item</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">request</span><span class="p">.</span><span class="na">getItems</span><span class="p">())</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">Product</span><span class="w"> </span><span class="n">product</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">productRepository</span><span class="p">.</span><span class="na">findById</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="na">getProductId</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                    </span><span class="p">.</span><span class="na">orElseThrow</span><span class="p">(()</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">RuntimeException</span><span class="p">(</span><span class="s">&#34;Producto no encontrado&#34;</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">BigDecimal</span><span class="w"> </span><span class="n">lineTotal</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">product</span><span class="p">.</span><span class="na">getPrice</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                    </span><span class="p">.</span><span class="na">multiply</span><span class="p">(</span><span class="n">BigDecimal</span><span class="p">.</span><span class="na">valueOf</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="na">getQuantity</span><span class="p">()));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">totalBeforeDiscount</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">totalBeforeDiscount</span><span class="p">.</span><span class="na">add</span><span class="p">(</span><span class="n">lineTotal</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">BigDecimal</span><span class="w"> </span><span class="n">discountApplied</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BigDecimal</span><span class="p">.</span><span class="na">ZERO</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">coupon</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">null</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="n">coupon</span><span class="p">.</span><span class="na">isActive</span><span class="p">())</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="n">discountApplied</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">totalBeforeDiscount</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                    </span><span class="p">.</span><span class="na">multiply</span><span class="p">(</span><span class="n">coupon</span><span class="p">.</span><span class="na">getPercentage</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                    </span><span class="p">.</span><span class="na">divide</span><span class="p">(</span><span class="n">BigDecimal</span><span class="p">.</span><span class="na">valueOf</span><span class="p">(</span><span class="n">100</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">Order</span><span class="w"> </span><span class="n">order</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Order</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">order</span><span class="p">.</span><span class="na">setUser</span><span class="p">(</span><span class="n">user</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">order</span><span class="p">.</span><span class="na">setCreatedAt</span><span class="p">(</span><span class="n">LocalDateTime</span><span class="p">.</span><span class="na">now</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">order</span><span class="p">.</span><span class="na">setTotalBeforeDiscount</span><span class="p">(</span><span class="n">totalBeforeDiscount</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">order</span><span class="p">.</span><span class="na">setDiscountApplied</span><span class="p">(</span><span class="n">discountApplied</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">order</span><span class="p">.</span><span class="na">setTotalFinal</span><span class="p">(</span><span class="n">totalBeforeDiscount</span><span class="p">.</span><span class="na">subtract</span><span class="p">(</span><span class="n">discountApplied</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="n">orderRepository</span><span class="p">.</span><span class="na">save</span><span class="p">(</span><span class="n">order</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></td></tr></table>
</div>
</div>
<h4 id="repositorio">Repositorio</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="nd">@Repository</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="kd">interface</span> <span class="nc">CouponRepository</span><span class="w"> </span><span class="kd">extends</span><span class="w"> </span><span class="n">JpaRepository</span><span class="o">&lt;</span><span class="n">Coupon</span><span class="p">,</span><span class="w"> </span><span class="n">Long</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">Optional</span><span class="o">&lt;</span><span class="n">Coupon</span><span class="o">&gt;</span><span class="w"> </span><span class="nf">findByCode</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">code</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></td></tr></table>
</div>
</div>
<p>A primera vista parece una aplicación bien estructurada: existen controladores, servicios y repositorios. Sin embargo, la arquitectura por capas no se está respetando.</p>
<h2 id="qué-está-mal-aquí">Qué está mal aquí</h2>
<h3 id="1-el-controlador-accede-directamente-al-repositorio">1. El controlador accede directamente al repositorio</h3>
<p>El <code>Controller</code> consulta <code>CouponRepository</code> por su cuenta. Esto rompe la dirección natural de comunicación: Controller → Service → Repository; y hace que la capa de entrada dependa directamente de la persistencia.</p>
<h3 id="2-la-lógica-de-negocio-queda-repartida">2. La lógica de negocio queda repartida</h3>
<p>El controlador decide si hay que buscar el cupón y pasa el resultado al servicio. Parte del caso de uso empieza en el controlador y continúa en el servicio.</p>
<h3 id="3-el-servicio-no-controla-completamente-el-caso-de-uso">3. El servicio no controla completamente el caso de uso</h3>
<p>El método <code>createOrder</code> depende de que el controlador haya resuelto previamente cierta información, por lo que el servicio deja de representar el flujo completo de creación de pedidos.</p>
<h3 id="4-el-servicio-recibe-estructuras-de-transporte">4. El servicio recibe estructuras de transporte</h3>
<p>El servicio recibe <code>OrderRequestDto</code>, que pertenece a la capa de entrada. Esto mezcla el modelo de transporte con la lógica de negocio.</p>
<h2 id="problemas-que-genera">Problemas que genera</h2>
<p>Este tipo de diseño puede funcionar, pero genera varios problemas:</p>
<ul>
<li><strong>Reglas repartidas:</strong> cambios en la lógica obligan a modificar varias capas.</li>
<li><strong>Menor reutilización:</strong> otros puntos de entrada (batch, eventos, etc.) necesitarían replicar parte de la lógica.</li>
<li><strong>Servicios menos autónomos:</strong> el servicio ya no representa el caso de uso completo.</li>
<li><strong>Controladores demasiado complejos:</strong> empiezan a conocer detalles de persistencia y reglas de negocio.</li>
</ul>
<h1 id="versión-correcta">Versión correcta</h1>
<p>En una arquitectura por capas el controlador debería limitarse a recibir la petición y delegar el caso de uso en la capa de negocio.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="nd">@PostMapping</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">public</span><span class="w"> </span><span class="n">ResponseEntity</span><span class="o">&lt;</span><span class="n">OrderResponseDto</span><span class="o">&gt;</span><span class="w"> </span><span class="nf">createOrder</span><span class="p">(</span><span class="nd">@RequestBody</span><span class="w"> </span><span class="n">OrderRequestDto</span><span class="w"> </span><span class="n">request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">CreateOrderDTO</span><span class="w"> </span><span class="n">orderDto</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">mapper</span><span class="p">.</span><span class="na">toCreateOrderDto</span><span class="p">(</span><span class="n">request</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">Order</span><span class="w"> </span><span class="n">order</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">orderService</span><span class="p">.</span><span class="na">createOrder</span><span class="p">(</span><span class="n">orderDto</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="n">ResponseEntity</span><span class="p">.</span><span class="na">ok</span><span class="p">(</span><span class="n">mapper</span><span class="p">.</span><span class="na">toResponse</span><span class="p">(</span><span class="n">order</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></td></tr></table>
</div>
</div>
<p>El servicio se encarga entonces de todo el flujo del caso de uso:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kd">public</span><span class="w"> </span><span class="n">Order</span><span class="w"> </span><span class="nf">createOrder</span><span class="p">(</span><span class="n">CreateOrderDTO</span><span class="w"> </span><span class="n">orderDto</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">Discount</span><span class="w"> </span><span class="n">discount</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">discountService</span><span class="p">.</span><span class="na">calculateDiscount</span><span class="p">(</span><span class="n">orderDto</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// buscar usuario</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// buscar productos</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// validar cupón</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// calcular totales</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// guardar pedido</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></td></tr></table>
</div>
</div>
<p>De esta forma:</p>
<ul>
<li>el <strong>Controller</strong> gestiona el transporte (HTTP, DTOs, respuesta),</li>
<li>el <strong>Service</strong> implementa la lógica de negocio,</li>
<li>los <strong>Repositories</strong> se encargan únicamente del acceso a datos.</li>
</ul>
<h2 id="conclusiones">Conclusiones</h2>
<p>Una arquitectura por capas no se rompe solo cuando una clase hace demasiado, sino también cuando las responsabilidades parecen separadas pero el flujo real del caso de uso queda repartido entre capas que no deberían conocer esos detalles.</p>
<p>Tener clases llamadas <code>Controller</code>, <code>Service</code> y <code>Repository</code> no garantiza una arquitectura por capas. Lo que realmente la define es <strong>respetar las responsabilidades de cada capa y mantener una dirección clara en las dependencias</strong>.</p>
]]></content:encoded></item></channel></rss>