<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>limpio</title><link>https://devtia.com/</link><description>Llevamos empresas a la nueva era digital. Te ayudamos a mejorar tus procesos a través de las métricas.</description><language>es</language><pubDate>Thu, 30 Apr 2026 01:51:18 +0200</pubDate><lastBuildDate>Thu, 30 Apr 2026 01:51:18 +0200</lastBuildDate><generator>DEVTIA</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><ttl>3600</ttl><item><title>Código limpio: la regla del boy scout</title><link>https://devtia.com/post/codigo-limpio-la-regla-del-boy-scout</link><description><![CDATA[<p style="line-height:1.7999999999999998; margin-top:13px">Aunque ya hab&iacute;amos intruducido la regla del boy scout en la entrada<a href="/post/que-es-el-codigo-limpio"> &iquest;Qu&eacute; es el c&oacute;digo limpio?</a>, creo que merece una entrada en exclusiva profundizar en este concepto. Quiza uno de los m&aacute;s importantes del libro.</p><h2>Dise&ntilde;o original</h2><p>Una historia habitual que seguro que te suena conocida es que viene la persona responsable de definir la funcionalidad del producto o proyecto y te explica que necesita un nuevo m&oacute;dulo.</p><p>Este es una situaci&oacute;n que no suele gustar mucho a los desarrolladores. En seguida nos ponemos a definir modelos, entidades, servicios, eventos, y todo encaja en nuestra cabeza. Pero problemente al cabo de pocos d&iacute;as o semanas, ese modelo no encaja todo lo bien que hab&iacute;amos pensado. Puede ser porque los requisitos han ido avanzando, o simplemente por que tu dise&ntilde;o no se ajustaba tan bien c&oacute;mo parec&iacute;a.</p><p>Esta es la situaci&oacute;n m&aacute;s habitual del mundo, &iquest;pero qu&eacute; hacemos ahora?. Muchos desarrolladores introducen una peque&ntilde;a &ntilde;apa para salir del paso, ponen la tarea en "done" y a otra cosa.</p><p><img alt="debemos preocuparnos por dejar el c&oacute;digo un poco mejor de lo que nos lo hemos encontrado" loading="lazy" src="/cache/thumb_1200_0400/uploads/content/image/image/65b5c5a90a0671b00c742c4215ea27b950a48c03.jpg" title="debemos preocuparnos por dejar el c&oacute;digo un poco mejor de lo que nos lo hemos encontrado"></p><h2>Los boy scouts</h2><p>Los boy scouts es una asociaci&oacute;n juvenil que tiene grupos por todo el mundo y que trata de promover una serie de valores entre los que se encuentran el cuidado del medio ambiente.</p><p>Los boy scout tienen una sencilla regla: &ldquo;Siempre deja el lugar de acampada m&aacute;s limpio que como lo encontraste&rdquo;.</p><p>Es decir, que deber&iacute;as recoger y limpiar todo lo que ensuciaste tu, pero adem&aacute;s si puedes aprovechar y limpiar alguna cosa m&aacute;s, dejar&aacute;s el sitio en mejores condiciones para el que venga detr&aacute;s de ti.</p><h2>El c&oacute;digo y la mejora continua</h2><p>Como ya te habr&aacute;s podido imaginar, la regla del boy scout aplicada al desarrollo de software consiste en que cada vez que tocas una pieza de c&oacute;digo para a&ntilde;adir o modificar una funcionalidad, deber&iacute;as mirar un poco alrededor, para ver si puedes dejar ese c&oacute;digo un poco mejor de lo que te encontraste.</p><p>&iquest;Quiz&aacute; puedas elegir un nombre mejor para algo? &iquest;Quiz&aacute; puedas extraer un m&eacute;todo? &iquest;Quiz&aacute; puedas separar responsabilidades?</p><p>No se trata de dejar tirar todo el trabajo que hay echo cada vez, si no de ir introduciendo peque&ntilde;as mejoras. Como podr&aacute;s imaginarte estas peque&ntilde;as mejoras introducidas de forma continua no s&oacute;lo generan una mejora gradual de la base de c&oacute;digo, si no que ayudan a cohesionar a todo el equipo.</p><h2></h2>
]]></description><guid>https://devtia.com/post/codigo-limpio-la-regla-del-boy-scout</guid><pubDate>Sat, 26 Sep 2020 13:42:15 +0200</pubDate></item><item><title>Código limpio: Organiza tus clases</title><link>https://devtia.com/post/codigo-limpio-organiza-tus-clases</link><description><![CDATA[<p>En la &uacute;ltima entrada realizamos una introducci&oacute;n a las <a href="/post/codigo-limpio-pruebas-automaticas">pruebas autom&aacute;ticas</a>. En esta entrada vamos a ver las reglas que utilizamos nosotros para mantener organizadas las clases que escribimos.</p><h2>Elige tu estilo</h2><p>En mi opini&oacute;n no tan importante que reglas utilices para organizar tus clases. Lo que s&iacute; es muy importante, es que <strong>elijas unas y te comprometas con ellas</strong>. Tambi&eacute;n es muy importante que <strong>no seas dogm&aacute;tico</strong> y que <strong>est&eacute;s dispuesto a a&ntilde;adir o modificar tus reglas si es que aparecen otras mejores</strong>.</p><p>No hay nada m&aacute;s frustrante que tratar de explicar a un desarrollador una forma mejor de hacer las cosas, y que no sea capaz de salir de sus trece, pero que tampoco sea capaz de argumentar un motivo.</p><p>Dentro de las reglas que elijas ten en cuenta <strong>que nada debe quedar al azar</strong>, si no que se note que <strong>todo est&aacute; de una forma determinada por un motivo determinado</strong> y no simplemente por que ha quedado as&iacute;.</p><h2>Nuestro estilo</h2><p>Nosotros utilizamos la <a href="https://symfony.com/doc/current/contributing/code/standards.html">guia de estilo</a> oficial para symfony ya que es el framework con el que trabajamos. Adem&aacute;s es muy sencillo configurar el editor para que las aplique autom&aacute;ticamente.</p><p>A continuaci&oacute;n vamos a explicar el resto de reglas que utilizamos nosotros y que no son exactamente iguales a las que describe el autor en el libro. Pero que vamos a argumentarte los motivos que hemos tenido en cuenta para elegirlas.</p><p>Para ello vamos a analizar la clase <code>Rectangle</code> que ya conocemos de entradas anteriores.</p><p>Casi todo lo que vamos a ver son esos peque&ntilde;os detalles que forman parte de nuestra pol&iacute;tica de no dejar nada al azar, y que probablemente <strong>no supongan una gran diferencia por s&iacute; s&oacute;los</strong>, pero que <strong>en conjunto y adoptadas por todo el equipo</strong>, nos permiten <strong>generar una base de c&oacute;digo de calidad</strong> en todos nuestros proyectos.</p><p>Vamos a describir las reglas leyendo la clase de arriba a abajo.</p><h3>Cabecera</h3><p>La cabecera es normalmente un fragmento de c&oacute;digo comentado que se pone encima de cada fichero. Deber&iacute;a indicar a que proyecto pertenece, que tipo de licencia aplica y que personas han intervenido en ella.</p><p>Lo m&aacute;s habitual es utilizar alguna herramienta para <strong>asegurar que todos los ficheros tienen la cabecera correcta</strong> y esta est&aacute; actualizada a la &uacute;ltima versi&oacute;n.</p><pre><code class="php">/*
 * This file is part of the clean code example package.
 *
 * Copyright (c) 2016-2020 Devtia Soluciones.
 * All rights reserved.
 *
 * @author Daniel Gonz&aacute;lez &lt;daniel@devtia.com&gt;
 */
