<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>código 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>Fri, 17 Apr 2026 06:18:08 +0200</pubDate><lastBuildDate>Fri, 17 Apr 2026 06:18:08 +0200</lastBuildDate><generator>DEVTIA</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><ttl>3600</ttl><item><title>Prueba técnica: Criterios de evaluación</title><link>https://devtia.com/post/prueba-tecnica-criterios-de-evaluacion</link><description><![CDATA[<p>A continuaci&oacute;n queremos detallar c&oacute;mo valoramos la prueba t&eacute;cnica que realizamos en nuestro proceso de selecci&oacute;n.</p><p>Como candidatos nos ha tocado hacer multitud de pruebas, y nunca hemos recibido ning&uacute;n tipo de feedback, as&iacute; que ahora que nos toca a nosotros, creemos que es un buen momento para tratar a los dem&aacute;s como nos gustar&iacute;a que nos hubieran tratado.</p><p>Lo primero, esto no es un examen: es una opini&oacute;n. Algunos candidatos entran en controversia con nosotros, y esto es algo bastante desagradable. Por supuesto siempre estamos abiertos a que alguien nos explique algo, y muchas veces hemos aprendido cosas con las pruebas de los candidatos, pero entiende que es muy desagradable cuando un candidato quiere convencerte de algo que no es.</p><p>Al final, si crees que estamos equivocados, es posible, simplemente somos programadores como tu, y por supuesto a veces nos equivocamos.</p><h2>Candidato</h2><p>Una prueba t&eacute;cnica tiene que estar muy orientada al tipo de candidato que est&aacute;s buscando. No tiene mucho sentido hacer una prueba de algoritmia y patrones de dise&ntilde;o para un perfil que va a trabajar con wordpress.</p><p>En nuestro caso buscamos perfiles con varios a&ntilde;os de experiencia, con un conocimiento razonablemente bueno del framework con el que trabajamos, pero que todav&iacute;a tenga un buen margen de crecimiento junto a nosotros. Es decir buscamos a alguien que pueda ser productivo en un corto plazo, que pueda trabajar la mayor parte del tiempo de forma independiente, pero que el desarrollo profesional y el aprendizaje que puede adquirir con nosotros sea algo importante para &eacute;l.</p><h2>Descripci&oacute;n de la prueba</h2><p>Nuestra prueba es realmente sencilla. No voy a describirla aqu&iacute;, porque la cambiamos con cada proceso, pero b&aacute;sicamente pedimos que se instale un proyecto con symfony y que se programen un par de acciones, y alg&uacute;n comando. Todo ello sin dar ning&uacute;n tipo de instrucci&oacute;n acerca de c&oacute;mo hacerlo. Si acaso se insin&uacute;a ligeramente al candidato que sea creativo.</p><h2>Consejos iniciales</h2><div class="row"><div class="col-sm-8"><p>Siempre que te enfrentes a una prueba t&eacute;cnica deber&iacute;as leer el texto con calma al menos un par de veces y quiz&aacute;s una vez m&aacute;s una vez que has acabado.</p><p>No creer&aacute;s la cantidad de candidatos que olvidan realizar alguna parte.</p></div><div class="col-sm-4"><div class="reference"><p>Si tienes una hora para cortar un &aacute;rbol, deber&iacute;as dedicar la primera mitad para afilar tu hacha.</p></div></div></div><h2>Criterios de evaluaci&oacute;n</h2><p><img alt="Criterios de evaluaci&oacute;n" loading="lazy" src="/cache/thumb_1200_0400/uploads/content/image/image/d844c65025a3956a11f8981d40732b220e2f6014.jpg" title="Criterios de evaluaci&oacute;n loading="></p><p>Como ver&aacute;s en las cosas que evaluamos a continuaci&oacute;n. es una prueba tan sencilla en la que buscamos es que seas muy detallista en las peque&ntilde;as cosas.</p><p>Asignar&iacute;amos una puntuaci&oacute;n 1-10 para cada uno de los siguientes apartados, de forma que pudi&eacute;ramos valorar de forma justa y a la vez sencilla para nosotros. Los criterios de evaluaci&oacute;n no est&aacute;n en orden de importancia. Tampoco hacemos una media artimetica del resultado, simplemente es una gu&iacute;a para saber cuales son tus puntos fuertes y cuales son tus puntos debiles. El resultado de la prueba t&eacute;cnica, junto con la evaluaci&oacute;n personal que hagamos, ser&aacute; lo que nos ayude a decantarnos por uno u otro candidato.</p><div class="row"><div class="col-sm-4"><div class="reference mt-5"><p>El diablo est&aacute; en los detalles.</p></div></div><div class="col-sm-8"><h3>Ficheros INSTALL.md y README.md</h3><p>Son dos requisitos de la prueba. El primero debe contener las instrucciones de instalaci&oacute;n del proyecto y el segundo una breve explicaci&oacute;n de las decisiones que has tomado y por que.</p></div></div><p>El README.md es una de las partes m&aacute;s importantes de la prueba, ya que te da la oportunidad de explicar y justificar las decisiones que has tomado.</p><p>Pon atenci&oacute;n a las faltas de ortograf&iacute;a. No pasa nada, el que est&eacute; libre de pecado que tire la primera piedra, pero mi recomendaci&oacute;n es que si sueles cometer faltas de ortograf&iacute;a, lo pases por un corrector antes de enviarlo.</p><h3>Versiones</h3><p>Valoramos positivamente que utilices las &uacute;ltimas versiones disponibles, especialmente del lenguaje y del framework.</p><h3>Docker</h3><p>Valoramos positivamente que presentes tu prueba dentro de un contenedor.</p><h3>Coding Style</h3><p>Valoramos positivamente que presentes un coding style consistente y especialmente que lo definas expl&iacute;citamente de alguna forma, por ejemplo indicandolo en el README.md o incluyendo alg&uacute;n tipo de fichero de configuraci&oacute;n como .php-cs-fixer.dist.php indicando tus reglas de estilo.</p><h3>Alcance</h3><p>Como ya he dicho anteriormente. Aseg&uacute;rate de leer bien, lo que se pide. Muchos candidatos olvidan alguna peque&ntilde;a cosa. Es obvio que es un despiste. Pero no dice algo bueno de ti, que seas despistado en una prueba sencilla.</p><h3>Bundles</h3><p>Muchos candidatos utilizan bundles de la comunidad. Valoramos positivamente que puedas usar los bundles m&aacute;s conocidos. Nos indica que conoces el ecosistema.</p><h3>Comandos</h3><p>La prueba probablemente te pida que ejecutes un sencillo comando. Evaluaremos que hagas un uso eficaz de los comandos. Valoramos que el candidato demuestre que conoce c&oacute;mo funciona el componente configurando correctamente tanto los par&aacute;metros de entrada, como haciendo un uso correcto de la salida.</p><h3>Formularios</h3><p>Valoramos que el candidato demuestre que entiende bien c&oacute;mo funcionan, que sea capaz de crear un formulario y a&ntilde;adirle algunas validaciones.</p><h3>Doctrine</h3><p>Valoramos que el candidato entienda c&oacute;mo funciona doctrine. Declare entidades, repositorios y realice algunas queries sin cometer errores.</p><h3>Servicios</h3><p>Aunque la prueba no lo pide expresamente, se valora que el candidato trate de crear servicios y llevar la l&oacute;gica desde los controladores a estos.</p><h3>Assets / Frontend</h3><p>Se valora que el candidato haga un uso correcto de webpack o que incluya alg&uacute;n otro recurso de frontend.</p><h3>Pruebas</h3><p>Se valora que el candidato entregue una bater&iacute;a de pruebas de alg&uacute;n tipo, unitarias, funcionales y sea capaz de justificar en el README.md su elecci&oacute;n.</p><h2>&iquest;Qu&eacute; te ha parecido?</h2><p><img alt="&iquest;Qu&eacute; te ha parecido?" loading="lazy" src="/cache/thumb_1200_0600/uploads/content/image/image/7ecc9ad0cd5f24b7b50268654c9059b98035c48c.jpg" title="&iquest;Qu&eacute; te ha parecido?"></p><p>Por supuesto, queremos saber tu opini&oacute;n, &iquest;qu&eacute; te ha parecido la prueba y el proceso en general?, &iquest;hay algo que cambiar&iacute;as? &iquest;Crees que has tenido la oportunidad de demostrar tus capacidades? &iquest;Qu&eacute; te hubiera gustado poder hacer?</p>
]]></description><guid>https://devtia.com/post/prueba-tecnica-criterios-de-evaluacion</guid><pubDate>Fri, 04 Feb 2022 11:22:04 +0100</pubDate></item><item><title>empleo: backend developer php symfony remoto</title><link>https://devtia.com/post/backend-developer-php-symfony-remoto</link><description><![CDATA[<h2>&iquest;STRONGHOLD ASSET MANAGEMENT?</h2><p>Este es un anuncio para trabajar en: <a href="https://strongholdam.com/" target="_blank">STRONGHOLD ASSET MANAGEMENT</a>.</p><p>STRONGHOLD ASSET MANAGEMENT (SAM) es un fondo de inversi&oacute;n donde nos dedicamos a financiar operaciones de desarrollo inmobiliario. Es decir somos el socio capitalista para un promotor que quiere construir por ejemplo una promoci&oacute;n de chalets. SAM por lo tanto es una empresa a medio camino de una FINTECH y una PROPTECH. Puedes curiosear la web <a href="https://strongholdam.com/">https://strongholdam.com/</a> para entender un poco mejor qu&eacute; es lo que hacemos.</p><h2>Un poco de historia</h2><p>En torno al a&ntilde;o 2016 Matt Calner, nuestro socio director, lleg&oacute; a Madrid procedente de Londres, con la intenci&oacute;n de establecerse en Madrid. Seg&uacute;n sus propias palabras, la mejor ciudad del mundo.</p><p>Una vez aqu&iacute; se dio cuenta de que exist&iacute;a una posibilidad de negocio ya que hab&iacute;a dificultades para obtener financiaci&oacute;n inmobiliaria. Hab&iacute;a producto, hab&iacute;a mercado, pero el principal freno era la financiaci&oacute;n. Y con esta idea en la cabeza y esp&iacute;ritu emprendedor, se asoci&oacute; con algunos inversores, conocidos y amigos, y empezaron a hacer operaciones peque&ntilde;as, principalmente pr&eacute;stamos puente y reestructuraciones de deuda.</p><p>En el a&ntilde;o 2019 se fund&oacute; oficialmente SAM y en 2020 entr&oacute; como socio de referencia Goldman Sachs, <em>los que financian al FC Barcelona</em>, con una l&iacute;nea de cr&eacute;dito de 100 millones que ha ido incrementando con el paso del tiempo.</p><p>Dentro de este camino de maduraci&oacute;n de la compa&ntilde;&iacute;a, a mediados del a&ntilde;o 2020 nos contactan para desarrollar una plataforma que les ayude en su trabajo diario. Calculo de intereses, generaci&oacute;n de certificados, gesti&oacute;n documental, etc. Lo que ser&iacute;a un peque&ntilde;o proyecto de solo unos pocos meses nos llev&oacute; a finales del 2021 a incorporarnos a tiempo completo en la compa&ntilde;&iacute;a.</p><h3>Momento clave</h3><p>Durante el 2021, con una plantilla realmente peque&ntilde;a hemos sido capaces de financiar proyectos por un importe de m&aacute;s de 120 millones de euros y el objetivo es poder duplicar esa cifra cada a&ntilde;o. Creemos que es un momento clave para los objetivos de la compa&ntilde;&iacute;a, y queremos que nos ayudes a materializarlos.</p><h2>&iquest;Qu&eacute; cosas tenemos en mente?</h2><p>Estas entre otras cosas es lo que queremos hacer en el medio plazo.</p><ul><li>Continuar mejorando y optimizando las herramientas y procesos de la plataforma que ya tenemos.</li><li>Mejorar la inteligencia de negocio para ofrecer informaci&oacute;n &uacute;til en tiempo real.</li><li>Internacionalizar la compa&ntilde;&iacute;a.</li></ul><p>A nivel de IT nos gustar&iacute;a.</p><ul><li>Mejorar nuestras habilidades para producir c&oacute;digo cada vez m&aacute;s confiable, sostenido por una buena test suite, y que se pueda ampliar / modificar f&aacute;cilmente.</li><li>Innovar a&ntilde;adiendo nuevas piezas a nuestra infraestructura.</li></ul><h2>&iquest;Qu&eacute; vas a hacer?</h2><h3>En tus primeros d&iacute;as</h3><ul><li>Conocer a tus compa&ntilde;eros, familiarizarte con el entorno de trabajo y el c&oacute;digo que ya tenemos desarrollado.</li><li>Comenzar a asimilar toda la terminolog&iacute;a / conocimiento que necesitar&aacute;s para desarrollar tu trabajo.</li><li>Resolver algunas issues sencillas.</li></ul><h3>En algunas semanas</h3><ul><li>Resolver issues que requieran un mayor conocimiento del proyecto.</li><li>Gestionar tu trabajo diario, desde la toma de requisitos, hasta poner el c&oacute;digo en producci&oacute;n.</li></ul><h3>En algunos meses</h3><ul><li>Ayudar a definir y ejecutar la estrategia de IT, en base a los objetivos y necesidades de la compa&ntilde;&iacute;a. SAM es una empresa orientada a resultados.</li><li>Formar al equipo en aquello que creas que puedes aportar.</li></ul><h2>&iquest;Con que lo har&aacute;s?</h2><ul><li>La pieza principal de la arquitectura est&aacute; desarrollada en un monolito sobre Symfony 5.4 y PHP 8.1
	<ul><li>Nos preocupan los principios SOLID y el contenido del libro CLEAN CODE, aunque no somos talibanes.</li><li>Tenemos test funcionales ( smoke test ) + test unitarios, que se ejecutan adem&aacute;s de en local, en un entorno de integraci&oacute;n continua.</li></ul></li><li>Un poquito de javascript + bootstrap.</li><li>git + github.</li></ul><h2>&iquest;C&oacute;mo es el equipo?</h2><p>Ser&aacute;s el tercer compa&ntilde;ero de un peque&ntilde;o equipo de IT. Somos un equipo horizontal, aut&oacute;nomo y &aacute;gil. Tenemos total libertad para hacer lo que queramos.</p><h3>Alvaro Cebri&aacute;n</h3><p>Apasionado de la tecnolog&iacute;a y la inform&aacute;tica, le encanta probar todo tipo de tecnolog&iacute;as y lenguajes nuevos que van saliendo. Aunque a nivel profesional est&aacute; m&aacute;s enfocado en el desarrollo web, tambi&eacute;n le divierte programar mis aplicaciones de escritorio, en otros lenguajes como C o aplicaciones m&oacute;viles para Android.</p><ul><li><a href="https://www.linkedin.com/in/alvarocebriangarcia/">https://www.linkedin.com/in/alvarocebriangarcia/</a></li><li><a href="https://github.com/alvarocebrian">https://github.com/alvarocebrian</a></li></ul><h3>Daniel Gonz&aacute;lez</h3><p>Cree que nada es imposible si se hace con pasi&oacute;n y honestidad.</p><ul><li><a href="https://www.linkedin.com/in/desarrolla2/">https://www.linkedin.com/in/desarrolla2/</a></li><li><a href="https://github.com/desarrolla2">https://github.com/desarrolla2</a></li></ul><h2>&iquest;Qu&eacute; buscamos?</h2><h3>Indispensable</h3><ul><li>Experiencia consolidada en las todas o casi todas las siguientes tecnolog&iacute;as.
	<ul><li>PHP, Symfony, MySQL, Git, Linux, JavaScript, Bootstrap.</li></ul></li><li>S&oacute;lidos conocimientos de programaci&oacute;n.
	<ul><li>Principios SOLID, test unitarios y funcionales.</li></ul></li><li>Capacidad para entender y proponer soluciones a problemas de negocio. No nos pagan por resolver issues, nos pagan por ayudar a la compa&ntilde;&iacute;a a llegar al siguiente nivel.</li><li>Alto rendimiento en el d&iacute;a a d&iacute;a, somos un equipo peque&ntilde;o, pero muy productivo.</li></ul><h3>Interesante</h3><ul><li>Conocimientos en el mundo financiero y/o del mercado inmobiliario.</li><li>Anal&iacute;tica de datos.</li><li>Comunicaci&oacute;n en ingl&eacute;s.</li><li>Docker.</li></ul><h2>&iquest;Qu&eacute; ofrecemos?</h2><ul><li>Lo b&aacute;sico
	<ul><li>Contrato indefinido / 23 d&iacute;as de vacaciones / flexibilidad horaria.</li><li>100% remoto, o si lo prefieres puedes venir a nuestra oficina en Castellana 60, Madrid.</li><li>40k - 70k brutos anuales.</li></ul></li><li>Otros perks:
	<ul><li>Formaci&oacute;n continua.</li><li>Cheques restaurante / guarder&iacute;a / transporte / seguro m&eacute;dico.</li><li>Viaje anual de toda la compa&ntilde;ia. Viaje a una conferencia del equipo de IT.</li></ul></li></ul><h2>&iquest;Quieres participar?</h2><p>Si estas interesad@ &iexcl;Queremos crecer junt@s!.</p><p><a class="btn btn--red" href="/work-with-us/as-developer/" style="margin-top:20px">aplica aqu&iacute;</a></p>
]]></description><guid>https://devtia.com/post/backend-developer-php-symfony-remoto</guid><pubDate>Mon, 12 Jul 2021 10:29:29 +0200</pubDate></item><item><title>Buenas prácticas</title><link>https://devtia.com/post/buenas-practicas</link><description><![CDATA[<p>Para la ejecuci&oacute;n de un buen proyecto de desarrollo de software es necesario que el equipo de desarrollo se preocupe por implementar una serie de buenas pr&aacute;cticas de trabajo.</p><p>En esta entrada queremos explicarte algunas de las buenas pr&aacute;cticas que implementamos en el equipo.</p><h2>C&Oacute;DIGO LIMPIO</h2><p>Cuando hablamos de c&oacute;digo limpio nos referimos a buenas pr&aacute;cticas en el desarrollo de software descritos por <strong>Robert C Martin</strong> en su libro <strong>&ldquo;C&oacute;digo Limpio&rdquo;</strong>, del que puedes encontrar mucha informaci&oacute;n en esta serie de entradas que hemos publicado.</p><p>El seguimiento de las indicaciones que se aportan genera proyectos que son m&aacute;s f&aacute;ciles de mantener en el tiempo.</p><h2>PROGRAMACI&Oacute;N EN PAREJAS</h2><p>La programaci&oacute;n en parejas es un <strong>concepto propuesto por Ken Beck</strong> en su libro &ldquo;<strong>Programaci&oacute;n extrema&rdquo;</strong>. La idea que subyace detr&aacute;s de su propuesta es que si bien, dos programadores que trabajan juntos van a producir menos l&iacute;neas de c&oacute;digo, el que generen ser&aacute; de mayor calidad, por lo que de forma efectiva el equipo va m&aacute;s r&aacute;pido.</p><p>Nosotros implementamos una versi&oacute;n de lo que &eacute;l propone. Cada programador trabaja de forma independiente la mayor&iacute;a del tiempo, pero programamos por parejas cuando alguien necesita ayuda o est&aacute; tocando algo muy delicado.</p><h2>PRUEBAS AUTOM&Aacute;TICAS</h2><p>Las pruebas autom&aacute;ticas es un software dise&ntilde;ado para probar el software, valga la redundancia, en el que se est&aacute; trabajando.</p><p>El uso de pruebas autom&aacute;ticas a&ntilde;ade muchas ventajas al desarrollo, pero sobre todo la principal ventaja desde el punto de vista del cliente es un <strong>producto digital con menos errores y con mayor facilidad para ser modificado.</strong></p><h2>INTEGRACI&Oacute;N CONTINUA</h2><p><strong>Integraci&oacute;n continua es una pr&aacute;ctica muy relacionada con el desarrollo &aacute;gil</strong>, seg&uacute;n la cual la bater&iacute;a de pruebas se ejecuta de manera autom&aacute;tica en un servidor remoto con cada cambio en el c&oacute;digo.</p><h2>RESUMEN</h2><div class="row"><div class="col-sm-4"><p>No hay una <strong>f&oacute;rmula m&aacute;gica que garantice el &eacute;xito de un proyecto</strong>, sin embargo si que hay un <strong>conjunto de buenas pr&aacute;cticas</strong> que nos sirvan para no perder el rumbo. Por nuestra parte, nuestra f&oacute;rmula del &eacute;xito es la siguiente resprsentaci&oacute;n.</p></div><div class="col-sm-8"><p><img alt="Happy Client" loading="lazy" src="/cache/thumb_1200_0800/uploads/content/image/image/a1a510f96d01e92b04994195a3216e4ea5d3033d.png" title="Nuestra f&oacute;rmula para ser un Cliente Feliz"></p></div></div>
]]></description><guid>https://devtia.com/post/buenas-practicas</guid><pubDate>Thu, 11 Mar 2021 10:36:04 +0100</pubDate></item><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>Sorteo 3 ejemplares del clean code para los miembros de la academia</title><link>https://devtia.com/post/sorteo-de-3-ejemplares-del-clean-code-para-los-miembros-de-la-academia</link><description><![CDATA[<p><em>Photo by Naim Benjelloun from Pexels</em></p><div class="alert alert-warning alert-dismissible"><h6>&iexcl;Atenci&oacute;n!</h6>
Esta es una entrada incompleta. Iremos actualizando con la lista de ids definitivos y con los resultados del sorteo.</div><p>La academia es una iniciativa sin &aacute;nimo de lucro en la que tratamos de construir una comunidad de personas que quieren mejorar sus capacidades como desarrolladores. Cada semana enviamos un nuevo video de unos 5 minutos con t&eacute;cnicas, trucos y consejos relacionados con el desarrollo de software y las buenas pr&aacute;cticas. Si esto te resulta interesante, al final de esta entrada tienes un formulario para apuntarte.</p><p>Adem&aacute;s ocasionalmente sorteamos algunos libros entre los miembros de la academia. Si quieres participar en este sorteo, tan s&oacute;lo tienes que inscribirte y activar tu cuenta antes del d&iacute;a 18 de Octubre a las 23:59.</p><p>En esta entrada se describen las bases y los resultados del sorteo de tres ejemplares del libro clean code que realizaremos los d&iacute;as 19 de Octubre de 2020 y sucesivos, hasta que aparezca un ganador.</p><h2>Premio</h2><p>Se van a sortear tres ejemplares del libro clean code publicado en el a&ntilde;o 2008 por Robert C Martin. Nos pondremos en contacto de forma privada con los ganadores.</p><h2>Sorteo</h2><ul><li>Cada usuario recibe un correo semanal, con un video relacionado con el desarrollo de software. En el p&iacute;e de dicho correo mismo aparece su id de usuario.</li><li>Se consideran usuarios activos aquellos, que han completado el formulario de registro y han confirmado su direcci&oacute;n de correo electronico.
	<ul><li>Los <strong>id de usuario activos en el momento de realizar el sorteo son</strong> los siguientes: 001, 006, 008, 009, 010, 013, 014, 015, 016, 017, 019, 021, 022, 023, 024, 025, 026, 027, 028, 029, 031, 034, 035, 036, 037, 038, 039, 040, 041, 042, 043, 044, 045, 046, 047, 048, 049, 050, 051, 052, 053, 054, 055, 058, 060, 061, 066, 067, 069, 070, 071, 072, 073, 074, 075, 077, 078, 079, 080, 081, 084, 085, 086, 087, 090, 091, 092, 093, 094, 095, 096, 098, 099, 101, 103, 104, 105, 106, 107, 108, 110, 112, 113, 114, 115, 117, 118, 119, 121, 122, 123, 124, 125, 126, 127, 128, 130, 131, 134, 135, 136, 137, 138, 139.</li></ul></li><li>Los n&uacute;meros se obtendr&aacute;n del sorteo del cup&oacute;n diario de la once, siendo el primer resultado v&aacute;lido el sorteo del d&iacute;a 19 de Octubre de 2020.
	<ul><li>Si el id es <strong>menor que 100 resultar&aacute;s ganador con los resultados pares de las centenas</strong>. Por ejemplo el id 001, resultar&aacute; ganador con el 001, 201, 401, 601 y 801.</li><li>Si el id es <strong>superior a 100 resultar&aacute;s ganador con los resultados impares de las centenas</strong>. Por ejemplo el id 101, resultar&aacute; ganador con el 101, 301, 501, 701 y 901.</li></ul></li><li>Si un resultado no se corresponde con ninguno de los ids activos, se utilizar&aacute; el resultado del d&iacute;a siguiente.</li><li>Gastos de env&iacute;o.
	<ul><li>Si se puede enviar sin gastos de env&iacute;o via amazon prime se enviar&aacute; sin gastos de env&iacute;o.</li><li>Si no se puede, se le pedir&aacute;n al destinatario que se haga cargo de los gastos de env&iacute;o o se pasar&aacute; al resultado del d&iacute;a siguiente.</li></ul></li><li>El sorteo continuar&aacute; hasta que tengamos tres ganadores.</li></ul><h2>Resultados</h2><div class="table-responsive"><table class="table table-striped table-hover"><thead><tr><th class="col-sm">Sorteo del d&iacute;a</th><th class="col-sm text-right">Resultado</th><th class="col-sm text-right">Ganador</th></tr></thead><tbody><tr><td>19 de Octubre</td><td class="text-right">13,840</td><td class="text-right">040</td></tr><tr><td>20 de Octubre</td><td class="text-right">53,104</td><td class="text-right">104</td></tr><tr><td>21 de Octubre</td><td class="text-right">91,067</td><td class="text-right">067</td></tr></tbody></table></div>
]]></description><guid>https://devtia.com/post/sorteo-de-3-ejemplares-del-clean-code-para-los-miembros-de-la-academia</guid><pubDate>Sat, 10 Oct 2020 18:40:26 +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></channel></rss>