final class Rectangle
{
    //..
}</code></pre><h3>La definici&oacute;n de la clase</h3><p>Nosotros <strong>intentamos por defecto ser lo m&aacute;s restrictivos posible</strong>, y luego ir abriendo la visibilidad seg&uacute;n sea necesario. Por eso siempre declaramos nuestras clases por defecto como <code>final</code>. Una palabra reservada que nos permite indicar que la clase no puede extenderse.</p><h3>Las constantes de clase</h3><p>Nosotros habitualmente <strong>separamos las constantes en clases independientes</strong>. Por ejemplo, si quisi&eacute;ramos poner los colores como constantes, es mejor crear una clase diferente para contenerlos. De esta forma mejoramos la sem&aacute;ntica del dominio.</p><pre><code class="php">final class Color
{
    const WHITE = 'FFFFFF';
    const BLACK = '000000';
}</code></pre><h3>Atributos</h3><p>Como norma general declaramos todos atributos como <code>private</code>. Si fuera necesario cuando realizamos un dise&ntilde;o, algunos de estos los declaramos como <code>protected</code> y evitamos siempre los atributos <code>public</code> salvo cuando se trata de DTOs.</p><p>Si tenemos atributos de diferente visibilidad dentro de una clase los agrupamos seg&uacute;n su visibilidad.</p><p>Dentro de cada grupo, <strong>ordenamos los atributos por orden de importancia</strong>. Los m&aacute;s importantes arriba. <strong>Tambi&eacute;n tratamos de agruparlos por tipo</strong>, para que est&eacute;n todas las fechas juntas, todos las colecciones juntas, ...</p><pre><code class="php">final class Rectangle
{
    /* @var Point */
    private $topLeft;

    /** @var Color */
    private $backgroundColor;

    /** @var Color */
    private $borderColor;

    /* @var float */
    private $border;

    /* @var float */
    private $height;

    /* @var float */
    private $width;

    //..
}</code></pre><h3>El constructor y el resto m&eacute;todos m&aacute;gicos</h3><p>A continuaci&oacute;n de los atributos <strong>escribimos el constructor de la clase</strong>. <strong>Una clase no deber&iacute;a encontrarse en una situaci&oacute;n inconsistente</strong>. Por eso <strong>el constructor deber&iacute;a recibir todo aquello que la clase necesita para existir</strong>. De esta forma evitamos por ejemplo la existencia de un <code>Rectangle</code> cuya altura est&aacute; sin definir.</p><pre><code class="php">final class Rectangle
{
    //..
    public function __construct(Point $topLeft, float $height, float $width)
    {
        $this-&gt;topLeft = $topLeft;
        $this-&gt;height = $height;
        $this-&gt;width = $width;
    }
    //..
}</code></pre><p>Los metodos m&aacute;gicos son m&eacute;todos que est&aacute;n definidos para todas las clases en php, y que son invocados cuando ocurre una circustancia concreta. Nosotros los definimos por orden alfab&eacute;tico despu&eacute;s del constructor.</p><h3>Los m&eacute;todos p&uacute;blicos</h3><p>Nosotros ordenamos los m&eacute;todos agrup&aacute;ndolos por visibilidad. Arriba del todos los m&eacute;todos <code>public</code> luego todos los <code>protected</code> y finalmente todos los <code>private</code>.</p><p>El autor nos indica que se deber&iacute;an ordenar seg&uacute;n su importancia y mantener los m&eacute;todos relacionados cerca entre s&iacute;. Nosotros creemos que esto podr&iacute;a tener sentido en el momento de publicar el libro, pero es una regla dificil de aplicar, cuando por ejemplo un mismo m&eacute;todo se llama desde diferentes m&eacute;todos, &iquest;junto a cual lo pones?</p><p>Los editores modernos nos permiten navegar con facilidad entre m&eacute;todos a&uacute;nque no est&eacute;n cercanos entre s&iacute;, asi que nosotros <strong>simplemente los ordenamos alfabeticamente</strong> y <strong>configuramos el editor para que haga esto autom&aacute;ticamente</strong> por nosotros.</p><h3>El resto de m&eacute;todos</h3><p>Los m&eacute;todos que no son <code>public</code> deber&iacute;an declararse <code>private</code> a menos que exista una buena raz&oacute;n para ello. Los ordenamos tambi&eacute;n por orden alfab&eacute;tico y dejamos que el editor se encarge de esta tarea.</p><h3>Bloques de c&oacute;digo</h3><p>Para explicar esto es necesario traer un ejemplo un poco m&aacute;s complejo. Veamos un ejemplo real de uno de nuestros proyectos.</p><pre><code class="php">final class ProposalController extends AbstractProposalController
{
    //..
    public function copyAction(Project $proposal)
    {
        $this-&gt;throwNotFoundExceptionIfNotIsPublicProposal($proposal);

        $copyManager = $this-&gt;get('app.service.project_copy_manager');
        $publicProposal = $copyManager-&gt;generatePublicProposal(
            $proposal,
            null,
            \AppBundle\Entity\Project\Type::PUBLIC_PROPOSAL_CLIENT_VERSION
        );

        $manager = $this-&gt;get('app.service.project_manager');
        $manager-&gt;update($publicProposal);

        $this-&gt;addFlash('success', 'proposal successfully updated');

        return $this-&gt;redirectToRoute('_public.proposal.view', ['hash' =&gt; $publicProposal-&gt;getHash()]);
    }
    //..
}</code></pre><p>Si ves el ejemplo anterior puedes ver que <strong>cada concepto est&aacute; separado por un salto de l&iacute;nea</strong>. Lo primero que hacemos es la validaci&oacute;n o cl&aacute;usulas de guarda, de las que hablaremos en otra entrada m&aacute;s adelante.</p><p>Lo siguiente que hacemos es obtener una copia de la propuesta a trav&eacute;s del servicio correspondiente. Despu&eacute;s actualizamos esa copia, mensaje de &eacute;xito y redirecci&oacute;n a la nueva propuesta.</p><p>Cada concepto est&aacute; separado por un salto de l&iacute;nea facilitando su entendimiento al lector.</p><h3>Ni un salto de l&iacute;nea de m&aacute;s</h3><p>El &uacute;ltimo detalle. Ya hemos visto donde s&iacute; debemos poner un salto de l&iacute;nea. En nuestra opini&oacute;n <strong>no se deben a&ntilde;adir saltos de l&iacute;nea adicionales</strong>, porque dan la sensaci&oacute;n de estar ah&iacute; por que s&iacute;, en lugar de porque tienen que estar.</p>
]]></description><guid>https://devtia.com/post/codigo-limpio-organiza-tus-clases</guid><pubDate>Thu, 24 Sep 2020 13:45:45 +0200</pubDate></item><item><title>Código limpio: Pruebas automáticas</title><link>https://devtia.com/post/codigo-limpio-pruebas-automaticas</link><description><![CDATA[<p>En la &uacute;ltima entrada repasamos qu&eacute; deber&iacute;as tener en cuenta a la hora de realizar una correcta <a href="/post/codigo-limpio-gestion-de-errores">gesti&oacute;n de errores</a>. En esta entrada vamos a realizar una peque&ntilde;a intruducci&oacute;n a las pruebas autom&aacute;ticas, &iquest;qu&eacute; son? &iquest;para qu&eacute; sirven? y sobre todo que caracter&iacute;siticas tienen que tener para ser realmente &uacute;tiles.</p><h2>&iquest;Pruebas autom&aacute;ticas?</h2><p>Las pruebas o la bater&iacute;a de pruebas es un software que debe escribirse en paralelo a nuestro propio software y cuya responsabilidad es comprobar que nuestro software funciona correctamente. B&aacute;sicamente es <strong>software que prueba nuestro software</strong>.</p><p>Puede que intuitivamente pienses que construir una bater&iacute;a de pruebas, es trabajo adicional, ya que probablemente tardar&aacute;s m&aacute;s tiempo y por lo tanto tu trabajo ser&aacute; m&aacute;s caro para tus clientes pero esto no es as&iacute;.</p><p>Cuando tienes una buena bater&iacute;a de pruebas, la primera "derivada" es que vas a cometer menos errores. Menos errores supone menos tiempo arreglando errores y m&aacute;s tiempo programando. Adem&aacute;s supone menos frustraci&oacute;n en los usuarios.</p><p>La segunda derivada es que puedes hacer cambios con mayor confianza, y esto te hace ir m&aacute;s r&aacute;pido. Las pruebas detectar&aacute;n que has roto, y simplemente tendr&aacute;s que arreglarlo, un equipo con una buena bater&iacute;a de pruebas termina trabajando mucho m&aacute;s r&aacute;pido que un equipo que no las tiene.</p><p>Hay una tercera derivada y es que al desarrollar tu bater&iacute;a de pruebas te va a permitir dise&ntilde;ar mejor software, pero esto es algo en lo que profundizaremos en una entrada m&aacute;s adelante.</p><h2>&iquest;Si es tan bonito por que no todo el mundo hace pruebas autom&aacute;ticas?</h2><p>Cuando escribes pruebas debes ser tan cuidadoso c&oacute;mo con el c&oacute;digo de producci&oacute;n. Todo lo que hemos comentado ya en esta serie sobre elegir buenos <a href="/post/codigo-limpio-nombres">nombres</a>, <a href="/post/codigo-limpio-funciones">funciones</a>, <a href="/post/codigo-limpio-argumentos">argumentos</a>, etc son cosas que tambi&eacute;n aplican a las pruebas autom&aacute;ticas.</p><p>Escribir buenas pruebas requiere cierta t&eacute;cnica y ocurre que muchos programadores o equipos comienzan haciendo pruebas, y al no ser pruebas de calidad terminan teniendo una bater&iacute;a de pruebas que supone m&aacute;s un problema que una soluci&oacute;n. Tras esta mala experiencia desisten, por eso en esta entrada vamos a explicarte c&oacute;mo escribir buenas pruebas.</p><h2>Escribe tus pruebas "PRIMERO"</h2><p><img alt="Escribe pruebas r&aacute;pido" loading="lazy" src="/cache/thumb_1200_0400/uploads/content/image/image/dcc63077554f52edf72fcc4d5c15300636e851dc.jpg" title="Escribe pruebas r&aacute;pido"></p><p><em>FIRST</em> o PRIMERO es un acr&oacute;nimo que se utiliza para describir las caracter&iacute;sticas que deber&iacute;a tener una prueba.</p><h3><em>Fast</em> o R&aacute;pidas</h3><p>Una prueba, as&iacute; como la bater&iacute;a de pruebas a la que pertenecen deber&iacute;an ser tan r&aacute;pidas c&oacute;mo sea posible. &iquest;Cu&aacute;nto? Pues depende del tipo de prueba y del proyecto. El autor no se moja en este aspecto, pero en mi opini&oacute;n deber&iacute;as mantener cada prueba por debajo de 1 segundo.</p><h3><em>Independent</em> o independientes</h3><p>Unas pruebas no deber&iacute;an depender de otras. Esto te permitir&aacute; ejecutar aisladamente las pruebas que fallen en lugar de tener que ejecutar toda la bater&iacute;a o un conjunto de pruebas.</p><h3><em>Repeatable</em> o repetibles</h3><p>El resultado de una prueba deber&iacute;a ser siempre el mismo y no variar si la ejecutas varias veces. De esta forma, podr&aacute;s ejecutar una prueba una y otra vez, hasta que arregles el error. De lo contrario tendr&iacute;as continuamente errores que luego no vas a poder reproducir.</p><h3><em>Self-validating</em> o validaci&oacute;n autom&aacute;tica</h3><p>Lo que quiere decir esta regla es que las pruebas no deber&iacute;an depender de una revisi&oacute;n, por ejemplo que el resultado fuera un texto que luego necesitar&aacute;s leer para saber si es correcto o no. La prueba debe pasar o no pasar, no deber&iacute;a haber otro resultado posible.</p><h3><em>Timely</em> o en el momento correcto</h3><p>El autor introduce en este cap&iacute;tulo las reglas del ciclo de TDD: rojo, verde y refactorizaci&oacute;n, pero no quiero profundizar mucho sobre este aspecto aqu&iacute;, porque tendremos el libro "Test Driven Development: By Example" por en este blog y en el canal de youtube m&aacute;s pronto que tarde.</p><h2>Show me the code</h2><p>Supongamos que tenemos la clase rectangulo que vimos en el cap&iacute;tulo de <a href="/post/codigo-limpio-estructuras-vs-objetos">estructuras vs objetos</a>.</p><pre><code class="php">class Rectangle
{
    private $height;
    private $width;

    public function __construct(float $height, float $width)
    {
        $this-&gt;height = $height;
        $this-&gt;width = $width;
    }

    public function area(): float
    {
        return round($this-&gt;height * $this-&gt;height, 2);
    }
}</code></pre><p>Escribir una prueba es una tarea muy sencilla, normalmente es simplemente una clase que tiene que extender de alg&uacute;n tipo de framework de pruebas, as&iacute; es como se hace con <code>phpunit</code></p><pre><code class="php">class RectangleTest extends \PHPUnit\Framework\TestCase
{
    public function test_area()
    {
        $rectangle = new Rectangle(1.11, 2.22);
        $this-&gt;assertSame(2.46, $rectangle-&gt;area());
    }
}</code></pre><p>F&aacute;cil, pero &iquest;que ocurre al ejecutarlo?</p><div class="alert alert-danger" role="alert">Failed asserting that 1.23 is identical to 2.46.</div><p>Efectivamente hab&iacute;a un error en el c&oacute;digo. En este caso lo hemos introducido a posta, pero es un tipo de error que se puede cometer f&aacute;cilmente.</p><p>&iquest;Has visto cual?</p>
]]></description><guid>https://devtia.com/post/codigo-limpio-pruebas-automaticas</guid><pubDate>Sat, 29 Aug 2020 11:32:50 +0200</pubDate></item><item><title>Código limpio: Gestión de errores</title><link>https://devtia.com/post/codigo-limpio-gestion-de-errores</link><description><![CDATA[<p>En la &uacute;ltima entrada vimos cual es la <a href="/post/codigo-limpio-no-hables-con-estranos">ley de demeter</a>, para que sirve y c&oacute;mo resolver el problema del acoplamiento a una estructura de clases a trav&eacute;s de la inyecci&oacute;n de dependencias. En esta entrada vamos a ver que deber&iacute;as tener en cuenta para mejorar la gesti&oacute;n de errores, como por ejemplo evitar el uso de c&oacute;digos de error, separar la l&oacute;gica de la gesti&oacute;n de errores y por supuesto evitar conocer los detalles de implementaci&oacute;n de las clases que hay por debajo. Cuando programamos adem&aacute;s de que nuestro c&oacute;digo sea limpio, vamos a tener que enfrentarnos a la sucia tarea de la gesti&oacute;n de errores.</p><p>Veamos un ejemplo con la clase responsable de notificar a los usuarios de <a href="/academy/">la academia</a> que hay un nuevo contenido disponible. En el m&eacute;todo <code>send</code> recibiremos un usuario y la entrada que debe serle notificada.</p><p>Partiremos de este primer ejemplo donde la gesti&oacute;n de errores ensucia el c&oacute;digo para ver cuales son las diferentes mejoras que podemos ir realizando.</p><pre><code class="php">class SendCommand extends AbstractCommand
{
    private function send(User $user, Post $post): void
    {
        $code = $this-&gt;mailer-&gt;sendTemplate(
            [$user-&gt;getEmail() =&gt; $user-&gt;getName()],
            $post-&gt;getName(),
            '@App/Command/Academy/Mailing/Post/post.html.twig',
            [
                'user' =&gt; $user,
                'post' =&gt; $post,
            ]
        );

        if (Code::TIMEOUT == $code) {
            sleep(20);
            $this-&gt;send($user, $post);
        } elseif (Code::ADDITIONAL_DATA_REQUIRED == $code) {
            $this-&gt;log(
                sprintf(
                    'message [%06d] for user "%s" could not be sent because was unavailable',
                    $post-&gt;getId(),
                    $user-&gt;getEmail()
                )
            );
        } elseif (Code::ADDITIONAL_DATA_REQUIRED == $code) {
            $this-&gt;log(
                sprintf(
                    'message [%06d] for user "%s" could not be sent because additional space was needed',
                    $post-&gt;getId(),
                    $user-&gt;getEmail()
                )
            );
        } elseif (Code::INBOX_IS_FULL == $code) {
            $this-&gt;log(
                sprintf(
                    'message [%06d] for user "%s" could not be sent because the inbox was full',
                    $post-&gt;getId(),
                    $user-&gt;getEmail()
                )
            );
        }
    }
}
</code></pre><p>Como se puede ver este ejemplo inicial tiene bastante que mejorar.</p><h2>Evita utilizar c&oacute;digos de error</h2><p>Los c&oacute;digos de error son <strong>dif&iacute;ciles de manejar</strong>. En general van a requerir un mont&oacute;n de estructuras if / else para poder lidiar con los diferentes c&oacute;digos de error.</p><p>Adem&aacute;s siempre cabe la posibilidad de que se a&ntilde;ada un nuevo c&oacute;digo de error que nosotros no tengamos capturado. En lugar de c&oacute;digos de error ser&iacute;a conveniente utilizar excepciones.</p><p>A continuaci&oacute;n vemos exactamente el mismo c&oacute;digo pero utilizando excepciones:</p><pre><code class="php">class SendCommand extends AbstractCommand
{
    private function send(User $user, Post $post): void
    {
        try {
            $this-&gt;mailer-&gt;sendTemplate(
                [$user-&gt;getEmail() =&gt; $user-&gt;getName()],
                $post-&gt;getName(),
                '@App/Command/Academy/Mailing/Post/post.html.twig',
                [
                    'user' =&gt; $user,
                    'post' =&gt; $post,
                ]
            );
        } catch (TimeoutException $e) {
            sleep(20);
            $this-&gt;send($user, $post);
        } catch (AdditionalDataRequiredException $e) {
            $this-&gt;log(
                sprintf(
                    'message [%06d] for user "%s" could not be sent because was unavailable',
                    $post-&gt;getId(),
                    $user-&gt;getEmail()
                )
            );
        } catch (ServiceUnavailableException $e) {
            $this-&gt;log(
                sprintf(
                    'message [%06d] for user "%s" could not be sent because additional space was needed',
                    $post-&gt;getId(),
                    $user-&gt;getEmail()
                )
            );
        } catch (InboxIsFullException $e) {
            $this-&gt;log(
                sprintf(
                    'message [%06d] for user "%s" could not be sent because the inbox was full',
                    $post-&gt;getId(),
                    $user-&gt;getEmail()
                )
            );
        }
    }
}</code></pre><p>De momento no hemos mejorado mucho y nuestro c&oacute;digo sigue teniendo una pinta terrible, pero estamos un paso m&aacute;s cerca de tener nuestro c&oacute;digo bastante m&aacute;s elegante.</p><h2>Separar l&oacute;gica y gesti&oacute;n de errores</h2><p>Lo que vamos a hacer ahora es separar la responsabilidad en dos m&eacute;todos. Uno de ellos contendr&aacute; la l&oacute;gica de negocio y el otro contendr&aacute; la gesti&oacute;n de errores. Este sencillo cambio hace nuestro c&oacute;digo mucho m&aacute;s legible y f&aacute;cil de mantener.</p><pre><code class="php">class SendCommand extends AbstractCommand
{
    private function handleSendException(User $user, Post $post, \Exception $exception): void
    {
        try {
            throw $exception;
        } catch (TimeoutException $e) {
            // ..
        } catch (AdditionalDataRequiredException $e) {
            // ..
        } catch (ServiceUnavailableException $e) {
            // ..
        } catch (InboxIsFullException $e) {
            // ..
        }
    }

    private function send(User $user, Post $post): void
    {
        try {
            $this-&gt;mailer-&gt;sendTemplate(
                [$user-&gt;getEmail() =&gt; $user-&gt;getName()],
                $post-&gt;getName(),
                '@App/Command/Academy/Mailing/Post/post.html.twig',
                [
                    'user' =&gt; $user,
                    'post' =&gt; $post,
                ]
            );
        } catch (\Exception$exception) {
            $this-&gt;handleSendException(user, $post, $exception);
        }
    }
}</code></pre><h2>Evita los detalles de implementaci&oacute;n</h2><p>Nuestro c&oacute;digo ha mejorado bastante, pero todav&iacute;a tiene un problema. Nuestro comando <strong>conoce los detalles de implementaci&oacute;n del sistema de env&iacute;o de correo</strong>. Esto supone un problema, si en el futuro quisi&eacute;ramos enviar el correo o las notificaciones con otra librer&iacute;a o a trav&eacute;s de otro medio, nuestro comando dejar&iacute;a de funcionar.</p><p>Para ello es conveniente evitar conocer los detalles de implementaci&oacute;n ( las excepciones ) que contiene el sistema de env&iacute;o, con lo que nos deber&iacute;a quedar algo as&iacute;.</p><pre><code class="php">class SendCommand extends AbstractCommand
{
    private function handleSendException(User $user, Post $post, \Exception $exception): void
    {
        $this-&gt;log(
            sprintf(
                'message [%06d] for user "%s" with message "%s"',
                $post-&gt;getId(),
                $user-&gt;getEmail(),
                $exception-&gt;getMessage()
            )
        );
    }

    private function send(User $user, Post $post): void
    {
        try {
            $this-&gt;mailer-&gt;sendTemplate(

                [$user-&gt;getEmail() =&gt; $user-&gt;getName()],
                $post-&gt;getName(),
                '@App/Command/Academy/Mailing/Post/post.html.twig',
                [
                    'user' =&gt; $user,
                    'post' =&gt; $post,
                ]
            );
        } catch (\Exception$exception) {
            $this-&gt;handleSendException($user, $post, $exception);
        }
    }
}</code></pre>
]]></description><guid>https://devtia.com/post/codigo-limpio-gestion-de-errores</guid><pubDate>Sat, 29 Aug 2020 11:31:17 +0200</pubDate></item><item><title>Código limpio: No hables con extraños</title><link>https://devtia.com/post/codigo-limpio-no-hables-con-extranos</link><description><![CDATA[<p>En la &uacute;ltima entrada repasamos qu&eacute; son <a href="/post/codigo-limpio-estructuras-vs-objetos">las estructuras de datos</a>, en que se diferencian de los objetos y cu&aacute;ndo conviene m&aacute;s utilizar una aproximaci&oacute;n u otra. En esta entrada vamos a explicar cual es la ley de demeter, que problemas puedes tener si es que no la cumples y que opciones tienes para cumplirla.</p><p>Empezemos describiendo los motivos por los que <strong>no deber&iacute;as hablar con extra&ntilde;os:</strong> muchas veces cuando tenemos una clase que a su vez est&aacute; formada por objetos de otras clases y estas a su vez por otras, tenemos una estructura de clases. Hasta aqu&iacute; todo bien, pero: &iquest;qu&eacute; ocurre cuando estas estructuras se vuelven complejas? Veamos un ejemplo que podr&iacute;a darse en un comando de symfony.</p><pre><code class="php">class CustomCommand extends Command
{
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $this-&gt;getApplication()-&gt;getKernel()-&gt;getContainer()-&gt;getCustomService()-&gt;getManager()-&gt;execute();

        return 1;
    }
}</code></pre><p>Como puedes ver, estamos <strong>acoplando de forma innecesaria</strong> nuestro c&oacute;digo a todas las clases que aparecen en la cadena de llamadas. Cualquier cambio en estas clases o en las relaciones entre ellas podr&iacute;a suponer que nuestro c&oacute;digo dejase de funcionar. Para que esto no suceda viene al rescate la ley de demeter.</p><h2>La ley de demeter</h2><p><img alt="La ley de demeter" loading="lazy" src="/cache/thumb_1200_0200/uploads/content/image/image/f0a9a0fb4bc402545242cec37f8a0821462dce05.jpg"></p><p>La ley de demeter fue descrita por primera vez dentro del proyecto demeter en 1987. Como curiosidad quiero contarte que Demeter, hace referencia a la diosa griega de la agricultura. Querian hacer referencia a algo as&iacute; como "cultivar" software en contraposici&oacute;n a "construir" el software.</p><p>La ley indica que desde un m&eacute;todo <strong>solo deber&iacute;as "hablar" con aquellos a quien conozcas bien</strong>. Y estos son:</p><ul><li>M&eacute;todos de la misma clase.</li><li>M&eacute;todos de los objetos de la clase.</li><li>M&eacute;todos de los objetos creados en la misma funci&oacute;n.</li><li>M&eacute;todos de los objetos pasados como argumento a la funci&oacute;n.</li></ul><h2>&iquest;Y c&oacute;mo lo soluciono?</h2><p>Ya hemos detectado que es lo que no debes hacer, te voy a proponer ahora tres opciones a tener en cuenta cuando detectes este problema en tu c&oacute;digo.</p><h3>No hacer nada</h3><p>La primera es no hacer nada. Es la soluci&oacute;n m&aacute;s sencilla, y <strong>la peor de las tres</strong> que vamos a ver, pero como ya vimos en la entrada sobre <a href="/post/los-dogmas-en-el-desarrollo-de-software">los dogmas en el desarrollo de software</a>, si crees que las clases que est&aacute;s llamando y sus relaciones est&aacute;n muy consolidadas, podr&iacute;as permitirte el lujo de realizar este tipo de llamadas en cadena.</p><h3>Usar atajos</h3><p>La segunda consiste en hacer atajos que permitan evitar estas llamadas encadenadas. Esta es una soluci&oacute;n bastante r&aacute;pida, que te puede permitir salir del paso en alg&uacute;n momento.</p><p>Por ejemplo en <code>CustomService</code> podr&iacute;amos a&ntilde;adir el m&eacute;todo <code>executeManager</code>.</p><pre><code class="php">class CustomService
{
    public function executeManager(): void
    {
        $this-&gt;getManager()-&gt;execute();
    }
}</code></pre><p>Esta soluci&oacute;n como puedes imaginarte tampoco es la mejor. Te permite abstraer parte de esa cadena de llamadas y por lo tanto es una opci&oacute;n mejor que al principio, ya que si la relacion cambia s&oacute;lo tendr&aacute;s que cambiar en este punto las llamadas.</p><p>El problema de esta soluci&oacute;n es que puedes encontrarte con tu c&oacute;digo con un mont&oacute;n de estos m&eacute;todos atajos, que realmente por dise&ntilde;o no deber&iacute;an encontraser ah&iacute;, pero est&aacute;n simplemente para hacer cumplir la ley de demeter.</p><h3>Inyectar dependencias</h3><p>La soluci&oacute;n buena, como probablemente ya te ven&iacute;as imaginando es <strong>inyectar las dependencias</strong>. Veamos un ejemplo.</p><pre><code class="php">class CustomCommand extends Command
{
    public function setCustomManager(CustomManager $customManager)
    {
        $this-&gt;manager = $customManager;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $this-&gt;manager-&gt;execute();
    }
}</code></pre><p>Hemos a&ntilde;adido como dependencia la clase <code>CustomManager</code> que era la que realmente necesitamos, y se la hemos inyectado a trav&eacute;s de un setter, pero hemos eliminado toda la cadena de dependencias y las relaciones entre s&iacute;.</p><p>Con este sencillo cambio hemos podido eliminar f&aacute;cilmente todas las dependencias sobrantes.</p>
]]></description><guid>https://devtia.com/post/codigo-limpio-no-hables-con-extranos</guid><pubDate>Sat, 29 Aug 2020 10:49:10 +0200</pubDate></item><item><title>Código limpio: Estructuras vs objetos</title><link>https://devtia.com/post/codigo-limpio-estructuras-vs-objetos</link><description><![CDATA[<p>En esta entrada vamos a ver que son las estructuras de datos y los objetos, y que ventajas puede tener el uso de uno u otro tipo. Vamos a implementar exactamente lo mismo con las dos aproximaciones para ver c&oacute;mo se comporta cada una.</p><h2>Estructuras de datos</h2><p>Una estructura de de datos, es una clase o un objeto que expone la informaci&oacute;n que contiene. En el ejemplo hemos evitado el uso de getters y setter, pero ser&iacute;a exactamente lo mismo si los tuviera, lo consideraremos una estructura, porque expone su informaci&oacute;n. Otras clases ser&aacute;n responsables de realizar las funcionalidad que necesitemos.</p><pre><code class="php">class Circle
{
    /** @var Point */
    public $center;
    public $radius;
}

class Geometry
{
    const PI = 3.141592653589793;

    public function area($shape): float
    {
        return $shape-&gt;radius * $shape-&gt;radius * Geometry::PI;
    }
}</code></pre><h2>Objetos</h2><p>Con el mismo ejemplo si usaramos el paradigma de la orientaci&oacute;n a objetos, debemos ocultar cu&aacute;l es la informaci&oacute;n y la estructura de los datos internos, y debemos exponer la funcionalidad que queremos.</p><pre><code class="php">class Circle
{
    const PI = 3.141592653589793;

    /** @var Point */
    private $center;
    private $radius;

    public function area(): float
    {
        return $this-&gt;radius * $this-&gt;radius * self::PI;
    }
}</code></pre><p>Aunque el ejemplo es muy sencillo nos permite entender la diferencia. Una estructura de datos es un elemento sencillo que solamente contiene informaci&oacute;n, mientras que la l&oacute;gica se encuentra en otras clases. Un objeto es una abstracci&oacute;n que expone su funcionalidad.</p><h2>A&ntilde;adir nuevas estructuras de datos / objetos</h2><p>Vamos a&ntilde;adir un nuevo tipo: <code>Rectangle</code> y vemos a ver que cambios son necesarios en cada aproximaci&oacute;n.</p><div class="row mb40 mt40"><div class="col-sm-6"><pre><code class="php">class Rectangle
{
    /** @var Point */
    public $topLeft;
    public $height;
    public $width;
}

class Circle
{
    /** @var Point */
    public $center;
    public $radius;
}

class Geometry
{
    const PI = 3.141592653589793;

    public function area($shape): float
    {
        if ($shape instanceof Rectangle) {
            return $shape-&gt;height * $shape-&gt;width;
        }

        if ($shape instanceof Circle) {
            return $shape-&gt;radius * $shape-&gt;radius * Geometry::PI;
        }

        throw new InvalidArgumentException();
    }
}</code></pre>
Estructura de datos</div><div class="col-sm-6"><pre><code class="php">class Rectangle
{
    /** @var Point */
    private $topLeft;
    private $height;
    private $width;

    public function area(): float
    {
        return $this-&gt;height * $this-&gt;width;
    }
}

class Circle
{
    const PI = 3.141592653589793;

    /** @var Point */
    private $center;
    private $radius;

    public function area(): float
    {
        return $this-&gt;radius * $this-&gt;radius * self::PI;
    }
}





    </code></pre>
Orientado a objetos</div></div><p>&iquest;Que diferencia ves entre ambos?. En la primera aproximaci&oacute;n adem&aacute;s de a&ntilde;adir la nueva estructura, hemos tenido que modificar <code>Geometry::area()</code>. En el ejemplo es un cambio muy sencillo, pero nos sirve para identificar que cuando a&ntilde;adimos nuevas estructuras vamos a tener que revisar el c&oacute;digo que las utiliza para que sea capaz de manejar esta nueva estrucutra, lo cual nos puede llevar a a&ntilde;adir errores en un c&oacute;diugo que ya estaba funcionando.</p><p>En cambio en la aproximaci&oacute;n orientada a objetos no hemos tenido que modificar ni una coma del c&oacute;digo que ya ten&iacute;amos, y simplemente hemos tenido que a&ntilde;adir un nuevo objeto.</p><h2>A&ntilde;adir funcionalidad</h2><p>Vamos a a&ntilde;adir una nueva funcionalidad, el c&aacute;lculo del per&iacute;metro: <code>perimeter</code> a ver que tal se comporta cada una de nuestras implementaciones.</p><div class="row mb40 mt40"><div class="col-sm-6"><pre><code class="php">class Rectangle
{
    /** @var Point */
    public $topLeft;
    public $height;
    public $width;
}

class Circle
{
    /** @var Point */
    public $center;
    public $radius;
}

class Geometry
{
    const PI = 3.141592653589793;

    public function area($shape): float
    {
        if ($shape instanceof Rectangle) {
            return $shape-&gt;height * $shape-&gt;width;
        }

        if ($shape instanceof Circle) {
            return $shape-&gt;radius * $shape-&gt;radius * Geometry::PI;
        }

        throw new InvalidArgumentException();
    }

    public function perimeter($shape): float
    {
        if ($shape instanceof Rectangle) {
            return 2 * $shape-&gt;height + 2 * $shape-&gt;width;
        }

        if ($shape instanceof Circle) {
            return 2 * Geometry::PI * $shape-&gt;radius;
        }

         throw new InvalidArgumentException();
    }
}</code></pre>
Estructuras de datos</div><div class="col-sm-6"><pre><code class="php">class Rectangle
{
    /** @var Point */
    private $topLeft;
    private $height;
    private $width;

    public function area(): float
    {
        return $this-&gt;height * $this-&gt;width;
    }

    public function perimeter(): float
    {
        return 2 * $this-&gt;height + 2 * $this-&gt;width;
    }
}

class Circle
{
    const PI = 3.141592653589793;

    /** @var Point */
    private $center;
    private $radius;

    public function area(): float
    {
        return $this-&gt;radius * $this-&gt;radius * self::PI;
    }

    public function perimeter(): float
    {
        return 2 * self::PI * $this-&gt;radius;
    }
}








    </code></pre>
Orientado a objetos</div></div><p>En este caso, nuestra primera aproximaci&oacute;n ha sido m&aacute;s sencilla. No hemos tenido que tocar el c&oacute;digo que ya ten&iacute;amos funcionando y s&oacute;lo hemos tenido que a&ntilde;adir una nueva funci&oacute;n.</p><p>En cambio en la aproximaci&oacute;n orientada a objetos hemos tenido que tocar cada una de las clases que ten&iacute;amos para a&ntilde;adirles esta funcionalidad. El ejemplo es muy sencillo, pero nos sirve para identificar el problema.</p><h2>Conclusiones</h2><p>A nivel de l&iacute;neas de c&oacute;digo no existe una diferencia sustancial. Tampoco es razonablemente m&aacute;s sencillo de implementar o de mantener una u otra aproximaci&oacute;n, pero cuando utilizamos estructuras, tendremos cierta facilidad cuando queramos a&ntilde;adir nueva funcionalidad, mientras que cuando utilizamos objetos tendremos facilidades para a&ntilde;adir nuevos tipos.</p>
]]></description><guid>https://devtia.com/post/codigo-limpio-estructuras-vs-objetos</guid><pubDate>Sun, 19 Jul 2020 15:29:55 +0200</pubDate></item><item><title>Código limpio: Deja de comentar</title><link>https://devtia.com/post/codigo-limpio-deja-de-comentar</link><description><![CDATA[<p>En esta entrada vamos a analizar cu&aacute;ndo y c&oacute;mo es conveniente el uso de comentarios durante la fase de desarrollo de software.</p><h2>bloques de c&oacute;digo</h2><p>Por regla general <strong>deber&iacute;as evitar el uso de comentarios</strong>. Los comentarios pueden parecer una herramienta muy &uacute;til ya que cuando estamos desarrollando puede que nos encontremos con que queremos explicar mejor c&oacute;mo funciona nuestro c&oacute;digo o por que hemos tomado una determinada decisi&oacute;n.</p><p>Pero cuando usamos un comentario de c&oacute;digo donde antes ten&iacute;amos un problema: que nuestro c&oacute;digo no era suficientemente sencillo de entender, ahora tenemos dos: nuestro c&oacute;digo sigue sin entenderse con facilidad, y ahora adem&aacute;s debo ocuparme de mantener los comentarios que he realizado.</p><p>Puedes pensar que mantener ese comentario no es mucho trabajo, pero que tal si esa energ&iacute;a qu&eacute; has gastado en mantener un comentario la hubieras gastado en <strong>hacer algo m&aacute;s productivo</strong>. &iquest;mejor, no?.</p><p>Vemos un ejemplo con el <code>TokenStorage</code> del componente <code>Security</code> de <code>Symfony</code>.</p><pre><code class="php">namespace Symfony\Component\Security\Core\Authentication\Token\Storage;

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Contracts\Service\ResetInterface;

/**
 * TokenStorage contains a TokenInterface.
 */
class TokenStorage implements TokenStorageInterface, ResetInterface
{
    // ..
    public function setToken(TokenInterface $token = null)
    {
        if ($token) {
            // ensure any initializer is called
            $this-&gt;getToken();
        }

        $this-&gt;initializer = null;
        $this-&gt;token = $token;
    }
    //..
}</code></pre><p>El autor de este c&oacute;digo necesitaba hacer algunas llamadas antes de configurar el token. Se dio cuenta que que no era sencillo de entender y que otra persona que viniera detr&aacute;s probablemente no entender&iacute;a el motivo de esa llamada, asi que utiliz&oacute; un comentario para aclararlo todo. &iquest;Pero que te parece si hubiera hecho esto?</p><pre><code class="php">namespace Symfony\Component\Security\Core\Authentication\Token\Storage;

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Contracts\Service\ResetInterface;

/**
 * TokenStorage contains a TokenInterface.
 */
class TokenStorage implements TokenStorageInterface, ResetInterface
{
    // ..
    public function setToken(TokenInterface $token = null)
    {
        if ($token) {
            $this-&gt;callInitializer();
        }

        $this-&gt;initializer = null;
        $this-&gt;token = $token;
    }

    private function callInitializer(): void
    {
        $this-&gt;getToken();
    }
    //..
}</code></pre><p>Como ves <strong>hemos eliminado el comentario y hemos mantenido e incluso mejorado la expresividad</strong>, ya que el c&oacute;digo es igual de expl&iacute;cito. Por lo tanto siempre que nos veamos en la necesidad de a&ntilde;adir comentarios, debemos plantearnos si podr&iacute;amos mejorar la expresividad de nuestro c&oacute;digo mejorando los nombres que estamos utilizando o extrayendo m&eacute;todos como en el ejemplo.</p><h2>DocBlock y documentaci&oacute;n autogenerada</h2><p>Algunos editores de texto a&ntilde;aden documentaci&oacute;n de forma m&aacute;s o menos autom&aacute;tica que permite indicar los tipos de los argumentos y del valor devuelto, as&iacute; como informaci&oacute;n adicional.</p><p>Veamos un ejemplo</p><pre><code class="php">    /**
     * get movements
     *
     * @return array
     */
    public function getMovements()
    {
        return $this-&gt;movements;
    }</code></pre><p>Este tipo de documentaci&oacute;n <strong>no aporta ning&uacute;n valor adicional</strong> ya que simplemente est&aacute; repitiendo lo mismo que ya dice el nombre de la funci&oacute;n. Quiz&aacute; esto ten&iacute;a sentido antes de la versi&oacute;n 7, para ayudar al IDE en el autocompletado. Pero a partir de esta versi&oacute;n es mucho mejor eliminar estos comentarios y utilizar el tipado nativo del lenguaje.</p><pre><code class="php">   public function getMovements(): array
    {
        return $this-&gt;movements;
    }</code></pre><h2>Usos permitidos</h2><p>Por supuesto el autor contempla algunos casos en los que s&iacute; estar&iacute;a permitido y justificado el uso de comentarios.</p><h3>Licencias y textos legales</h3><p>Es un uso completamente justificado el incluir la licencia y otros textos legales en el encabezado de nuestros ficheros. Adem&aacute;s esto no supone ning&uacute;n trabajo adicional, por que es habitual utilizar sistemas que se encargan de a&ntilde;adir estos comentarios de forma autom&aacute;tica, y adem&aacute;s los IDE suelen ocultarlos por lo que no molestan.</p><h3>APIs</h3><p>Si est&aacute;s construyendo una api y probablemente quieras generar la documentaci&oacute;n a trav&eacute;s de alg&uacute;n sistema autom&aacute;tico, s&iacute; estar&iacute;a justificado el incluir toda esta informaci&oacute;n adicional en tu c&oacute;digo.</p>
]]></description><guid>https://devtia.com/post/codigo-limpio-deja-de-comentar</guid><pubDate>Fri, 17 Jul 2020 14:46:07 +0200</pubDate></item><item><title>Código limpio: Nombres</title><link>https://devtia.com/post/codigo-limpio-nombres</link><description><![CDATA[<p>En esta entrada vamos a entender y profundizar en la importancia de elegir buenos nombres. Es muy importante que te tomes el tiempo necesario para encontrar un buen nombre, y no debes tener ning&uacute;n miedo a cambiarlo si es que encuentras otro mejor.</p><h2>Evita el uso de contracciones</h2><p>Esta es la primera regla y la m&aacute;s sencilla de todas. Cuando programamos, podemos caer en la tentaci&oacute;n de crear peque&ntilde;as contracciones, dentro de la api de linux por ejemplo nos encontramos con un mont&oacute;n de ellas como por ejemplo <code>mv</code>, <code>cp</code>, <code>chmod</code> y muchas m&aacute;s.</p><p>Cuando escribes una contracci&oacute;n puede que en ese momento a t&iacute; te parezca obvia, pero es posible que para otra persona en otro contexto no lo sea tanto, as&iacute; que no merece la pena ahorrarse unos caracteres a cambio de los problemas que puedas generar en el futuro.</p><p>Adem&aacute;s esta regla te permitir&aacute; no entrar en conflicto con la siguiente que es la consistencia. Si usas una contracci&oacute;n en una variable o m&eacute;todo, &iquest;Por qu&eacute; no usarlo en todas las dem&aacute;s? &iquest;En cu&aacute;les s&iacute; y en cu&aacute;les no? Acabas de crear un problema donde no lo hab&iacute;a.</p><h2>S&eacute; consistente</h2><p><img alt="S&eacute; consistente" loading="lazy" src="/cache/thumb_1200_0400/uploads/content/image/image/17b93e4abdd2e6b2bed5b34fbe251abed368da8d.jpg" title="S&eacute; consistente"></p><p>Una de las caracter&iacute;sticas que vimos del c&oacute;digo limpio es que no es f&aacute;cil de mejorar. Eso significa que el c&oacute;digo es consistente. Si has decidido por ejemplo llamar <code>Lesson</code> a la entidad que representa a un profesor, una asignatura, una colecci&oacute;n de alumnos y un momento concreto en el tiempo, no deber&iacute;as utilizar ning&uacute;n tipo de sin&oacute;nimos.</p><p>Otro elemento que debes tener en cuenta a la hora de producir nombres consistentes es utilizar siempre los mismos verbos para una determinada tarea. Por ejemplo si has decidido que cuando accedas a un repositorio y recuperes un conjunto de lecciones vas a utilizar el verbo <code>get</code> generando nombres del tipo <code>getByUser()</code>, <code>getByState()</code>, <code>getByDate()</code> deber&iacute;as evitar usar sin&oacute;nimos del verbo <code>get</code>, como por ejemplo <code>fetchByUser()</code>, <code>findByState()</code>, <code>retrieveByDate()</code>.</p><h2>Utiliza el contexto</h2><p>Evita repetir conceptos que ya est&aacute;n claros a trav&eacute;s del contexto. Continuando con el ejemplo anterior, si est&aacute;s escribiendo un m&eacute;todo dentro de <code>LessonRepository</code> para buscar lecciones por su estado no necesitas indicar que est&aacute;s buscando lecciones <code>getLessonsByState</code>. Ya te encuentras dentro de <code>LessonRepository</code> as&iacute; que todos sus m&eacute;todos deber&iacute;an devolver por colecciones de lecciones. Debes evitar repetir "Lessons" en cada nombre, siendo <code>getByState()</code> m&aacute;s adecuado./p&gt;</p><p>Deber&iacute;as evitar usar nombres demasiado largos, as&iacute; como deber&iacute;as evitar usar nombres demasiado parecidos. Si te encuentras en una situaci&oacute;n en la que est&aacute;s escribiendo un nombre demasiado largo deber&iacute;as evaluar si puedes utilizar el contexto para generar un nombre m&aacute;s corto.</p><p>Por ejemplo si tienes la clase <code>UniversityLessonState</code> que contiene los estados posibles de una lecci&oacute;n de la universidad, podr&iacute;as generar un nuevo namespace del tipo <code>University\Lesson\State</code> obteniendo un nombre de clase mucho m&aacute;s corto y f&aacute;cil de leer, pero sin haber perdido ning&uacute;n tipo de informaci&oacute;n.</p><p>Si necesitas dos palabras para definir el nombre de una clase es probable que necesites crear un nuevo contexto, y si necesitas tres palabras definitivamente deber&iacute;as crear un contexto nuevo.</p><h2>Hace lo que dice que hace</h2><p><img alt="Hace lo que dice que hace" loading="lazy" src="/cache/thumb_1200_0400/uploads/content/image/image/6e032f2cbbc3defe991d6878c01e6298fa24ed2f.jpg" title="Hace lo que dice que hace"></p><p>Entramos en la parte final de las recomendaciones. Sin embargo estas dos &uacute;ltimas son las m&aacute;s importante de todas. Cuando eliges un nombre lo m&aacute;s importante es ser sincero. El nombre que est&aacute;s eligiendo tiene que servir para identificar qu&eacute; es lo que contiene.</p><p>En general debemos evitar nombres gen&eacute;ricos como <code>data</code>, <code>info</code>, <code>resume</code>, <code>items</code>. En algunos momentos muy concretos puede que tengan sentido, &iquest;pero que contienen exactamente?. Quiz&aacute; el autor no sab&iacute;a que nombre poner y eligi&oacute; uno de estos.</p><p>Si lo que quer&iacute;amos crear era por ejemplo un conjunto de lecciones filtradas por algunos criterios, podr&iacute;amos haber eleg&iacute;do <code>lessons</code> o <code>filteredLessons</code> al menos indica que contiene un conjunto de lecciones.</p><p>Debemos tambi&eacute;n evitar nombres que definan qu&eacute; es lo que necesita el autor en lugar de que es lo que hace un m&eacute;todo o clase. Por ejemplo <code>LessonRepository::getForDashboard</code>. Tenemos claro que el autor necesitaba una colecci&oacute;n de lecciones para mostrarlas en el dashboard, pero no tenemos ni idea de que criterios tiene en cuenta. Si el criterio para mostrar las lecciones en el dashboard fuera que pertenecieran a un determinado usuario, que estuvieran en un rango determinado de fechas, como por ejemplo los pr&oacute;ximos 15 d&iacute;as, y se encontraran en un determinado estado, podr&iacute;amos haber elegido <code>LessonRepository::getByUserFromToAndState</code>.</p><h2>Explica c&oacute;mo debe usarse</h2><p>Llegamos al &uacute;ltimo punto. Una vez que has encontrado el nombre adecuado que cumple todos los anteriores requisitos debes plantearte una &uacute;ltima pregunta.</p><p>&iquest;Explica mi nombre c&oacute;mo debe ser utilizado? Veamos un ejemplo supongamos que tenemos una clase que se encarga de realizar cambios sobre las lecciones <code>LessonManager::changeDate</code>, el contexto <code>LessonManager</code> nos indica que la entidad que va a modificar es una <code>Lesson</code> y el nombre nos revela que la va a cambiar de estado.</p><p>Por coherencia los argumentos deber&iacute;an ser <code>Lesson</code>, <code>Date</code> en este orden. Sin embargo podemos ayudar a evitar malentendidos, nombrando correctamente los argumentos. <code>LessonManager::changeDate($lesson, $toDate)</code> no deja lugar a ning&uacute;n tipo de equivocaci&oacute;n.</p><h2>Conclusiones</h2><p>Cuando escribimos c&oacute;digo limpio debemos tener en cuenta a la persona que lo va a leer, y cuando elegimos nombres debemos elegirlos pensando primero en esa persona en hacerle la vida lo m&aacute;s f&aacute;cil posible.</p>
]]></description><guid>https://devtia.com/post/codigo-limpio-nombres</guid><pubDate>Wed, 03 Jun 2020 10:39:13 +0200</pubDate></item><item><title>¿Qué es el código limpio?</title><link>https://devtia.com/post/que-es-el-codigo-limpio</link><description><![CDATA[<p>En esta entrada vamos a realizar una peque&ntilde;a introducci&oacute;n a los conceptos principales del libro.</p><h2>M&aacute;s lento para ir m&aacute;s r&aacute;pido</h2><p><img alt="M&aacute;s lento para ir m&aacute;s r&aacute;pido" loading="lazy" src="/cache/thumb_1200_0400/uploads/content/image/image/826f0cfe85aeb9de4864a7440b4529066e96be1d.jpg" title="M&aacute;s lento para ir m&aacute;s r&aacute;pido"></p><p>A lo largo de este primer cap&iacute;tulo Martin nos introduce la idea de que en muchos proyectos cuando se trata de ir demasiado deprisa el resultado es exactamente el contrario. Si eers programador probablemente hayas vivido esto en tus propias carnes. En el periodo de uno o dos a&ntilde;os en los que los programadores han ido a&ntilde;adiendo cambios al c&oacute;digo sin control el resultado es que cada vez se hace m&aacute;s y m&aacute;s dif&iacute;cil avanzar y se dedica la mayor&iacute;a del tiempo a solucionar incidencias. Para a&ntilde;adir cualquier peque&ntilde;o cambio es necesario tener en cuenta un sin fin de detalles, efectos y consecuencias, as&iacute; que cada nueva funcionalidad a&ntilde;ade a&uacute;n m&aacute;s complejidad al proyecto.</p><p>La soluci&oacute;n que aplican muchos managers en este momento es aumentar la plantilla, pero sin cambiar la forma de trabajar, lo que fragmenta m&aacute;s el c&oacute;digo y reduce cada vez m&aacute;s la productividad. M&aacute;s pronto que tarde el equipo de desarrollo se plantar&aacute; y exigir&aacute; "rehacer" el c&oacute;digo para sacar una nueva versi&oacute;n, esta vez sin los problemas de la actual. Pero recuerda que si no cambian su forma de trabajar y de pensar, el mismo equipo que gener&oacute; el problema volver&aacute; a generar un problema parecido de nuevo.</p><p>Si te has visto en esta situaci&oacute;n te aconsejo leer esta serie de entradas sobre c&oacute;digo limpio.</p><h2>Bien, &iquest;Pero qu&eacute; es el c&oacute;digo limpio?</h2><p>El libro autor comienza haci&eacute;ndose el mismo esta pregunta. Para ello recurre a diversos autores relevantes a los que les traslada esta cuesti&oacute;n.</p><div class="row mt-2"><div class="col-sm-3"><p><img alt="Bjarne stroustrup" loading="lazy" src="/cache/thumb_1200/uploads/content/image/image/d240078809f3a4cc995742f4cd017a235c31f529.jpg" title="Bjarne stroustrup"></p></div><div class="col-sm-9"><h3 class="mt-0">Bjarne stroustrup</h3><p>Ha destacado por desarrollar el lenguaje de programaci&oacute;n C++ y por ser el autor del libro que se considera de referencia en dicho lenguaje: "programming principles and practice using c++".</p><p>Bjarne indica que el c&oacute;digo debe ser <strong>elegante y eficaz</strong>, la <strong>l&oacute;gica debe ser sencilla</strong> para evitar errores, el <strong>procesamiento de errores debe ser completo</strong>, el <strong>rendimiento debe ser &oacute;ptimo</strong>. Bjarne concluye que el c&oacute;digo limpio <strong>hace bien una &uacute;nica cosa</strong>.</p></div></div><div class="row mt-2"><div class="col-sm-9"><h3 class="mt-0">Grady Booch</h3><p>Es conocido entre otras cosas por ser uno de los dise&ntilde;adores del Lenguaje Unificado de Modelado UML.</p><p>Grady define que el c&oacute;digo limpio debe ser <strong>simple y directo</strong>. Adem&aacute;s el c&oacute;digo <strong>debe exponer la intenci&oacute;n</strong> del dise&ntilde;ador.</p></div><div class="col-sm-3"><p><img alt="Grady Booch" loading="lazy" src="/cache/thumb_1200/uploads/content/image/image/f755bee53e04e7fc5953612f473229b5be394256.jpg" title="Grady Booch"></p></div></div><div class="row mt-2"><div class="col-sm-3"><p><img alt="Dave thomas" loading="lazy" src="/cache/thumb_1200/uploads/content/image/image/ac935c6dad12174b783964ac57c0f63a6540819f.jpg" title="Dave thomas"></p></div><div class="col-sm-9"><h3 class="mt-0">Dave thomas</h3><p>Es el autor del libro pragmatic programmer que tambi&eacute;n nos gustar&iacute;a analizar.</p><p>Dave introduce la idea de que el c&oacute;digo limpio debe ser <strong>f&aacute;cil de modificar</strong> para alguien que no es el autor original. En su opini&oacute;n el c&oacute;digo debe tener tanto <strong>pruebas unitarias c&oacute;mo de aceptaci&oacute;n</strong>. Los <strong>nombres deben tener significado</strong>. El c&oacute;digo ofrece <strong>una &uacute;nica forma de hacer una determinada cosa</strong> a trav&eacute;s de una API clara.</p></div></div><div class="row mt-2"><div class="col-sm-9"><h3 class="mt-0">Michael Feathers</h3><p>Es el autor del libro working effectively with legacy code.</p><p>Michael considera que el c&oacute;digo limpio es aquel al que <strong>se le ha dado importancia</strong> y al mismo tiempo <strong>se ha mantenido sencillo</strong>. Seg&uacute;n Michael cuando te enfrentas a un c&oacute;digo limpio no existe una forma f&aacute;cil de mejorarlo, ya que el autor pens&oacute; en todos los aspectos posibles.</p></div><div class="col-sm-3"><p><img alt="Michael Feathers" loading="lazy" src="/cache/thumb_1200/uploads/content/image/image/68dcfa1ce0de8c7be21551b3a1ac7334988451e9.jpg" title="Michael Feathers"></p></div></div><div class="row mt-2"><div class="col-sm-3"><p><img alt="Ron Jeffires" loading="lazy" src="/cache/thumb_1200/uploads/content/image/image/a66b690433e5eea7b6c7ba98ef07d6e25bbe07d5.jpg" title="Ron Jeffires"></p></div><div class="col-sm-9"><h3 class="mt-0">Ron Jeffires</h3><p>Es uno de los tres desarrolladores de la metodolog&iacute;a eXtreme programming.</p><p>Ron nos indica que el c&oacute;digo limpio debe seguir las indicaciones de Ken Beck. En orden de prioridad <strong>debe contener pruebas</strong>, <strong>debe evitar la duplicidad</strong>, <strong>debe expresar los conceptos</strong> del dise&ntilde;o y <strong>debe mantenerse tan peque&ntilde;o c&oacute;mo sea posible</strong>.</p></div></div><div class="row mt-2"><div class="col-sm-9"><h3 class="mt-0">Ward Cunningham</h3><p>Es uno de los impulsores de la identificaci&oacute;n y estandarizaci&oacute;n de los patrones de dise&ntilde;o.</p><p>Seg&uacute;n Ward sabemos que estamos ante c&oacute;digo limpio cuando <strong>el c&oacute;digo hace lo que se espera que haga</strong>.</p></div><div class="col-sm-3"><p><img alt="Ward Cunningham" loading="lazy" src="/cache/thumb_1200/uploads/content/image/image/c49ee369ea6a530b2089de35bf5d506146374f0a.jpg" title="Ward Cunningham"></p></div></div><h2>&iquest;Qu&eacute; conclusiones sacamos?</h2><p>De todas estas entrevistas se extraen una serie de ideas m&aacute;s o menos comunes.</p><h3>Que haga lo que se espera que haga</h3><p>Nosotros en DEVTIA a esta regla la llam&aacute;mos: "No me mientas". Es tambi&eacute;n muy f&aacute;cil de entender cada funci&oacute;n y cada clase tiene que hacer exactamente, lo que se espera que haga. Adem&aacute;s esto debe ser evidente, no debo necesitar entrar a ver el m&eacute;todo para saber que puedo esperar de el.</p><h3>Peque&ntilde;o</h3><p>Esta es una regla f&aacute;cil de seguir y f&aacute;cil de entender. Cuanto m&aacute;s peque&ntilde;o sea nuestro c&oacute;digo m&aacute;s f&aacute;cil ser&aacute; que podamos modificarlo y mantenerlo. Depender&aacute; de cada proyecto y de cada equipo establecer los l&iacute;mites, pero un buen punto de partida podr&iacute;a ser que las funciones y las clases con sus m&eacute;todos colapsados deber&iacute;an poder visualizarse completamente en las pantallas que est&aacute; usando el equipo.</p><p>En los siguientes cap&iacute;tulos veremos muchos ejemplos para mejorar este aspecto.</p><h3>Sin duplicidad</h3><p>Un error claro de dise&ntilde;o es cuando necesitas copiar y pegar tu c&oacute;digo en diferentes sitios. A la larga esto va a introducir errores, ya que cuando alguien actualize una copia, probablemente olvidar&aacute; actualizar las dem&aacute;s.</p><h3>Debe tener tests</h3><p>Casi todos los autores han introducido la importancia de los tests. Tener una buena bater&iacute;a de test nos va a permitir trabajar con nuestro c&oacute;digo y poderlo modificar con seguridad de que si estamos rompiendo alguna cosa, los test nos van a avisar.</p><h2>La regla del boy scout</h2><p><img alt="La regla del boy scout" loading="lazy" src="/cache/thumb_1200_0200/uploads/content/image/image/e9f673dc381ac6d3e65ddb07eb0856d15af750d5.jpg" title="La regla del boy scout"></p><p>La regla del Boy Scout se trata de una regla muy sencilla. Originalmente se refiere a lo que hacen los Boy Scout cuando hacen una acampada: dejan el lugar en el que han estado un poco m&aacute;s limpio de como se lo encontraron.</p><p>Aplicado al desarrollo de software nos indica que si en nuestro d&iacute;a a d&iacute;a seg&uacute;n estamos trabajando en un proyecto podemos ir introduciendo peque&ntilde;as mejoras que el autor original no tuvo en cuenta, pero que para nosotros son evidentes. Estos peque&ntilde;os cambios, en los que podemos incluir desde cambio de nombres, extracci&oacute;n de m&eacute;todos, peque&ntilde;os refactorizaciones, soluci&oacute;n de bugs, ect, a lo largo de un periodo de tiempo generar&aacute; un grado de maduraci&oacute;n en el c&oacute;digo.</p>
]]></description><guid>https://devtia.com/post/que-es-el-codigo-limpio</guid><pubDate>Sat, 23 May 2020 15:40:32 +0200</pubDate></item></channel></rss>