[{"content":"En desarrollo de software es habitual asumir que las releases forman parte natural del proceso de Scrum; que ocurren al final de un sprint, que agrupan todas las historias planificadas o que representan el último estado del flujo de trabajo. Sin embargo, esta asociación es más cultural que real. Aunque lo parezca, las releases no dependen de Scrum, ni del estado de tus historias, ni de lo que hayas decidido planificar en un sprint.\nUna release es, ante todo, una decisión de entrega. Es el momento en el que decides poner una versión concreta de tu software en manos de usuarios o en producción. Scrum, en cambio, es un framework de gestión del trabajo. Te ayuda a estructurar cómo desarrollas el producto, a inspeccionar el progreso y a mejorar continuamente, pero scrum no define cuándo ni cómo debes entregar software.\nCuando trabajas con Scrum, cada sprint produce un incremento potencialmente liberable. Esa expresión es clave. Potencialmente significa que puede liberarse, no que deba liberarse. Que una funcionalidad esté terminada desde el punto de vista del equipo no implica que tenga que formar parte de una release inmediata, ni siquiera de la siguiente. Puedes tener software terminado que no se libera, o que se libera junto con otros cambios desarrollados en momentos completamente distintos.\nEl flujo de estados de las historias de usuario tampoco define las releases. Ese flujo existe para darte visibilidad y control del trabajo, no para gobernar la entrega. Una historia puede llegar a Done y quedarse ahí. Otra puede liberarse sin que el resto del sprint esté completo. Incluso puedes liberar cambios que no están asociados a una historia visible para negocio, como refactors, mejoras técnicas o correcciones internas. El tablero describe el trabajo; no decide la publicación.\nTampoco existe una obligación de sincronizar las releases con el cierre del sprint. Aunque muchas organizaciones lo hacen por comodidad o tradición, no hay nada en Scrum que lo exija. Puedes liberar a mitad del sprint, varias veces dentro del mismo sprint o después de varios sprints sin liberar nada. El sprint marca el ritmo de trabajo; la release responde a necesidades de negocio, riesgo o contexto operativo. Son relojes distintos y forzarlos a coincidir suele generar fricción innecesaria.\nEsta separación se entiende con especial claridad cuando trabajas con entrega continua (Continuous Delivery). En este modelo, cada cambio que supera el pipeline de CI/CD queda listo para ser liberado. Si completas una historia el tercer día del sprint y pasa todas las pruebas automatizadas, puedes ponerla en producción inmediatamente, sin esperar al Sprint Review ni al cierre del sprint. El sprint continúa, el equipo sigue trabajando y la release ocurre cuando aporta valor, no cuando lo dicta el calendario.\nEn el desarrollo de backend esta independencia es todavía más evidente. Es habitual hacer múltiples releases al día, desplegar cambios invisibles para el usuario final o liberar funcionalidades protegidas por feature flags. Se utilizan técnicas como compatibilidad hacia atrás, despliegues progresivos o rollbacks rápidos. Nada de esto necesita alinearse con un sprint ni con el estado global del tablero.\nScrum sí juega un papel importante, pero no como mecanismo de entrega. Te ayuda a producir software de calidad, a mantener un ritmo sostenible y a tener claridad sobre qué está realmente terminado. Eso facilita decidir cuándo liberar, pero no te obliga a hacerlo de una forma concreta.\nEntender esta diferencia te permite dejar de forzar releases artificiales, evitar acoplamientos innecesarios y asumir una idea fundamental: liberar software es una decisión consciente e independiente. Scrum te ayuda a construirlo bien; la release decide cuándo ese valor llega al mundo real.\n","id":0,"tag":"Product owner","title":"Las releases no están ligadas a Scrum","url":"https://metrosetenta.es/blog/las-releases-no-estan-ligadas-a-scrum/"},{"content":"La batalla entre producción y calidad no es exclusiva del desarrollo de software; se da en todas las industrias. En la manufactura, por ejemplo, Henry Ford revolucionó la producción con la línea de ensamblaje, permitiendo fabricar automóviles a una velocidad sin precedentes. Sin embargo, este enfoque sacrificaba la personalización y, en algunos casos, la durabilidad de los vehículos. En la industria de la moda, las marcas de fast fashion logran lanzar nuevas colecciones en semanas, pero a menudo a costa de la calidad de los materiales y la sostenibilidad.\nEn el desarrollo de software, esta tensión también existe: algunos desarrolladores priorizan la entrega rápida de funcionalidades, mientras que otros se enfocan en la solidez y estabilidad del código. Como Product Owner, tu papel es comprender estos dos enfoques y gestionarlos adecuadamente para el éxito de tu proyecto.\nPerfil 1: El Desarrollador Enfocado en la Velocidad Este tipo de desarrollador se caracteriza por su rapidez en la implementación de historias de usuario. Su principal objetivo es entregar funcionalidad lo antes posible, asegurándose de que el \u0026ldquo;happy path\u0026rdquo; funcione correctamente. Sin embargo, puede omitir aspectos cruciales como:\nGestión de errores y excepciones. Manejo de casos extremos o inusuales. Calidad del código y buenas prácticas. Pruebas exhaustivas, incluyendo pruebas unitarias y de integración. Pros: Rapidez en la entrega de nuevas funcionalidades. Capacidad de reacción ágil ante cambios y prioridades del negocio. Prototipado rápido de ideas y conceptos. Contras: Mayor riesgo de errores en producción. Código difícil de mantener y extender. Necesidad de retrabajo frecuente para corregir problemas no considerados inicialmente. Perfil 2: El Desarrollador Enfocado en la Robustez Este perfil prioriza la estabilidad y la calidad del código. Asegura que la solución no solo funcione en el \u0026ldquo;happy path\u0026rdquo;, sino que también contemple excepciones, validaciones y pruebas rigurosas. Es meticuloso con la arquitectura y sigue buenas prácticas de desarrollo.\nPros: Código más estable, mantenible y escalable. Menos fallos en producción. Reducción del costo de mantenimiento a largo plazo. Contras: Mayor tiempo de implementación. Posible sobreingeniería si no se gestiona adecuadamente. Riesgo de retraso en la entrega de funcionalidades críticas para el negocio. La \u0026ldquo;Best Simple Way\u0026rdquo; y su Relación con el Desarrollo Ágil Una noción interesante que puede influir en este debate es el concepto de la \u0026ldquo;best simple way\u0026rdquo;. Este enfoque, discutido en este artículo, propone que el mejor sistema es el más sencillo que puedas construir, dado el contexto y los requisitos actuales. Esto no debe confundirse con dejar \u0026ldquo;corner cases\u0026rdquo; detectados sin gestionar. La clave está en crear una solución que funcione de manera efectiva para el presente sin sobrecomplicar el sistema, pero siempre considerando las posibles fallas y casos extremos. A medida que el producto evoluciona, puedes ir añadiendo robustez y refinamiento según lo demanden los usuarios y las circunstancias.\nTensiones entre Ambos Perfiles y Cómo Aliviarlas La coexistencia de estos dos perfiles en un mismo equipo puede generar fricciones. Los desarrolladores orientados a la velocidad pueden frustrarse con los procesos de validación y pruebas que consideran innecesarios, mientras que los enfocados en la robustez pueden sentir que se sacrifica la calidad en favor de una entrega apresurada. Esta tensión puede derivar en conflictos, reprocesos y un ambiente de trabajo menos colaborativo.\nPara aliviar estas tensiones, puedes tomar las siguientes medidas:\nFomentar la empatía y el entendimiento mutuo: Organiza sesiones donde cada perfil exponga su enfoque y los beneficios que aporta al equipo. Establecer estándares comunes: Define reglas claras sobre cuándo priorizar rapidez y cuándo es imprescindible profundizar en la robustez. Asignación equilibrada de tareas: Combina ambos perfiles en proyectos o tareas específicas para aprovechar sus fortalezas y mitigar sus debilidades. Revisiones de código colaborativas: Impulsa revisiones entre desarrolladores con enfoques distintos para asegurar un balance entre velocidad y calidad. Feedback continuo: Mantén una comunicación abierta donde ambos perfiles puedan expresar preocupaciones y proponer mejoras. Cómo Gestionar Ambos Perfiles desde el Rol de Product Owner Antes de definir estrategias concretas, es fundamental reconocer que, aunque ciertas prácticas de desarrollo deben ser innegociables (como la seguridad, las pruebas críticas o la gestión de excepciones), siempre es conveniente acordar con el negocio, los clientes y los interesados cuál será el equilibrio adecuado entre calidad y velocidad de producción. Encontrar este balance garantizará que el software cumpla con los objetivos estratégicos sin comprometer su estabilidad a largo plazo.\nEl equilibrio entre velocidad y robustez es clave para el éxito de un producto digital. Como Product Owner, puedes tomar ciertas acciones para gestionar ambos perfiles dentro del equipo:\nDefinir criterios de aceptación claros: Asegura que las historias de usuario incluyan requisitos funcionales y no funcionales, como gestión de errores y validaciones. Priorizar el código de calidad: Fomenta revisiones de código, pair programming y buenas prácticas para que los desarrolladores que priorizan la velocidad no sacrifiquen la calidad. Promover una cultura de testing: Incluye pruebas unitarias y de integración como parte de la definición de \u0026ldquo;done\u0026rdquo;. Fomentar la colaboración: Haz que los desarrolladores con mentalidades opuestas trabajen juntos en tareas específicas para equilibrar rapidez con robustez. Asegurar entregas incrementales: Implementa historias de usuario en pequeños incrementos que permitan validar funcionalidades sin comprometer la estabilidad del sistema. Revisar incidentes en producción: Si detectas fallos recurrentes debido a código apresurado, es momento de reforzar la importancia de la calidad en el equipo. Equilibrar la planificación: Establece expectativas realistas sobre el tiempo necesario para desarrollar correctamente una funcionalidad, sin frenar excesivamente a los desarrolladores rápidos ni presionar demasiado a los meticulosos. Conclusión En un equipo de desarrollo, tanto la velocidad como la robustez son cualidades valiosas. Tu desafío como Product Owner es fomentar un balance entre ambos enfoques, asegurando que el producto se entregue a tiempo sin comprometer su calidad. A través de una gestión efectiva, revisiones de código y criterios de aceptación sólidos, puedes aprovechar lo mejor de cada perfil y construir un software estable, escalable y alineado con las necesidades del negocio.\n","id":2,"tag":"Product owner","title":"La batalla entre producción y calidad","url":"https://metrosetenta.es/blog/la-batalla-entre-produccion-y-calidad/"},{"content":"En un proyecto de software, las decisiones de alto nivel las puedes documentar en un formato estándar conocido como ADR (Architecture Decision Record). Los ADR son documentos cortos y claros que capturan información clave sobre decisiones arquitectónicas y de diseño importantes. A continuación, te explico cómo puedes documentar y compartir estas decisiones:\nFormato típico de un ADR Título: Escribe un título descriptivo que resuma la decisión. Contexto: Explica el problema o situación que te llevó a tomar la decisión. Incluye antecedentes técnicos, restricciones y objetivos del proyecto. Decisión: Describe la solución o enfoque que seleccionaste, de manera clara y concisa. Razonamiento: Justifica la decisión, incluyendo pros y contras, alternativas evaluadas y las razones por las que las descartaste. Consecuencias: Detalla los efectos de la decisión, incluyendo beneficios, riesgos y posibles desafíos futuros. Fecha: Registra la fecha en que tomaste la decisión. Estado: Indica el estado actual de la decisión (por ejemplo, propuesta, aceptada, rechazada o reemplazada). Buenas prácticas para documentar ADRs Centraliza la información: Guarda los ADR en un repositorio accesible para todo el equipo, como un repositorio de código (por ejemplo, Git) o una herramienta de documentación (por ejemplo, Confluence o Notion). Usa un formato consistente: Esto facilita que todos los interesados lean y comprendan los documentos. Mantén los ADR actualizados: Si cambias una decisión, crea un nuevo ADR que documente el cambio y haga referencia al anterior. Hazlos visibles: Proporciona enlaces desde herramientas de gestión de proyectos o bases de conocimiento para que los interesados los encuentren fácilmente. Evita documentos excesivamente largos: Asegúrate de que los ADR sean breves y directos; si es necesario, incluye enlaces a documentación más detallada. Aquí puedes consultar información sobre plantillas de ADRs.\nHerramientas para gestionar ADRs Repositorios de código (Git): Crea un directorio docs/adr/ o similar para mantener los ADR versionados junto con el código. Herramientas colaborativas: Usa herramientas como Confluence, Notion o Google Docs para facilitar el acceso y la edición colaborativa. Plantillas: Usa plantillas prediseñadas para asegurar la uniformidad en todos los ADR. Este enfoque te asegura que todos los interesados, incluidos desarrolladores, QA y stakeholders, tengan acceso a un historial claro y bien documentado de las decisiones clave del proyecto.\nGestión de ADRs con Azure DevOps En un proyecto gestionado con Azure DevOps, puedes integrar los ADRs (Architecture Decision Records) de manera efectiva aprovechando las capacidades de documentación, repositorios de código y la integración con herramientas de colaboración que ofrece la plataforma. Aquí tienes un enfoque recomendado:\n1. Usar un repositorio Git en Azure DevOps Ubicación: Crea un directorio específico para los ADRs dentro del repositorio principal del proyecto, por ejemplo, docs/adr/. Estructura: Guarda cada ADR como un archivo Markdown (.md) nombrado de manera secuencial y descriptiva, como 001-elegir-base-de-datos.md. Ventajas: Tienes versionado automático con Git. Puedes enlazar a commits o pull requests que implementan la decisión. Es compatible con revisiones a través de pull requests. 2. Wiki de Azure DevOps Descripción: Usa la funcionalidad de Wiki de Azure DevOps para documentar los ADR en una sección específica. Acceso: Asegúrate de que el Wiki esté accesible para todos los miembros del equipo y que tenga permisos de lectura para los stakeholders que no son desarrolladores. Organización: Crea una página principal llamada \u0026ldquo;ADRs\u0026rdquo; que enlace a páginas individuales para cada decisión. Organiza las decisiones por fecha o categorías. Ventajas: Ofreces una interfaz amigable para no desarrolladores. Facilitas la búsqueda y navegación. 3. Incorporar ADRs en Work Items Enlace a Work Items: Vincula los ADR relevantes a Work Items de Azure DevOps (por ejemplo, Epics, Features, o User Stories). Usa el campo de descripción o los comentarios para incluir enlaces directos a los ADR en el repositorio o Wiki. Beneficio: Esto permite que los desarrolladores y QA comprendan el contexto de decisiones arquitectónicas mientras trabajan en tareas específicas. 4. Automatizar con Azure Pipelines Validación y consistencia: Configura Azure Pipelines para automatizar revisiones de ADR, como: Verificar que los archivos estén en el formato correcto. Asegurar que cada ADR tenga los campos requeridos (por ejemplo, contexto, decisión, razones, consecuencias). Notificaciones: Configura notificaciones para el equipo cada vez que crees o modifiques un ADR. 5. Integración con Dashboards Widgets personalizados: Usa los dashboards de Azure DevOps para mostrar: Un resumen de los ADR más recientes. Enlaces directos al repositorio o al Wiki. Estado de las decisiones: Implementa un widget que muestre el estado de las decisiones clave (aceptado, en revisión, rechazado). 6. Políticas de mantenimiento Actualización de ADRs: Define un proceso claro para actualizar ADR cuando cambien las decisiones. Revisión periódica: Asigna responsables para revisar regularmente la relevancia y precisión de los ADR. Ejemplo de flujo en Azure DevOps: Decisión inicial: Crea un ADR en docs/adr/001-elegir-base-de-datos.md. Discusión y aprobación: Revisa el documento mediante un pull request en Azure Repos. Implementación: Vincula el ADR a los Work Items relacionados. Documentación accesible: Refleja la decisión final en la Wiki y enlázala desde los dashboards o pipelines relevantes. Este enfoque te asegura que los ADR estén centralizados, versionados y fácilmente accesibles para todos los miembros del proyecto, desde desarrolladores hasta stakeholders.\n","id":3,"tag":"Fundamentos arquitectura","title":"Registro de decisiones arquitectónicas","url":"https://metrosetenta.es/blog/registro-de-decisiones-arquitectonicas/"},{"content":"Web 3.0, la tercera generación de internet, está revolucionando la manera en que interactuamos en línea, proporcionando un ecosistema más descentralizado, seguro y transparente. A medida que esta tecnología avanza, surgen nuevas aplicaciones que aprovechan las características únicas de Web 3.0, cambiando radicalmente diversas industrias y servicios. A continuación, exploramos algunos de los casos de uso más destacados de Web 3.0, tanto actuales como futuros.\nAplicaciones Actuales de Web 3.0 Finanzas Descentralizadas (DeFi): DeFi es uno de los casos de uso más prominentes de Web 3.0, permitiendo la creación de servicios financieros sin intermediarios tradicionales como bancos o corredores. A través de contratos inteligentes, plataformas DeFi facilitan préstamos, intercambios, staking y otros servicios financieros de manera automatizada y descentralizada. Ejemplos de aplicaciones DeFi incluyen Uniswap, Aave y Compound.\nOrganizaciones Autónomas Descentralizadas (DAOs): Las DAOs son organizaciones gestionadas y gobernadas por contratos inteligentes en la blockchain, sin necesidad de una autoridad central. Esto permite una gobernanza más transparente y democrática, donde los miembros pueden votar sobre decisiones clave. DAOs como MakerDAO y Uniswap son ejemplos de cómo se puede gobernar una organización de manera descentralizada.\nAplicaciones Descentralizadas (DApps): DApps son aplicaciones que funcionan en una red blockchain, lo que significa que no dependen de servidores centralizados. Estas aplicaciones son más seguras y resistentes a la censura. Un ejemplo popular de una DApp es OpenSea, un mercado descentralizado para la compra y venta de NFTs.\nIdentidad Digital Descentralizada: Web 3.0 está impulsando la creación de identidades digitales que permiten a los usuarios controlar sus datos personales sin depender de grandes corporaciones. Proyectos como Sovrin y uPort están desarrollando sistemas de identidad digital descentralizada que permiten a los usuarios gestionar sus datos de manera segura y privada.\nNFTs (Tokens No Fungibles): Los NFTs son tokens únicos que representan la propiedad de un activo digital, como obras de arte, música o bienes virtuales en videojuegos. Estos tokens han transformado industrias creativas al proporcionar una forma de verificar la autenticidad y la propiedad de los activos digitales. Ejemplos de aplicaciones incluyen marketplaces como OpenSea y juegos como Axie Infinity.\nAplicaciones Futuras de Web 3.0 Interoperabilidad entre Blockchains: Uno de los desafíos actuales es la falta de comunicación entre diferentes blockchains. El futuro de Web 3.0 verá un aumento en la interoperabilidad, permitiendo que diferentes redes blockchain interactúen entre sí. Esto abrirá nuevas posibilidades para aplicaciones que puedan operar a través de múltiples blockchains, aumentando su funcionalidad y alcance.\nMetaverso Descentralizado: El concepto del metaverso, un universo virtual compartido, está ganando terreno gracias a Web 3.0. A medida que la tecnología blockchain evoluciona, el metaverso descentralizado permitirá a los usuarios poseer y comerciar activos digitales, como tierras virtuales y objetos de juegos, en un entorno completamente interoperable y descentralizado.\nRedes Sociales Descentralizadas: Las redes sociales actuales están controladas por grandes corporaciones que manejan y monetizan los datos de los usuarios. Las redes sociales descentralizadas prometen un cambio radical, permitiendo a los usuarios tener el control total sobre sus datos y la monetización de su contenido. Proyectos como Mastodon y Diaspora están liderando el camino hacia una nueva generación de redes sociales.\nSupply Chain Management (Gestión de la Cadena de Suministro): La tecnología blockchain puede ser utilizada para mejorar la transparencia y la trazabilidad en las cadenas de suministro. Empresas en todo el mundo están explorando cómo Web 3.0 puede permitir un seguimiento más eficiente y transparente de los productos desde la fabricación hasta el consumidor final, asegurando la autenticidad y reduciendo el fraude.\nGobierno Digital Descentralizado: En el futuro, Web 3.0 podría facilitar la creación de gobiernos digitales más transparentes y eficientes, utilizando blockchain para la gestión de registros públicos, votaciones electrónicas y la distribución de servicios sociales de manera justa y verificable.\nConclusión Web 3.0 está redefiniendo la forma en que interactuamos con la tecnología y cómo se gestionan los servicios digitales. Desde las finanzas hasta la identidad digital, las aplicaciones actuales y futuras de Web 3.0 están transformando industrias y creando nuevas oportunidades. A medida que esta tecnología evoluciona, el potencial para nuevas innovaciones sigue siendo enorme, y aquellos que se adentren en este mundo ahora tendrán la ventaja de estar a la vanguardia de la próxima gran ola de la evolución digital.\n","id":4,"tag":"Web3 ; Blockchain","title":"Casos de uso de Web 3.0: aplicaciones actuales y futuras","url":"https://metrosetenta.es/blog/casos-uso-web-3-0/"},{"content":"La descentralización es uno de los pilares más importantes de Web 3.0. A diferencia de los modelos centralizados de Web 2.0, donde los datos y el poder se concentran en manos de unas pocas entidades, Web 3.0 se basa en la distribución del control a través de una red de nodos independientes. Pero, ¿por qué es tan crucial la descentralización para la próxima generación de internet?\n¿Qué es la Descentralización? La descentralización en el contexto de Web 3.0 significa que ninguna entidad única controla toda la red. En lugar de depender de servidores centralizados que son vulnerables a ataques, censura y fallas, Web 3.0 utiliza redes descentralizadas que están compuestas por muchos nodos independientes. Cada nodo mantiene una copia del registro de datos y participa en el proceso de verificación, lo que garantiza la integridad y la disponibilidad de la red.\nRazones por las que la Descentralización es Importante en Web 3.0 Resistencia a la Censura: En una red descentralizada, no hay una sola autoridad que pueda censurar o controlar el flujo de información. Esto es especialmente importante en regiones donde la libertad de expresión está limitada. La descentralización permite a los usuarios compartir información sin temor a ser silenciados por una entidad central.\nMayor Seguridad: Las redes centralizadas son objetivos atractivos para los hackers porque concentran muchos datos valiosos en un solo lugar. La descentralización distribuye esos datos a través de una red de nodos, haciendo que sea mucho más difícil y costoso para los atacantes comprometer la red en su totalidad.\nConfianza sin Intermediarios: En Web 2.0, los usuarios deben confiar en intermediarios, como bancos o plataformas de redes sociales, para manejar sus datos y transacciones. Web 3.0 elimina la necesidad de estos intermediarios mediante el uso de contratos inteligentes y tecnología blockchain, permitiendo transacciones directas entre usuarios con total transparencia.\nPropiedad de los Datos: En las plataformas centralizadas, las corporaciones suelen tener control sobre los datos del usuario y pueden utilizarlos para su propio beneficio, a menudo sin el consentimiento explícito del usuario. En un sistema descentralizado, los usuarios tienen el control total sobre sus datos y deciden cómo y con quién compartirlos.\nFomento de la Innovación y la Inclusión: La descentralización abre la puerta a la innovación al permitir que cualquier persona contribuya a la red. Los desarrolladores pueden crear aplicaciones sin necesidad de permisos de una autoridad central, fomentando un ecosistema más inclusivo y diverso.\nConclusión La descentralización es fundamental para la visión de Web 3.0 porque empodera a los usuarios, mejora la seguridad y promueve la transparencia y la inclusión. Al distribuir el control y la propiedad, Web 3.0 crea una web más justa y democrática, alineada con los principios de apertura y libertad que guían la evolución de internet. Al entender la importancia de la descentralización, podemos apreciar cómo Web 3.0 está configurando un nuevo paradigma para el futuro de la web.\n","id":5,"tag":"Web3 ; Descentralización ; Blockchain","title":"Importancia de la Descentralización en Web 3.0","url":"https://metrosetenta.es/blog/importancia-de-la-descentralizacion-web-3-0/"},{"content":"Web 3.0, la evolución más reciente de internet, se basa en varios principios fundamentales que buscan transformar la forma en que interactuamos con la web. Estos principios no solo redefinen la estructura técnica de internet, sino que también promueven un cambio en cómo se gestionan los datos, la privacidad y la seguridad en línea.\nPrincipios Fundamentales de Web 3.0 Descentralización: En Web 3.0, el poder y el control están distribuidos en lugar de centralizados. Esto significa que, en lugar de depender de grandes corporaciones o entidades únicas para gestionar y almacenar datos, estos se distribuyen a través de una red de nodos. Esto no solo mejora la resistencia a la censura, sino que también aumenta la seguridad, ya que no hay un único punto de falla.\nPropiedad del Usuario: Uno de los cambios más significativos en Web 3.0 es el retorno del control de los datos al usuario. A diferencia de Web 2.0, donde las empresas almacenan y gestionan nuestros datos, en Web 3.0, cada usuario posee y controla sus propios datos. Esto se logra mediante el uso de tecnologías de identidad descentralizada y almacenamiento en blockchain, lo que asegura que los datos del usuario estén seguros y solo sean accesibles con su consentimiento.\nInteroperabilidad: Web 3.0 promueve un entorno en el que diferentes aplicaciones y plataformas pueden interactuar sin problemas entre sí. Gracias a las tecnologías de blockchain y estándares abiertos, los datos y activos pueden moverse fácilmente entre diversas aplicaciones sin que los usuarios pierdan el control o la propiedad. Esto facilita una experiencia de usuario más unificada y eficiente.\nSeguridad y Privacidad Mejoradas: La seguridad es un pilar clave de Web 3.0. Con el uso de criptografía avanzada y almacenamiento distribuido, los datos de los usuarios están mejor protegidos contra hackers y violaciones de datos. Además, la privacidad se mejora significativamente, ya que los datos no son controlados por una sola entidad y los usuarios tienen la capacidad de decidir quién tiene acceso a su información.\nTransparencia y Confianza: En Web 3.0, todas las transacciones y actividades en la red son transparentes y verificables. La tecnología blockchain permite que todas las acciones sean registradas en un libro mayor inmutable, accesible para cualquier persona en la red. Esto no solo aumenta la confianza, sino que también reduce la necesidad de intermediarios, ya que todos pueden verificar directamente la autenticidad de las transacciones.\nConclusión Web 3.0 representa un cambio radical en cómo percibimos y utilizamos internet. Al centrarse en la descentralización, la propiedad del usuario, la interoperabilidad, la seguridad y la transparencia, Web 3.0 está configurando un futuro digital más equitativo y seguro. Comprender estos principios fundamentales es crucial para aprovechar al máximo las oportunidades que ofrece esta nueva era de internet.\n","id":6,"tag":"Web3 ; Blockchain ; Descentralización","title":"Principios Fundamentales de Web 3.0","url":"https://metrosetenta.es/blog/principios-fundamentales-web-3-0/"},{"content":"A medida que la tecnología evoluciona, también lo hace la forma en que interactuamos con internet. Web 2.0 y Web 3.0 representan dos etapas distintas en el desarrollo de la web, cada una con características y filosofías únicas que las diferencian.\n¿Qué es Web 2.0? Web 2.0, a menudo conocida como la \u0026ldquo;web social\u0026rdquo;, es la versión de internet que conocemos hoy en día. Esta etapa se caracteriza por la creación y el intercambio de contenido generado por los usuarios a través de plataformas centralizadas como redes sociales, blogs y sitios web de colaboración. Las empresas como Facebook, Google y Twitter dominan este espacio, proporcionando servicios gratuitos a cambio de los datos personales de los usuarios y mostrando anuncios personalizados.\nDiferencias Clave entre Web 2.0 y Web 3.0 Centralización vs. Descentralización:\nWeb 2.0: Los datos y servicios están centralizados en grandes plataformas que controlan la infraestructura y el acceso a la información. Web 3.0: Los datos y servicios se distribuyen a través de una red descentralizada, utilizando tecnología blockchain. Esto elimina la necesidad de intermediarios, permitiendo a los usuarios interactuar directamente entre sí. Propiedad de los Datos:\nWeb 2.0: Las plataformas centralizadas poseen y controlan los datos de los usuarios. Los datos se almacenan en servidores privados, lo que a menudo lleva a problemas de privacidad y seguridad. Web 3.0: Los usuarios tienen control total sobre sus datos, que están almacenados de forma segura en blockchain. La privacidad y la seguridad son mayores, ya que solo los propietarios de los datos pueden decidir quién tiene acceso a ellos. Modelo de Monetización:\nWeb 2.0: El modelo de negocio predominante es la publicidad. Las plataformas recopilan datos de los usuarios para crear perfiles detallados que se utilizan para mostrar anuncios dirigidos. Web 3.0: En lugar de depender de la publicidad, Web 3.0 se basa en modelos de negocio más justos, como pagos directos entre usuarios y desarrolladores o recompensas en tokens. Los usuarios pueden ser recompensados por su participación y contribución a la red. Interactividad y Automatización:\nWeb 2.0: La interactividad se limita principalmente a las acciones facilitadas por las plataformas centralizadas, como hacer \u0026ldquo;me gusta\u0026rdquo; o compartir contenido. Web 3.0: Utiliza contratos inteligentes que se ejecutan automáticamente cuando se cumplen ciertas condiciones, permitiendo una mayor automatización y nuevas formas de interacción, como las finanzas descentralizadas (DeFi) y los tokens no fungibles (NFTs). Interoperabilidad:\nWeb 2.0: Las aplicaciones y servicios suelen estar aislados entre sí, lo que dificulta la integración y el intercambio de datos entre plataformas diferentes. Web 3.0: Está diseñada para ser interoperable, facilitando la comunicación y el intercambio de información entre diferentes redes y aplicaciones, independientemente de la plataforma o blockchain subyacente. Conclusión Web 2.0 y Web 3.0 son representaciones de cómo la web ha evolucionado para satisfacer las necesidades cambiantes de los usuarios. Mientras que Web 2.0 se centró en la conectividad y la creación de contenido social, Web 3.0 está construyendo un entorno más descentralizado, seguro y equitativo. Al entender estas diferencias, podemos ver hacia dónde se dirige el futuro de internet y cómo los desarrolladores pueden aprovechar estas nuevas tecnologías para crear aplicaciones más innovadoras y justas.\n","id":7,"tag":"Web2 ; Web3 ; Internet","title":"Diferencias entre Web 2.0 y Web 3.0","url":"https://metrosetenta.es/blog/diferencias-web-2-0-y-web-3-0/"},{"content":"Web 3.0, también conocida como la tercera generación de internet, es una evolución de la web tradicional hacia un entorno más descentralizado, seguro y transparente. A diferencia de Web 2.0, que se centra en la creación de contenido y la interacción social a través de plataformas centralizadas, Web 3.0 utiliza tecnologías de blockchain y contratos inteligentes para crear aplicaciones y servicios que no dependen de una autoridad central.\nCaracterísticas Principales de Web 3.0 Descentralización: A diferencia de las aplicaciones tradicionales que almacenan datos en servidores centralizados, Web 3.0 utiliza una red distribuida de nodos para almacenar información, lo que reduce el control de las grandes corporaciones y mejora la seguridad y la privacidad de los usuarios.\nPropiedad de los Datos: En Web 3.0, los usuarios tienen mayor control sobre sus datos. A través de sistemas de identidad descentralizados, los individuos pueden gestionar quién tiene acceso a su información personal y cómo se utiliza.\nInteroperabilidad: Las aplicaciones y servicios en Web 3.0 están diseñados para ser interoperables entre diferentes plataformas y blockchains, facilitando la comunicación y el intercambio de valor entre distintas redes.\nContratos Inteligentes: Los contratos inteligentes son programas que se ejecutan automáticamente cuando se cumplen ciertas condiciones. Esto permite la automatización de acuerdos y transacciones sin necesidad de intermediarios, reduciendo costes y mejorando la eficiencia.\nTransparencia y Seguridad: Gracias al uso de la tecnología blockchain, todas las transacciones y operaciones en Web 3.0 son transparentes y pueden ser verificadas por cualquier usuario, lo que aumenta la confianza y la seguridad en el ecosistema digital.\n¿Por Qué Es Importante Web 3.0? Web 3.0 representa un cambio fundamental en cómo interactuamos con la tecnología y los servicios en línea. Al empoderar a los usuarios con mayor control sobre sus datos y permitir la creación de aplicaciones descentralizadas, Web 3.0 está construyendo un internet más justo y equitativo, donde la privacidad, la seguridad y la transparencia son primordiales.\n","id":8,"tag":"Web3 ; Descentralización ; Blockchain","title":"¿Qué es Web 3.0?","url":"https://metrosetenta.es/blog/que-es-web-3-0/"},{"content":"¿Te ha pasado en alguna ocasión que no quieres compartir modificaciones de código? Te cuento mi caso.\nEn el proyecto donde colaboro actualmente usamos el puerto 5000 para desplegar la aplicación, pero un software de Intel instalado en mi equipo usa por defecto dicho puerto y, claro, al desplegar el proyecto en mi máquina recibo el siguiente mensaje:\nUnhandled exception. System.IO.IOException: Failed to bind to address http://127.0.0.1:5000: address already in use. La solución más sencilla pasa por actualizar el puerto donde despliego la aplicación en mi máquina, y para esto debo hacer una modificación en un archivo nombrado como launchSettings.json pero, como el resto de colaboradores seguirá usando el puerto 5000 no quiero compartir dicha modificación del puerto de despliegue, únicamente la usaré yo en mi equipo local.\nConseguir esto pasa por estar atento a excluir dicho archivo de todas las subidas de código que realizo, lo cual es muy tedioso dado que soy propenso a usar el siguiente comando antes de hacer una confirmación en git cuando estoy satisfecho con mi código.\ngit add . Añadir una sentencia a mi configuración de git para ignorar el archivo launchSettings.json tampoco sería una solución ideal, pues debería generar una confirmación para que git deje de rastrearlo y, si algún colaborador quisiera en el futuro hacer alguna modificación en este archivo de configuración, no podría compartirla. Finalmente, la solución que mejor se adapta a esta circunstacia es pedirle a git que asuma que dicho archivo no tiene cambios.\nCon el siguiente comando podemos configurar archivos que están siendo rastreados, y no que queremos dejen de estarlo, para que git asuma que no han sido cambiados:\ngit update-index --assume-unchanged src/project.api/properties/launchSettings.json Puedes listar los archivos ignorados así:\ngit ls-files -v | grep \u0026#39;^h\u0026#39; Y, por último, para dejar de asumir que dicho archivo no tiene cambios, usa el siguiente comando:\ngit update-index --no-assume-unchanged src/project.api/properties/launchSettings.json ","id":9,"tag":"Git","title":"Código que no quieras compartir","url":"https://metrosetenta.es/blog/codigo-que-no-quieras-compartir/"},{"content":"En ocasiones podemos disponer de una buena documentación, una wiki del proyecto o cualquier plataforma de colaboración que nos permita consultar y compartir información técnica, configuraciones, procesos de gestión\u0026hellip; Pero seamos sinceros, documentar no es lo que más nos gusta a los ingenieros de desarrollo de software y estas opciones no siempre están disponibles para nosotros. Por otro lado, es posible que quieras disponer de algunas notas personales, scripts de automatización o incluso configuraciones personales para el proyecto donde estás colaborando.\nPara poder disponer de un lugar donde guardar este tipo de información tengo el hábito de crear en la carpeta principal del proyecto, siempre que esté versionado con git, una carpeta para mis notas personales del proyecto. Es cierto que podría disponer de esta información en cualquier otro lugar de mi equipo, pero ubicándola en el propio proyecto consigo mayor orden y facilidad de acceso a mis pequeños tesoros. Ahora bien ¿Cómo se me ocurre añadir al proyecto una carpeta de caracter personal y que incluso podría contener información sensible? Esto es lo mejor, gracias a git puedo usar dicha ubicación, ordenada y accesible, sin enturbiar el proyecto. Te explico a continuación como lo hago.\nEn mis carpetas personales de configuración, mis dotFiles, dispongo de un archivo de configuración de .gitignore_global que contiene la siguiente línea:\n# Ignore my personal project notes personal-project-notes/ Ahora se trata de configurar git, a nivel global, para que use dicho archivo de configuración. Si no usaste .gitignore_global para nombrar tu archivo no olvides modificarlo en el siguiente script.\ngit config --global core.excludesfile ~/documents/dotFiles/.gitignore_global ¡Y listo, ya puedes crear en la carpeta raiz tu propia carpeta personal-project-notes sin molestar al resto de colaboradores!\nSi en algún momento quieres consultar la ubicación del archivo que estas usando en la configuración global de git para ignorar carpetas o archivos puedes ejecutar el siguiente comando:\ngit config --get core.excludesfile ","id":10,"tag":"Git","title":"Notas personales del proyecto","url":"https://metrosetenta.es/blog/notas-personales-del-proyecto/"},{"content":"El doble gasto (double spending) es un concepto crítico en el entorno de blockchain y las criptomonedas. Se refiere al acto de gastar el mismo token digital, por ejemplo una criptomoneda, dos veces o más. En un sistema de pago tradicional como el dinero en efectivo, en la compra se transfiere directamente el bien utilizado como modo de pago, y al dejar de poseerlo es imposible volver a gastarlo. Por otro lado, en las transacciones bancarias centralizadas hay una entidad que registra y controla todos los movimientos, cuidando así de evitar el doble gasto, pero en las redes blockchain descentralizadas, y por tanto donde no existe dicha entidad, evitarlo es un desafío significante.\nPara dar solución al problema del doble gasto las redes blockchain utilizan una tecnología llamada mecanismo de consenso con el cual se pueden validar y registrar las transacciones. Los participantes de la red, los nodos verifican la autenticidad de las transacciones y garantizan que no se haya gastado la misma criptomoneda en más de una transacción. Uno de los algoritmos de consenso más comunes utilizados en criptomonedas como Bitcoin es la prueba de trabajo (proof of work), que requiere que los mineros resuelvan complejos rompecabezas matemáticos para agregar transacciones al registro público, lo que hace que duplicar un gasto sea extremadamente difícil y más costoso que el mismo gasto a duplicar.\n","id":11,"tag":"Blockchain","title":"El motivo de los mecanismos de consenso en Blockchain","url":"https://metrosetenta.es/blog/el-motivo-de-los-mecanismos-de-consenso-en-blockchain/"},{"content":"Blockchain es una tecnología descentralizada que permite almacenar y compartir información de forma segura.\nAtendiendo a su diseño no existe un único actor con la capacidad de acceder a la información y gestionarla, por tanto, se debe establecer un mecanismo de consenso entre todos los actores capaces para realizar dichas acciones. Esto es lo que le otorga a Blockchain su caracter descentralizado.\nCuando se alcanza una determinada cantidad de información a almacenar, esta se empaqueta en un bloque junto un hash del contenido del último bloque existente. Este modo de ordenar y almacenar datos es lo que le otorga el nombre de cadena de bloques. También confiere seguridad pues, al modificar el contenido de cualquier bloque, el hash que hace referencia a dicho contenido en el bloque posterior será incorrecto y, por tanto, se detectará una manipulación no deseada.\n","id":12,"tag":"Blockchain","title":"Breve descripción de Blockchain","url":"https://metrosetenta.es/blog/breve-descripci%C3%B3n-de-blockchain/"},{"content":"El compromiso del equipo de React, desde la aparición de los componentes funcionales, siempre ha sido hacer que estos fueran más eficientes que los componentes basados en clases. De hecho, si le preguntas a cualquier desarrollador que use React, seguro que afirma convencido que son mucho más rápido y eficientes, aunque la realidad es que, en el momento de escribir estas líneas, apenas existe una diferencia de segundos entre componentes funcionales y componentes basados en clases. Teniendo en cuenta que esto es inapreciable para el usuario final, no deberías temer por el rendimiento de tu aplicación si necesitas usar algún componente basado en clases, a pesar de que los componentes funcionales son técnicamente más rápidos y eficientes.\n","id":13,"tag":"React","title":"Rendimiento de los componentes funcionales en React","url":"https://metrosetenta.es/blog/rendimiento-de-los-componentes-funcionales-en-react/"},{"content":"Si has usado React para desarrollar aplicaciones web seguro que ya sabes que cuando un componente es modificado, ésta biblioteca de código de Javascript crea un DOM virtual para compararlo con el DOM actual y, de este modo, calcular si es necesario actualizarlo. A este proceso de actualizar el DOM actual cuando es necesario, para mantenerlo sincronizado con el DOM virtual, se le llama Reconciliación.\nSi usáramos un algoritmo de vanguardia para calcular el número mínimo de operaciones necesarias para transformar un árbol de nodos como el DOM en otro, la complejidad sería del orden de O(n³), donde n es el número de elementos en el árbol. Esto nos lleva a que mostrar 1000 elementos se complica hasta el orden de unos mil millones de operaciones, lo que afectaría drásticamente al rendimiento y, por este motivo, se usa un algoritmo heurístico, el algoritmo diferencial, que se basa en dos suposiciones:\nDos elementos de diferentes tipos producirán diferentes árboles. El desarrollador puede insinuar qué elementos secundarios pueden ser estables en diferentes renders con una propiedad key. ","id":14,"tag":"React","title":"Reconciliación y algoritmo diferencial en React","url":"https://metrosetenta.es/blog/reconciliacion_y_algoritmo_diferencial_en_react/"},{"content":"Creo que no es la primera vez que te cuento que, habitualmente, en las empresas del sector los equipos se plataforman con sistemas operativos Windows. En Windows las líneas de código finalizan con un retorno de carro y un salto de línea, CRLF, pero en Linux y Mac, dichos finales se representan únicamente con saltos de línea, LF. En la gestión de un proyecto donde los programadores usan distintos sistemas operativos, o simplemente deseas mantener un tipo de fin de línea distinto al del sistema operativo que estas usando en el desarrollo, puede ser muy frustrante gestionar los cambios entre versiones de código. Esto se debe a que Git interpretará cambios en cada línea del código, pues donde había simplemente LF, tu editor colocó CRLF, y no podrás discernir los cambios reales. Git, sin embargo, dispone de una configuración para gestionar estos casos relativos a los finales de línea, core.autocrlf.\nPara ver la configuración actual en este parámetro debes usar el siguiente comando de Git:\ngit config --get core.autocrlf Puedes ajustar esta configuración con los valores true, input o false. A continuación te muestro como ajustarla al valor input.\ngit config core.autocrlf input Déjame que te indique a continuación como se comportan los comandos git checkout y git add con cada uno de los tres valores que puedes usar en esta configuración:\nSi lo configuras a true\ngit checkout convierte LF a CRLF git add convierte CRLF a LF Si lo configuras a input\ngit checkout no realiza ninguna conversión git add convierte CRLF a LF Si lo configuras a false\ngit checkout no realiza ninguna conversión git add no realiza ninguna conversión Como habrás deducido, este último valor, false, es el ajuste correcto para proyectos que únicamente se gestionarán en sistemas Windows.\n","id":15,"tag":"Git","title":"Gestión de final de línea en Git","url":"https://metrosetenta.es/blog/gestion_de_final_de_linea_en_git/"},{"content":"Para empezar, y como curiosidad, te cuento que en la abreviatura i18n el número 18 hace referencia a las letras que se encuentran entre la primera y última letra de la palabra internacionalitation.\nLa internacionalización de un proyecto de software es algo en cuya implementación no se suele prestar toda la atención requerida. Habitualmente sólo se gestiona el aspecto más básicos que permita mostrar los textos en distintos idiomas, y hay otros aspectos, como la gestión de la pluralización, que quedan olvidados.\nEn esta entrada, y alguna más que le seguirá, usaré Vue I18n para añadir la gestión de la internacionalización a un proyecto Vue. Como primer paso, por tanto, deberías acceder al directorio donde se encuentra tu proyecto Vue y añadir Vue I18n.\ncd proyecto-vue vue add i18n Tendrás que atender unas consultas en la consola; La primera de estas consultas es la sobre configuración regional que usará por defecto el proyecto. Luego debes indicar la configuración regional alternativa, el directorio donde se guardarán los archivos con las traducciones y si deseas activar cierta compatibilidad.\n? The locale of project localization. es ? The fallback locale of project localization. en ? The directory where store localization messages of project. It\u0026#39;s stored under `src` directory. locales ? Enable legacy API (compatible vue-i18n@v8.x) mode ? No Después vas a poder comprobar que hay varios cambios en el proyecto, por ejemplo, en el archivo main.js deberías ver algo parecido a esto:\nimport i18n from \u0026#39;./i18n\u0026#39; const app = createApp(App).use(i18n) Y el archivo vue.config.js debería contener algo parecido a esto:\nconst { defineConfig } = require(\u0026#39;@vue/cli-service\u0026#39;) module.exports = defineConfig({ pluginOptions: { i18n: { locale: \u0026#39;es\u0026#39;, fallbackLocale: \u0026#39;en\u0026#39;, localeDir: \u0026#39;locales\u0026#39;, enableLegacy: false, runtimeOnly: false, compositionOnly: false, fullInstall: true } } }) Comprueba también que ya dispones de una carpeta llamada locales en la carpeta src de tu proyecto. Aquí es donde guardaremos los archivos con las traducciones que utilizará nuestra aplicación.\n","id":16,"tag":"Vue","title":"Internacionalización de un proyecto Vue","url":"https://metrosetenta.es/blog/internacionalizacion-de-un-proyecto-vue/"},{"content":"En ocasiones te puede tocar trabajar en un proyecto cuyo repositorio cuenta ya con varios años de historia. Clonar este tipo de proyectos puede terminar en un error debido a la cantidad de datos a ser transferidos y, por tanto, es preferible hacer un clonado superficial. Un clonado superficial de un repositorio Git consiste en clonar únicamente parte de la historia del repositorio, y lo puedes hacer con una instrucción similar a la que sigue:\ngit clone urlProyectoAClonar --depth 1 Con este comando clonarías el último commit del repositorio en la url indicada. Esto supone un gran ahorro de espacio y el proyecto será más ligero de gestionar en local, pero es posible que no puedas resolver alguna mezcla que relacione a un commit anterior, ya que no está en tu local. Debido a esto último, es una buena idea clonar, al menos, los 50 o 100 últimos commits.\ngit clone urlProyectoAClonar --depth 50 Otra opción sería extraer los commits deseados:\ngit fetch --depth 50 Por último, tienes que saber que siempre dispones de la opción de deshacer el clonado superficial del repositorio.\ngit fetch --unshallow ","id":17,"tag":"Git","title":"Clonado Superficial de repositorio Git","url":"https://metrosetenta.es/blog/clonado-superficial-de-repositorio-git/"},{"content":"En muchas empresas es habitual plataformar únicamente el sistema operativo Windows en los equipos facilitados a los empleados, de modo que, si quieres disponer de las bondades de Linux para desarrollar tu trabajo, la opción más factible es usar el susbsitema Linux que Windows incluye, WSL. Desde su segunda versión WSL se ejecuta en una máquina virtual que intenta ser lo más liviana posible, pero que usa un archivo vhdx que crece con el uso de dicho subsistema y, aunque liberes espacio en el subsistema Linux, la realidad es que no vas a recuperar espacio de tu disco duro si no manipulas directamente el archivo vhdx. Lo primero que necesitas es saber dónde se encuentra dicho archivo. En el caso de que estés usando una distribución Ubuntu, la dirección será similar a esto:\nC:\\Users\\metroSetenta\\AppData\\Local\\Packages\\CanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgsc\\LocalState\\ext4.vhdx A continuación abre la aplicación Command Prompt o Powershell asegurándote de hacerlo con privilegios de administrador. Lo más sencillo sería ejecutar el siguiente comando desde el directorio donde se encuentre el archivo ext4.vhdx:\noptimize-vhd -Path .\\ext4.vhdx -Mode full Pero podrias encontrarte con un mensaje como el que sigue:\nOptimize-Vhd : The term \u0026#39;Optimize-Vhd\u0026#39; is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. No hay problema, en ese caso, ejecuta la siguiente secuencia de comandos sin olvidar usar la dirección donde se encuentra tu archivo ext4.vhdx:\nwsl --shutdown diskpart # open window Diskpart select vdisk file=\u0026#34;C:\\Users\\metroSetenta\\AppData\\Local\\Packages\\CanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgsc\\LocalState\\ext4.vhdx\u0026#34; attach vdisk readonly compact vdisk detach vdisk exit ","id":18,"tag":"WSL","title":"Liberar espacio de WSL","url":"https://metrosetenta.es/blog/liberar-espacio-de-wsl/"},{"content":"En informática, este término hace referencia a un contenedor abstracto de identificadores únicos. Los lenguajes que gestionan espacios de nombres especifican las reglas que determinan a que espacio de nombre pertenece un identificador, de modo que pueden manejar grandes cantidades de estos sin que haya colisión entre ellos, es decir, asegurándose de que son identificadores únicos, a pesar de que algunos de ellos usen la misma designación.\nTe explico mejor con un ejemplo: Dos personas, Rebeca y Andrés, que pertenecen a empresas distintas, pueden tener un mismo número de empleado, digamos el 456. En este caso la empresa representaría el espacio de nombre, y 456, el número de empleado, representaría el identificador único. Aunque se trata de la misma designación para ambos empleados, 456, no existe colisión porque Rebeca es el empleado 456 de la empresa A, y Andrés es también el 456, pero en la empresa B.\n","id":19,"tag":"Conceptos básicos","title":"Espacio de nombres","url":"https://metrosetenta.es/blog/espacio-de-nombres/"},{"content":"En el ámbito de los sistemas de información, el dominio del problema es el conjunto de conceptos, interrelacionados entre sí, que se necesita conocer para comprender el negocio del cliente. Es decir, son todos aquellos conocimientos que están implicados en la correcta comprensión de la necesidad del cliente y, por tanto, son necesarios para proponer una correcta solución. Un buen ejemplo podría ser el dominio del problema al desarrollar un aplicación para una clínica médica privada, donde habría de manejar correctamente conceptos como póliza, paciente, cita, diagnóstico\u0026hellip;\n","id":20,"tag":"Fundamentos arquitectura","title":"Dominio del problema","url":"https://metrosetenta.es/blog/dominio-del-problema/"},{"content":"Es habitual, cuando se aprende un lenguaje de programación, escribir una pequeña aplicación mostrando el mensaje \u0026ldquo;¡Hola mundo!\u0026rdquo;. En el caso de Deno, vamos a hacer algo un poco diferente para ejecutar tu primer programa con esta tecnología. Ya te conté aquí que Deno ofrece un servicio de repositorios a través de https://deno.land/x/, y vamos a usar un programa ejemplo que tienen publicado con el nombre de welcome. ¡Para que Deno lo descarge, lo compile y lo ejecute, sólo necesitamos escribir una línea!:\n$ deno run https://deno.land/std@0.87.0/examples/welcome.ts Download https://deno.land/std@0.87.0/examples/welcome.ts Compile https://deno.land/std@0.87.0/examples/welcome.ts Welcome to Deno! Por supuesto que ejecutar código de manera arbitraria desde cualquier URL de internet no es una práctica recomendable, pero no olvides que con Deno disponemos de un entorno aislado del resto del sistema operativo donde es posible ajustar distintos tipos de permisos para los ejecutables, es decir, Deno dispone de un sandbox integrado.\nEl programa que hemos ejecutado es realmente sencillo, tan solo una llamada a console.log().\nconsole.log(\u0026#39;Welcome to Deno 🦕\u0026#39;) Si abres en el navegador la URL que hemos utilizado no verás el código fuente, porque la web de Deno reconoce tu navegador y sirve dicho código de un modo más amable para nosotros. Puedes descargarlo con, por ejemplo wget, que solita la versión text/plain en lugar de la versión text/html.\n$ wget https://deno.land/std@0.87.0/examples/welcome.ts --2021-02-13 23:36:09-- https://deno.land/std@0.87.0/examples/welcome.ts Loaded CA certificate \u0026#39;/etc/ssl/certs/ca-certificates.crt\u0026#39; Resolving deno.land (deno.land)... 104.21.18.123, 172.67.181.211, 2606:4700:3031::ac43:b5d3, ... Connecting to deno.land (deno.land)|104.21.18.123|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 33 [application/typescript] Saving to: ‘welcome.ts’ welcome.ts 100%[===============================\u0026gt;] 33 --.-KB/s in 0s 2021-02-13 23:36:10 (34.3 MB/s) - ‘welcome.ts’ saved [33/33] Si volvieras a ejecutar el programa, como es algo que ya hiciste anteriormente, y Deno cacheó dicho programa, verás que en esta ocasión no lo descargará.\n$ deno run https://deno.land/std@0.87.0/examples/welcome.ts Welcome to Deno! En todo caso, si quieres que lo vuelva a descargar para asegurarte de que ejecuta la última versión publicada, podrías usar la opción \u0026ndash;reload o -r.\n$ deno run --reload https://deno.land/std@0.87.0/examples/welcome.ts Download https://deno.land/std@0.87.0/examples/welcome.ts Compile https://deno.land/std@0.87.0/examples/welcome.ts Welcome to Deno! Deno run tiene, además de esta, muchísimas opciones más. Para conocerlas ejecutar el comando deno run \u0026ndash;help.\n$ deno run --help deno-run Run a program given a filename or url to the module. By default all programs are run in sandbox without access to disk, network or ability to spawn subprocesses. deno run https://deno.land/std/examples/welcome.ts Grant all permissions: deno run -A https://deno.land/std/http/file_server.ts Grant permission to read from disk and listen to network: deno run --allow-read --allow-net https://deno.land/std/http/file_server.ts Grant permission to read whitelisted files from disk: deno run --allow-read=/etc https://deno.land/std/http/file_server.ts USAGE: deno run [OPTIONS] \u0026lt;SCRIPT_ARG\u0026gt;... OPTIONS: -A, --allow-all Allow all permissions --allow-env Allow environment access --allow-hrtime Allow high resolution time measurement --allow-net=\u0026lt;allow-net\u0026gt; Allow network access --allow-plugin Allow loading plugins --allow-read=\u0026lt;allow-read\u0026gt; Allow file system read access --allow-run Allow running subprocesses --allow-write=\u0026lt;allow-write\u0026gt; Allow file system write access --cached-only Require that remote dependencies are already cached --cert \u0026lt;FILE\u0026gt; Load certificate authority from PEM encoded file -c, --config \u0026lt;FILE\u0026gt; Load tsconfig.json configuration file -h, --help Prints help information --importmap \u0026lt;FILE\u0026gt; UNSTABLE: Load import map file Docs: https://deno.land/std/manual.md#import-maps Specification: https://wicg.github.io/import-maps/ Examples: https://github.com/WICG/import-maps#the-import-map --inspect=\u0026lt;HOST:PORT\u0026gt; activate inspector on host:port (default: 127.0.0.1:9229) --inspect-brk=\u0026lt;HOST:PORT\u0026gt; activate inspector on host:port and break at start of user script --lock \u0026lt;FILE\u0026gt; Check the specified lock file --lock-write Write lock file. Use with --lock. -L, --log-level \u0026lt;log-level\u0026gt; Set log level [possible values: debug, info] --no-remote Do not resolve remote modules -q, --quiet Suppress diagnostic output By default, subcommands print human-readable diagnostic messages to stderr. If the flag is set, restrict these messages to errors. -r, --reload=\u0026lt;CACHE_BLACKLIST\u0026gt; Reload source code cache (recompile TypeScript) --reload Reload everything --reload=https://deno.land/std Reload only standard modules --reload=https://deno.land/std/fs/utils.ts,https://deno.land/std/fmt/colors.ts Reloads specific modules --seed \u0026lt;NUMBER\u0026gt; Seed Math.random() --unstable Enable unstable APIs --v8-flags=\u0026lt;v8-flags\u0026gt; Set V8 command line options. For help: --v8-flags=--help ARGS: \u0026lt;SCRIPT_ARG\u0026gt;... script args ","id":21,"tag":"Javascript","title":"Hola mundo al estilo Deno","url":"https://metrosetenta.es/blog/hola-mundo-al-estilo-deno/"},{"content":"Hay varios motivos por los cuales podrías querer traer la información de un repositorio de código, versionado con Subversion, a tu repositorio de código versionado con Git, desde sincronizar ambos repositorios durante un periodo de transición de gestor de versiones hasta, simplemente, aprovechar las características de git para la gestión de ramas antes de subir nuevo código al repositorio de Subversion. Estos motivos son los que justifican la existencia de git-svn, una característica de Git que nos proporciona comandos para gestionar un flujo bidireccional entre Git y Subversion.\nLo más común es tirar de todo el árbol de Subversion con el siguiente comando:\n$ git svn clone https://miRepositorio.com/repositorios/projecto -T trunk -b branches -t tags Pero lo que te quiero mostrar es como puedes hacer cuando no quieres traer toda la información, sino que quieres traer y trabajar únicamente con una rama del repositorio Subversion. Para ello, debes saber que Git almacena una lista de los repositorios remotos en el archivo .git/config, incluyendo aquellos que has configurado con el comando que te acabo de mostrar arriba, y puedes verlos, una vez que has usado el comando fetch, usando este otro comando que muestras todas tus ramas, tanto locales como remotas.\n$ git branch -a Sabiendo esto, puedes deducir que añadiendo la configuración que nos interesa en dicho archivo, podremos gestionar, desde git, la rama que nos interesa del repositorio Subversion sin tener que hacerle seguimiento a todas. Abajo te muestro un ejemplo para configurar la rama entregas, pero ten en cuenta que la URL que tú necesites dependerá de la estructura de tu repositorio Subversion.\n[svn-remote \u0026#34;entregas\u0026#34;] url = https://miRepositorioSubversion.com/repositorios/projecto/ramas/entregas fetch = :refs/remotes/subversion/entregas Con esto añades a Git una configuración para gestionar una rama de un repositorio remoto Subversion, con un referencia, entregas, sobre la que poder usar el comando git svn fetch.\n$ git svn fetch entregas Si vuelves a comprobar la lista de ramas con git branch -a deberías ver algo similar esto:\n$ git branch -a master netlify * writting remotes/gitlab/master remotes/gitlab/netlify remotes/gitlab/writting remote/subversion/entregas ¡Observa que nuestra nueva rama remota está en la última línea de la salida del comando!\n","id":22,"tag":"Git","title":"Configurar en Git un repositorio remoto Subversion","url":"https://metrosetenta.es/blog/configurar-en-git-un-repositorio-remoto-subversion/"},{"content":"Son muchísimos los proyectos que, en el momento de escribir este artículo, utilizan Maven para gestionar su gestión de dependencias su construcción. Maven permite, además, la encriptación y gestión de contraseñas, lo cual es muy útil para poder acceder a repositorios privados, como los gestionados con Nexus, que pueden requerir autorización. Para esto, únicamente necesitas crear un par de archivos en la carpeta ${user.home}/.m2, y cuyos nombres serán settings-security.xml y settings.xml.\nVamos a comenzar con settings-security.xml, que es el que va a contener una contraseña maestra de nuestra elección. Podemos crearla con el comando mvn de Maven.\nmvn --encrypt-master-password \u0026lt;password\u0026gt; Omite el parámetro password si estás usando una versión de Maven superior a la 3.2.1. Una vez ejecutado el comando obtendrás una versión encriptada de tu contraseña maestra. Debería tener un aspecto parecido a este:\n{jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+9EF1iFQyJQ$} Es el momento de almacenar esta contraseña en ${user.home}/.m2/settings-security.xml.\n\u0026lt;settingsSecurity\u0026gt; \u0026lt;master\u0026gt;{jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+9EF1iFQyJQ$}\u0026lt;/master\u0026gt; \u0026lt;/settingsSecurity\u0026gt; Y una vez que tenemos esto configurado, ya podemos guardar las credenciales que usaremos para identificarnos en el servidor privado de artefactos. Para hacer esto, usaremos el comando que se muestra a continuación, y en donde el parámetro password tiene la misma peculiaridad que en comando anterior.\nmvn --encrypt-password \u0026lt;password\u0026gt; De igual manera que antes recibiremos una versión encriptada de nuestras credenciales.\n{COQLCE6DU6GtcS5P$} En esta ocasión, la vamos a usar dentro del archivo ${user.home}/.m2/settings.xml.\n\u0026lt;settings\u0026gt; \u0026lt;servers\u0026gt; \u0026lt;server\u0026gt; \u0026lt;id\u0026gt;mi_servidor\u0026lt;/id\u0026gt; \u0026lt;username\u0026gt;mi_usuario\u0026lt;/username\u0026gt; \u0026lt;password\u0026gt;{COQLCE6DU6GtcS5P$}\u0026lt;/password\u0026gt; \u0026lt;/server\u0026gt; \u0026lt;/servers\u0026gt; \u0026lt;/settings\u0026gt; ","id":23,"tag":"Maven","title":"Configurar credenciales de repositorios privados en Maven","url":"https://metrosetenta.es/blog/configurar-credenciales-de-repositorios-privados-en-maven/"},{"content":"Ya sabes que Ionic se integra perfectamente con los tres principales frameworks de front en el momento de escribir este artículo, Angular, React y, recientemente, con Vue.js. Centrándonos en Ionic React, habría que destacar varios aspectos. En definitiva se trata de React, y esto significa que usa los estándares abiertos de la web y las capacidades integradas en los navegadores, por tanto es compatible com millones de bibliotecas de código web. Ionic React cotinene más de una centena de componentes de interfaz de usuario optimizados para ser utilizados con React, usa la pila estandar de herremientas de React, como react-dom o react-router, y puedes preparar tu aplicación para ser utilizada en iOS, Android, Electron y PWA.\nCon únicamente tres comandos puedes instalar Ionic, crear un proyecto React y servirlo en tu máquina local:\n$ npm install -g @ionic/cli $ ionic start myApp tabs --type react $ ionic serve ¡Toda la documentación necesaria para continuar la tienes aquí!\n","id":24,"tag":"Ionic ; JavaScript ; React","title":"Ionic React","url":"https://metrosetenta.es/blog/ionic-react/"},{"content":"Ionic se define a sí mismo como un entorno de trabajo con el que puedes crear aplicaciones móviles y aplicaciones web progresivas de alto rendimiento. Su filosofía está muy basada en la web, pues entiende que es el entorno de ejecución más probado y estable que existe, de modo que cualquier desarrollador que tenga conocimientos de HTML, JavaScript y CSS pude desarrollar aplicaciones para distintas plataformas y dispositivos. Es más, Ionic puede ser usado con los entornos de trabajo de Javascript más utilizados, Angular, React y, recientemente, con Vue.js. La posibilidad de usar las capacidades nativas de un dispositivo, como podría ser la cámara del teléfono inteligente, se añaden gracias al uso de Apache Cordova o Capacitor.\nSu competidor más directo, posiblemente, sea Flutter, aunque este segundo tiene una filosofía muy distinta, pues las aplicaciones de Flutter se escriben con Dart, que posteriormente puede ser compilado a Javascript.\n","id":25,"tag":"Ionic ; JavaScript","title":"Qué es Ionic","url":"https://metrosetenta.es/blog/que-es-ionic/"},{"content":"El operador Elvis es una abreviatura del operador ternario. Un caso en el que suele utilizarse de manera habitual es para devolver un valor que es sensible por defecto cuando una expresión se resuelve como false. Un sencillo ejemplo:\n// Con el operador ternario, tienes que repetir el valor a asignar mostrarNombre = usuario.nombre? usuario.nombre: \u0026#39;Anónimo\u0026#39; //Con el operador de Elvis, el valor que se prueba y se usa si no es falso mostrarNombre = usuario.nombre?: \u0026#39;Anónimo\u0026#39; El uso del operador Elvis reduce la verbosidad de tu código y los riesgos de errores, en caso de refactorizaciones, al eliminar la necesidad de duplicar la expresión que se prueba, tanto en la condición, como en el valor de retorno positivo.\n","id":26,"tag":"Groovy","title":"El operador Elvis de Groovy","url":"https://metrosetenta.es/blog/el-operador-elvis-de-groovy/"},{"content":"Una imagen Docker es una plantilla o esquema a partir del cual podemos generar un contenedor Docker, es decir, podemos generar un entorno aislado que está diseñado para ejecutar una o más apliaciones de forma óptima. La imágenes se crean a partir de un archivo, al que se denomina Dockerfile, usando el comando docker build. Una vez que has generado tu imagen puedes almacenarla en repositorio de imágenes Docker. En Docker Hub, por ejemplo, puedes almacenar tus imágenes de manera privada o pública. Si visitas Docker Hub verás que puedes usar muchísimas imágenes de forma gratuita sin tener que crear tus propias imágenes. Muchas de estas imágenes son oficiales, desarrolladas y distribuidas por equipos desarrolladores de una tecnología específica. Desde bases de datos a herramientas DevOps, pasando por servicios de mensajería e, incluso, sistemas operativos, tienen una imagen preparada para ser descargada y usada en Docker Hub. Puedes disponer rápidamente de una instancia de Jenkins descargando su imagen oficial\u0026hellip;\n$ docker pull jenkins \u0026hellip;y luego creando el contenedor con el comando docker run, que se encargará de, usando la imagen Docker para Jenkins recién descargada, crear el sistema de archivos, iniciar las dependencias necesarias y todas las demas gestiones necesarias para ejecutar jenkins en un contenedor Docker.\n","id":27,"tag":"Docker","title":"Qué es una imagen Docker","url":"https://metrosetenta.es/blog/que-es-una-imagen-docker/"},{"content":"¿Te imaginas una clase de Groovy a la que le puedes añadir, en tiempo de ejecución, propiedades y métodos? Pues eso es lo que te ofrece su clase Expando, cuyo uso es muy similar al modo en el que, en JavaScript, se usan objetos instanciando la variable Object.\n// Define la classe Expando con dos propiedades: def blog = new Expando(titulo : \u0026#34;metroSetenta\u0026#34;, subtitulo : \u0026#34;Arquitectura y diseño de software\u0026#34;) // Añade una nueva propiedad a Expando: blog.url=\u0026#34;metrosetenta.es\u0026#34; // Incluye un método con un cierre: blog.toString={ return \u0026#34;\u0026#34;\u0026#34; Título del blog: ${titulo} Subtítulo del blog: ${subtitulo} URL del blog: ${url} \u0026#34;\u0026#34;\u0026#34; } println (blog) Observa en el pequeño ejemplo de arriba que el constructor usa una notación similar a los mapas Groovy y, que los métodos, son implementados usando cierres (closures). Puedes probar este pequeño ejemplo guardándolo en un archivo para ejecutarlo con el comando groovy.\n$ groovy expandoText.groovy Título del blog: metroSetenta Subtítulo del blog: Arquitectura y diseño de software URL del blog: metrosetenta.es Este pequeño artículo se lo quiero dedicar con cariño a mi compañero Fran, que fue quien me mostró la clase Expando de Groovy.\n","id":28,"tag":"Groovy","title":"La clase Expando de Groovy","url":"https://metrosetenta.es/blog/la-clase-expando-de-groovy/"},{"content":"Los patrones de diseño creacionales son aquellos que nos proponen soluciones para problemas relacionados con la instanciación de objetos. Automatizar el proceso de construcción de un objeto complejo, limitar la instaciación de una clase a un único objeto al que se pueda acceder de manera global o usar un objeto como prototipo para crear otros objetos similares son algunos de los usos de los patrones de diseño creacionales.\nFactory Method (Método de fabricación): Si necesitamos un objeto de un tipo, pero desconocemos cual es el objeto concreto que vamos a necesitar en el momento del diseño, este es nuestro patrón. Donde dije tipo puedes poner, por ejemplo, conexión a base de datos, y puedes sustituir objeto concreto por conexión a Oracle Database, conexión a MySQL, conexión a PostgreSQL\u0026hellip;\nAbstract Factory (Fábrica abstracta): Si agrupamos los objetos que tienen una cualidad común obtenemos una familia de objetos. Pues bien, este patrón nos ayuda cuando necesitamos instaciar toda una familia de objetos pero no sabemos cual es la familia concreta en el momento del diseño. Un buen ejemplo de familia de objetos son los elementos de una interfaz gráfica (ventana, menú, botón\u0026hellip;), y podemos diseñar una familia concreta para cada sistema operativo que queramos soportar.\nSingleton (Instancia única): Sirve para limitar una clase a una única instanca a la que es posbible acceder de forma global. Piensa en la configuración de una aplicación, que es necesaria utilizar desde varias clases, y ya no hay que instanciar cada vez que se consulte. Se crea una única instancia de la configuración y a compartir.\nBuilder (Constructor virtual): Abstrae el proceso de creación de un objeto complejo. Cuando tienes que crear muchas veces un tipo de objeto, cuando dicho tipo de objeto tiene muchisimos atributos que ajustar o cuando gestionar sus muchos métodos constructores es difícil, este patrón aplica perfectamente.\nPrototype (Prototipo): Se trata de crea nuevos objetos clonándolos de una instancia ya existente. El patrón perfecto para crear objetos con sutiles diferencias con otro ya creado, como copiar y pegar un círculo en un programa de dibujo.\nObject Pool (Grupo de objetos): Se trata de crear un almacén de objetos reutilizables, de un determinado tipo. Puede contar con varias opciones de gestión, como limitar el número de objetos disponibles, la cantidad de usos, la operativa a seguir al solicitar un objeto del almacén si todos están siendo utilizados\u0026hellip; Este patrón no se encuentra entre los patrones del GoF.\nModel View Controller o MVC (Modelo Vista Controlador). Este patrón es de arquitectura, no de diseño, y plantea una estructura de tres capas. La primera, la capa modelo, es la que representa los objetos que gestiona la aplicación. El usuario usa la segunda capa, la vista, para visualizar dichos objetos y para hacer peticiones respecto a ellos, interactuando con la aplicación. La tercera y última capa, la capa controlador, recibe y realiza lo que el usuario quiere hacer, y es el encargado de comunicar las dos capas anteriores, ejecutando en el modelo las peticiones que le llegan desde la vista y, posteriormente, informando al usuario, mediante la capa vista, del resultado de sus peticiones.\n","id":29,"tag":"Patrones creacionales ; Patrones de diseño ; Patrones de arquitectura","title":"Patrones creacionales","url":"https://metrosetenta.es/blog/patrones-creacionales/"},{"content":"En ocasiones necesitas conocer la evolución de una petición o tarea en Redmine, en la que no estás involucrado, mediante notificaciones por correo electrónico. Es posible hacerlo porque Redmine te facilita la posibilidad de monitorizar peticiones o tareas. Para ello, dirígete a la petición a la que deseas hacer seguimiento y, en la parte inferior, al final del cuerpo de la petición, pulsa en el enlace Monitorizar que se encuentra junto al icono de la estrella.\nEs importante que en tu cuenta, en la configuración de notificaciones, selecciones objetos de los cuales eres seguidor.\n","id":30,"tag":"Redmine","title":"Monitorizar peticiones en Redmine","url":"https://metrosetenta.es/blog/monitorizar-peticiones-en-redmine/"},{"content":"Hoy voy a ampliar los artículos sobre Deno que hay en el blog comentandote los subcomandos disponibles en esta herramienta. Si ya has instalado y configurado Deno, y dispones del comando deno en tu consola, el primer subcomando que debes probar es help.\n$ deno help Entre otras cosas, te va a facilitar un listado de subcomandos similar al que sigue:\nbundle Bundle module and dependencies into single file cache Cachea las dependencias completions Genera autocompletados de la consola de comandos doc Muestra la documentación para un módulo eval Evalúa un script fmt Formatea archivos fuente help Imprime la ayuda general o la de un subcommando dado info Muestra información sobre el caché o información relacionada con un archivo fuente install Instalar script como un ejecutable lint Aplicar resaltado de código a archivos fuente repl Bucle leer, evaluar e imprimir run Ejecuta un programa desde un nombre de archivo o una URL. Usa \u0026#39;-\u0026#39; como nombre de archivos para leer de la entrada estandar test Ejecuta las pruebas types Imprime las declaraciones de TypeScripts en tiempo de ejecución upgrade Actualiza el ejecutable deno a una versión dada Algo más sobre el subcomando help es que si lo usas con cualquiera de los subcomandos listados más arriba, te facilitará información más detallada sobre dicho subcomando y su sobre uso. Por ejemplo, si queremos saber algo más sobre el subcomando eval, podemos ejecutar el siguiente comando:\n$ deno help eval Y Deno nos facilitará una información más detallada sobre el subcomando eval.\ndeno-eval Evalua JavaScript desde la línea de comandos. deno eval \u0026#34;console.log(\u0026#39;¡Hola mundo!\u0026#39;)\u0026#34; Para evaluar como TypeScript: deno eval -T \u0026#34;const v: string = \u0026#39;hello\u0026#39;; console.log(v)\u0026#34; Este comando tiene acceso implícito a todos los permisos (--allow-all). USO: deno eval [OPCIONES] \u0026lt;código\u0026gt; OPCIONES: --cert \u0026lt;ARCHIVO\u0026gt; Cargar autoridades certificadoras desde un archivo PEM codificado -h, --help Imprimir información de ayuda --inspect=\u0026lt;HOST:PORT\u0026gt; Activar inspector en host:port (por defecto: 127.0.0.1:9229) --inspect-brk=\u0026lt;HOST:PORT\u0026gt; Activar inspector en host:port host:port con break al comienzo del script del usuario -L, --log-level \u0026lt;nivel log\u0026gt; Ajustar el nivel de log [Valores posibles: debug, info] -p, --print Imprimir resultados a la salida estandar -q, --quiet Suprimir salida de diagnóstico -T, --ts Tratar la entrada dada a eval como Typescript --unstable Habilitar APIs inestables --v8-flags=\u0026lt;opciones V8\u0026gt; Ajustar las opciones V8 de la línea de comandos. Para más ayuda: --v8-flags=--help ARGUMENTOS: \u0026lt;código\u0026gt; ","id":31,"tag":"JavaScript ; Deno","title":"Subcomandos de Deno","url":"https://metrosetenta.es/blog/subcomandos-de-deno/"},{"content":"Docker es, posiblemente, la herramienta que revolucionó el modo en el que desplegamos y distribuimos aplicaciones. Asegurarnos de que el entorno en el que se van a ejecutar nuestras aplicaciones es óptimo para ellas ha sido siempre un esfuerzo asociado al desarrollo de software. El uso de máquinas virtuales supuso el acercamiento más satisfactorio antes de Docker, pero el rendimiento se veía comprometido por el esfuerzo que suponía, para el sistema operativo huesped, levantar y gestionar un sistema operativo completo en el que ajustar el entorno deseado y ejecutar nuestra aplicación. Con Docker, ejecutamos nuestras aplicaciones en entornos aislados, contenedores, que si bien no son máquinas virtuales, se asemejan muchísimo, pero con la ventaja de aprovechar nuestro sistema operativo todo lo posible en lugar de tener que gestionar un completo sistema operativo inquilino.\nLa idea principal detrás de Docker consiste en diseñar un esquema de un entorno ideal para nuestra aplicación y el modo en el que ésta se ejecuta en él usando los recursos mínimos necesarios. A este esquema lo llamamos imagen, y cualquier desarrollador que disponga de nuestra imagen puede usar Docker para instanciarla, como un contenedor, del modo que hemos mencionado en el párrafo anterior. Esto significa que podemos distribuir una imagen de nuestra aplicación con la certeza de que funcionará en cualquier máquina que disponga de Docker.\nLos beneficios son numerosos, desde poder ejecutar varias versiones de la misma aplicación en nuestro sistema operativo a evitar tener que dar soporte a todos los servidores, o configuraciones posibles, que los usuarios de nuestras aplicaciones puedan utilizar. Simplemente hay que poner una imagen de Docker a la disposición de los usuarios de nuestras apliaciones, en un repositorio propio o en un repositorio de imágenes de Docker. Esto abre, además, nuevas posibilidades de distribución.\nDocker es el asesino de la frase \u0026ldquo;Pues en mi máquina no funciona\u0026hellip;\u0026rdquo;\n","id":32,"tag":"Docker","title":"¿Qué es Docker?","url":"https://metrosetenta.es/blog/que-es-docker/"},{"content":"Los patrones de diseño son un concepto que empezó a manejar el arquitecto britano-americano Christopher Alexander en 1966. Mucho más tarde, en 1994, con la publicación de Design Patterns: Elements of Reusable Object-Oriented Software, dicho concepto comenzó a ganar popularidad en el mundo del desarrollo de software. Este libro fué escrito por cuatro autores que posteriormente serían conocidos como la pandilla de los cuatro (Gang of Four): Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides. Los patrones de diseño aportan soluciones generales y reutilizables para problemas comunes. No se trata de porciones de código, sino de algo más genérico: La descripción de un problema y de una solución, que ha sido probada, a ese problema. Comprender un patrón, identificar cuando es útil, aplicarlo y adaptarlo a un caso concreto es tarea de aquel que lo estudia. El uso adecuado de estos patrones, por tanto, puede acelerar el proceso de diseño y desarrollo de software, pues al aportar paradigmas que han sido probados como eficaces evitan invertir tiempo en buscar una solución partiendo desde cero.\nOriginalmente, los patrones de diseño fueron categorizados en 3 grupos:\nPatrones creacionales: Tratan la creación de objetos de un modo controlado basandose en unos criterios requeridos. Patrones estructurales: Tratan la organización de distintas entidades software para crear estructuras mayores, extensibles y desacopladas entre sí. Patrones de comportamiento: Tratan la asignación de responsabilidades entre distintas entidades software y como éstas se comunican entre sí. Hay que mencionar también que existen patrones de diseño para dominios específicos, como pueden ser la visualización de información, la seguridad, el diseño web\u0026hellip; El grupo Hillside viene realizando, desde hace años, unas conferencias anuales sobre los patrones de diseño de software, dónde se contemplan estos patrones específicos para un dominio.\n","id":33,"tag":"Patrones de diseño","title":"Patrones de diseño","url":"https://metrosetenta.es/blog/patrones-de-diseno/"},{"content":"Al espacio de memoria donde Java almacena objetos se denomina heap. El heap se crea cuando la maquina virtual de java, JVM, se inicia, y puede aumentar o disminuir de tamaño durante la ejecución de la aplicación. Cuando se llena este espacio de memoria Java inicia el proceso de recolección de basura, Garbage Collector. Durante la recogida de basura, los objetos que ya no se utilizan son eliminados, creando así espacio para nuevos objetos. La JVM puede iniciarse con unos parámetros para gestionar la memoria. Con Xmx configuramos el tamaño máximo del heap y con Xms el tamaño mínimo. La JVM tiene, también, un espacio permanente para alojar objetos, el Permanent Generation o Metaspace desde Java 8. Será el espacio donde se alojan las clases y los métodos. Un ejemplo de configuración de estos parámetros sería como sigue:\n-Xms256m -Xmx1024m -XX:PermSize=512m -XX:MaxPermSize=512m ","id":34,"tag":"Java","title":"Gestión de memoria de la máquina virtual de Java","url":"https://metrosetenta.es/blog/gestion-de-memoria-de-la-maquina-virtual-de-java/"},{"content":"origin es la palabra con la que git nombra por defecto un repositorio remoto cuando lo clonas. Renombrar este repositorio como, por ejemplo, gitlabMetroSetenta es una buena idea, porque origin parece una palabra reservada de Git y puede causar confusiones. Para comprobar con detalle los repositorios remotos que has configurado en un proyecto git, usa el siguiente comando:\ngit remote -v Para renombrar un repositorio remoto origin como miRepositorioRemoto puedes usar este otro:\ngit rename origin miRepositorioRemoto ","id":35,"tag":"Git","title":"Renombrar un repositorio remoto en Git","url":"https://metrosetenta.es/blog/renombrar-un-repositorio-remoto-en-git/"},{"content":"Vamos a mejorar un poco las búsqueda de porciones de código dentro de nuestros proyectos y, para ello, vamos a comenzar por la entrada de datos que le damos a fzf. Te presento a ripgrep, una herramienta de búsquedas que tiene un rendimiento increible en comparación con otras parecidas como ugrep o ack. Ripgrep usa el archivo .gitignore por defecto, lo que le dá un enfoque muy Desarrollo para la búsqueda de código. Aquí tienes los diferentes métodos de instalación. Una vez que hayas aplicado el mejor para tu máquina, prueba a ejecutar, por ejemplo, el comando rg return en la carpeta de uno de tus proyectos, donde rg ejecutará ripgrep y return será el criterio de búsqueda. ¡A mí me pareció impresionante, especialmente, por su velocidad!\nEn Vim, gracias a fzf.vim, puedes darle esta entrada de datos a fzf, con esta capacidad de configuración y velocidad, usando el comando Rg. Seguro que te parece una alternativa mejor a la que te conté en este artículo. Aquí te comenté como instalar fzf.vim.\nEs el turno ahora de mejorar las búsquedas de archivos dentro del proyecto. Si compruebas el listado de comandos disponibles con fzf.vim, verás que Files ejecuta el comando que esté definido en la variable de entorno $FZF_DEFAULT_COMMAND y, en su defecto, ejecutará el comando FZF. Un modo de mejorar nuestra búsqueda de archivos es ajustando dicha variable en la configuración de nuesto Shell para que use ripgrep.\nexport FZF_DEFAULT_COMMAND=\u0026#39;rg --files --follow --hidden\u0026#39; Y ahora sólo resta añadir o modificar nuestro mapa de teclas en la configuración de Vim para usar el comando Files:\nnnoremap \u0026lt;C-p\u0026gt; :Files \u0026lt;CR\u0026gt; ","id":36,"tag":"Vim","title":"Mejorando las búsquedas en Vim","url":"https://metrosetenta.es/blog/mejorando-las-busquedas-en-vim/"},{"content":"Pues nada, que andaba probando programas para crear gifs y, como no me convencieron los que probé del repositorio oficial de Manjaro, pues busqué alguno en AUR, el repositorio de usuarios de Arch. En la interfaz gráfica de pamac pulsé la opción para refrescar las base de datos e instalar las actualizaciones pendientes. Desde ese momento, cualquier intento de instalación de cualquier software, utilizando los repositorios de AUR, me devolvían el siguiente error:\ntarget not found Lo cierto es que nunca he necesitado cacharrear en profundidad con los gestores de paquetes de software y, por este motivo, me costó dar con el problema y solucionarlo. Desde la interfaz gráfica de pamac no tenía ninguna opción para ayudarme a dar con la solución, así que, con ayuda de la documentación, probé a instalar paquetes del AUR usándo pamac desde la consola. Así fué como encontré la siguiente pista.\nERROR: PKGBUILD contains CRLF characters and cannot be sourced. Este mensaje ya me resultaba más familiar. Soy usuario de Linux y, muy a mi pesar, en casi todas las empresas de mi ciudad se utiliza Windows como sistema operativo, que usa una secuencia de control de caracteres, para indicar un final de línea, muy distinto al de los sistemas Unix. Al compartir código usando repositorios de Git es habitual usar la siguiente configuración para que Git no considere, basándose en esta secuencia de control de caracteres, que todas las líneas contienen cambios.\nautocrlf = true Esto se usa para convertir los caracteres LF con los que los sistemas Unix finalizan las líneas de código en los caracteres CRLF propios de Windows. Como AUR podría entenderse como un repositorio de scripts que se descargan habitualmente con Git, estaba claro que, con mi configuración de Git, había cambiado los finales de línea a CRLF al descargar las actualizaciones. Mi equipo Unix estaba intentando ejecutar uno de estos scripts y siempre resultaba en una salida de error. Se trataba, ahora, de localizar los archivos con los finales de línea incorrectos y eliminarlos para descargar de nuevo los scripts correctos. Antes, por supuesto, reajusté la configuración de Git.\nautocrlf = false En mi distribución, los archivos incorrectos estaban descargados en /var/tmp/pamac-build-javier/, así que los borré todos con el comando de abajo. Ten en cuenta que tu dirección será distinta a no ser que tu usuario, en tu sistema operativo, también sea javier.\n$ rm /var/tmp/pamac-build-javier/* -Rf ¡Y eureka, despues de un par de horas de investigación, ya podía volver a instalar software desde el AUR usando pamac!\n","id":37,"tag":"Equipo","title":"Target Not Found en Pamac","url":"https://metrosetenta.es/blog/target-not-found-en-pamac/"},{"content":"En éste artículo ya te conté que es fzf y como usarlo en Vim para buscar archivos dentro de tu proyecto, pero lo cierto es que podemos aplicarlo para muchísimos más usos. Mediante fzf.vim puedes tener configurados varios comandos en Vim, sin estar familiarizado con Vimscript, que ponen a tu disposición las aplicaciones más comunes de fzf en este editor de texto.\nComo siempre, si usas el gestor de conectables vim-plug, que aprendimos a instalar aquí, es muy sencillo conectar fzf.vim. La primera línea instalará el conectable de vim del repositorio básico de fzf. Comprueba si ya la tenías en tu configuración con anterioridad.\nPlug \u0026#39;junegunn/fzf\u0026#39;, { \u0026#39;do\u0026#39;: { -\u0026gt; fzf#install() } } Plug \u0026#39;junegunn/fzf.vim\u0026#39; Y listo, ya tienes un juego de comandos realmente útiles que, además, pueden ser configurados para ajustarlos más a tus gustos y necesidades. Dispones, por ejemplo, del comando Commits, que dará como entrada a fzf un listado de los commits de tu proyecto Git. Con Lines, la entrada que usará fzf serán las líneas de los buffers cargados, y del bufer actual en el caso de que uses BLines. No dejes de echarle un vistazo aquí a los comandos disponibles con fzf.vim, como History, Marks, Tags\u0026hellip;\n","id":38,"tag":"Vim","title":"Sacándole más partido a fzf en Vim","url":"https://metrosetenta.es/blog/sacandole-mas-partido-a-fzf-en-vim/"},{"content":"Seguro que estás acostumbrado a usar criterios de búsquedas y a aplicar filtros a un conjunto de datos. Cada vez que usas un búscador como Google o DuckDuckGo lo haces. Habitualmente los criterios de búsqueda son aplicados usando algoritmos muy rígidos, que devuelven resultados donde las coincidencias de los datos con dichos criterios son exactas. Deja que te hable ahora sobre la búsqueda difusa (Fuzzy search), donde los algoritmos aplicados son más indulgentes, consiguiendo así que podamos lograr resultados a los que no accederíamos con los métodos expuestos anteriormente.\nTe escribo un sencillo ejemplo usando el criterio de búsqueda termino. Si aplicáramos los métodos habituales de búsqueda a un texto, para localizar las líneas que contienen dicho criterio podríamos obtener resultados tal que así:\nSi termino más rápido de lo previsto te aviso para que pases antes a recogerme.\nAplicando una búsqueda difusa, obtendríamos líneas donde el criterio de búsqueda está en plural, con distintos acéntos gráficos, escrito erróneamente, etc.\nSi termino más rápido de lo previsto te aviso para que pases antes a recogerme.\nEn el examen olvidé un término bastante importate, seguro que me ha bajado la nota.\nEl chico que terminó justo antes que yo tropezó cuando iba a entregar el examen.\ny como nadie conocía los términos en los que se había pactado su salida, resultó\n, y aunque te resulte confuso, mirándolo detenidamente seguro que es\nLa búsqueda difusa es útil, por tanto, cuando es importante conseguir resultados donde la relevancia no está determinada por la exactitud con la que estos se ajustan al criterio de búsqueda. En su lugar, el usuario tiende a buscar una idea general, no una etiqueta técnica, espera recibir más resultados y ser él quien decida la relevancia de estos. La búsqueda en archivos académicos, textos traducidos con posibles errores o sistemas de archivos son algunos casos de uso donde aplica perfectamete la búsqueda difusa.\n","id":39,"tag":"Algoritmo","title":"Búsqueda difusa","url":"https://metrosetenta.es/blog/busqueda-difusa/"},{"content":"Prettier es una herramienta de formateo de código de gran popularidad en el ecosistema JavaScript. Mediante unas opciones especificadas en su archivo de configuración podemos conseguir que todos los archivos de código formateados con Prettier luzcan idéntico sangrado (indent), tipo de comillas, uso de espacios, ancho de líneas, y demás aspectos de estilo. Para disponer de Prettier únicamente tienes que añadirlo a tu proyecto.\n$ npm install --save-dev --save-exact prettier # or globally $ npm install --global prettier Puedes ejecutar Prettier mediante su CLI, o puedes engancharlo para que se ejecute justo antes de una confirmación de cógido de Git, un pre-commit hook, pero la intención de este artículo es usarlo en Vim para que dé formato a tu archivo de código cuando lo guardas.\nSi estás usando ESLint del modo que te conté aquí, tienes que saber que algunos métodos de Prettier pueden entrar en conflicto con las capacidades de formateo de ESLint. Para evitar esto es mejor dejar que ESLint cuide de la correción del código mientras que Prettier se encarga únicamente de dar formato al guardar el archivo. Lo puedes conseguir desactivando, mediante eslint-config-prettier, la reglas de ESLint que entra en conflicto con Prettier.\n$ npm install --save-dev eslint-config-prettier También tienes que añadir a ESLint las capacidades de correción de código de Prettier para seguir disponiendo de ellas, y esto lo puedes hacer con eslint-plugin-prettier.\n$ npm install --save-dev eslint-plugin-prettier La forma más sencilla de configurar los dos dispositivos software que acabas de instalar es mediante el archivo de configuración de ESLint.\n{ \u0026#34;extends\u0026#34;: [\u0026#34;plugin:prettier/recommended\u0026#34;] } Eso es todo lo que necesitas para integrar Prettier con ESLint, ahora deja que te muestre como configurarlo con Vim para formatear el código de tu archivo JavaScript en el momento de guardarlo. Además de gestionar correctores de errores, como te mostré aquí, Ale tambén ejecuta correctores de formato de código en el buffer de Vim, todo lo que necesitas hacer es especificar en el archivo de configuración de Vim lo siguiente:\nlet g:ale_fixers[\u0026#39;javascript\u0026#39;] = [\u0026#39;eslint\u0026#39;] \u0026#34; Fix files automatically on save let g:ale_fix_on_save = 1 Con esta configuración será ESLint el encargado de corregir el código y advertir de errores de formato, mientras que Prettier realizará el formateo del código al guardar al archivo.\n","id":40,"tag":"Vim ; JavaScript","title":"Javascript con Vim: Formateando el código","url":"https://metrosetenta.es/blog/javascript-con-vim-formateando-el-codigo/"},{"content":"Los programas de análisis y correción de código son nombrados en inglés como linters. Un corrector de este tipo te ayuda a identificar errores potenciales en tu código sin necesidad de ejecutarlo, evitar patrones problemáticos e, incluso, cumplir con una guía de estilo. En JavaScript, el linter más usado se llama ESLint, y puedes instalarlo siguiendo los pasos aquí indicados. Por defecto, ESLint está configurado mediante un juego de reglas que, comprobando si el código las cumple, gestionan los problemas más comunes. Por supesto, puedes personalizar estas reglas para solucionar problemas específicos; de hecho, existen paquetes de configuración de ESLint, como Airbnb, y es posible que se ajusten a tus necesidades, ahorrándote mucho tiempo en hacer esta tarea.\nESLint es una herramienta de línea de comandos, y al igual que con otras herramientas de líneas de comando, podemos integrarla con Vim para, en este caso, disponer de las características de análisis y correción de código en el mismo instante en el que lo estamos escribiendo. Para conseguir esto Ale es una gran opción. Ale es un motor asíncrono de correción de código que implementa el protocolo LSP (Language Server Protocol). Esto quiere decir que actua entre Vim (cliente) y un proveedor de inteligencia de lenguaje (servidor), para integrar características como autocompletado, ir a definiciones, encontrar referecias y otras utilidades similares útiles para el desarrollo. Aquí tienes los métodos de instalación de Ale. Una vez que lo conectes a Vim y abras un archivo JavaScript de un proyecto configurado con ESLint, este funcionará sin más ajustes. Con el siguiente comando puedes listar los errores y avisos del fichero,\n:lopen y si lo prefieres, puedes preparar unos atajos de teclado para navegar rapidamente entre ellos.\nnmap \u0026lt;silent\u0026gt; [c \u0026lt;Plug\u0026gt;(ale_previous_wrap) nmap \u0026lt;silent\u0026gt; ]c \u0026lt;Plug\u0026gt;(ale_next_wrap) Puedes comprobar que, cuando el cursor se encuentra sobre una línea de código problemática, aparece información a cerca de la advertencia o el error marcado en la parte inferior de Vim.\n","id":41,"tag":"Vim ; JavaScript","title":"JavaScript con Vim: Corrigiendo el código","url":"https://metrosetenta.es/blog/javascript-con-vim-corrigiendo-el-codigo/"},{"content":"Aunque Vim soporta sintaxis básica para JavaScript, cuando trabajes con especificaciones modernas del lenguaje o bibliotecas como React, que usa JSX, notarás que no funciona todo lo bien que esperas. Una buena opción para realatar la sintaxis de JavaScript en Vim es Polyglot, un conectable que gestiona otros conectables, de sintaxis en este caso, cargándolos bajo demanda para evitar afectar al rendimiento de tu editor de texto. Gracias a Polyglot, si cambias de framework de JavaScript, o si gestionas archivos de otro lenguaje, no es necesario que instales nuevos conectables, porque él lo gestionará de un modo sencillo.\nSi usas vim-plug es muy sencillo enchufar Polyglot a Vim\nPlug \u0026#39;sheerun/vim-polyglot\u0026#39; Si necesitas instalar vim-plug, aquí tienes un artículo explicando como puedes hacerlo.\nPor último, asegúrate de que la sintaxis está activa.\n:set syntax=on ","id":42,"tag":"Vim ; JavaScript","title":"JavaScript con Vim: Resaltando la sintaxis","url":"https://metrosetenta.es/blog/javascript-con-vim-resaltando-la-sintaxis/"},{"content":"Como ya te expliqué en este artículo, al retomar este blog quería mejorar la navegación y, para ello, decidí implementar un buscador que permitiera localizar contenido de la manera más eficaz posible. El tema con el que está generado el blog, Mainroad, incluye la posibilidad de renderizar un buscador en la barra lateral con un sencillo ajuste en el archivo de configuración de Hugo, config.toml.\n[Params.sidebar] # Enable widgets in given order widgets = [\u0026#34;image\u0026#34;, \u0026#34;search\u0026#34;, \u0026#34;categories\u0026#34;] La caja de búsqueda es sencilla, me gusta el estilo, pero cuando se visualiza el blog en una pantalla más pequeña la barra lateral que la contiene se muestra debajo de los primeros posts. Yo prefiero que el buscador esté siempre visible, desde el inicio, para que de este modo se pueda acceder al contenido rápidamente sin tener que navegar a la parte inferior del blog, así que probé a sacar la caja de búsqueda de la barra lateral y colocarla debajo del título, justo antes del primer artículo. Gracias a que el widget de búsqueda esta escrito en su propio partial, es sencillo probar la caja de búsqueda, en esa ubicación, añadiendo una única línea de código en la plantilla base del blog.\n{{partial \u0026#34;widgets/search.html\u0026#34; . }} Al colocar el buscador en esa posición el aspecto del blog en pantallas pequeñas era bueno, pero no en pantallas de tamaño mayor, por esto decidí condicionar su posición al tamaño de la pantalla. Mainroad ya hace esto con la posición de la barra lateral, la gestiona mediante CSS con una Media query, así que usé esa misma condición, la que lleva la barra lateral a la parte inferior del blog, para ocultar la caja de búsqueda en dicha barra lateral y mostrar, en su lugar, la caja de búsqueda que coloqué bajo el título del blog.\n/* Search widget */ @media screen and (min-width: 768px) { .primary .widget-search { display: none; } } @media screen and (max-width: 767px) { .sidebar .widget-search { display: none; } } ","id":43,"tag":"Hugo","title":"Hugo y el buscador: Presentando el widget de búsqueda","url":"https://metrosetenta.es/blog/hugo-y-el-buscador-presentando-el-widget-de-busqueda/"},{"content":"Hugo se presenta como el constructor de sitios web más rápido del mundo. Está escrito con Go y genera sitios de forma estática con la intención de ofrecer mejor rendimiento, seguridad y facilidad de uso. Por cada petición que recibe un sitio generado dinámicamente su servidor HTTP crea un nuevo archivo HTML. Con el tiempo estos generadores de sitios dinámicos comenzaron a almacenar algunas páginas en caché para mejorar el rendimiento. En tanto que Hugo no genera las páginas dinámicamente, sino que renderiza todos los archivos HTML en tu computadora, podemos definirlo como un generador de sitios estáticos. Es como si un generador de sitios dinámicos almacenara todas las páginas en caché. Este método te permite revisar todas las páginas en local tal cual serán enviadas al cliente y, además, el servidor HTTP las servirá usándo únicamente una fracción de cómputo y memoria de la que necesitaría un sitio generado dinámicamente.\n","id":44,"tag":"Hugo","title":"Hugo, generador de sitios estáticos","url":"https://metrosetenta.es/blog/hugo-generador-de-sitios-estaticos/"},{"content":"Cuando gestionaba mis dotfiles era habitual encontrarme, entre los archivos modificados, al misterioso netrwhist. Antes que nada debes de saber que netrw es un script conectable a vim, que está orientado a redes y que permite lectura, escritura y navegación. netrwhist es el archivo donde netrw guarda un histórico de los directorios que fueron modificados. netrw tiene bastantes opciones de configuración:\nlet g:netrw_banner = 0 let g:netrw_liststyle = 3 let g:netrw_browse_split = 4 let g:netrw_altv = 1 let g:netrw_winsize = 25 let g:netrw_dirhistmax = 10 let g:netrw_dirhist_cnt = 6 Un modo de no versionar este histórico es usar el parámetro de configuración netrw_home para guardar su histórico fuera del repositorio dotfiles.\nlet g:netrw_home=$HOME.\u0026#39;/.cache/vim\u0026#39; Otra opción que puedes considerar es añadirlo a tu archivo .gitignore, pero si optas por ella, y eres consistente con el resto de tus archivos históricos, el problema es la gestión de tu .gitignore, que puede crecer demasiado, desactualizarse, etc. El problema de la primera opción es que no exista la carpeta .cache si usas tus dotfiles en una nueva máquina. Yo opté por la primera opción porque este problema me parece más sencillo de solucionar y más eventual. ¿Cuál eliges tú?\n","id":45,"tag":"Git ; Vim","title":"El misterioso netrwhist","url":"https://metrosetenta.es/blog/el-misterioso-netrwhist/"},{"content":"Hace poco un compañero me preguntó cómo podía consultar los archivos que había gestionado en un desarrollo, desde la versión que había partido, hasta la versión actual en la que se encontraba. Consultando un poco dimos con esta opción,\n$ git diff 0819dfcb 20620b5b --name-only Y el resultado era exáctamente el que buscábamos, nombres de los archivos que habian sufrido algún tipo de modificación entre los dos commits que le estábamos pasando al comando git diff.\nbash/aliases bash/rc bash/specific_aliases bash/specific_rc guake/preferences vim/.netrwhist vim/rc Al usar esta información, mi compañero comprobó que los archivos podían haber sido eliminados, además de creados o modificados; esos archivos eliminados no existian en la versión actual, y la nueva necesidad se centró en identificarlos. Para esto usamos git log de este modo,\n$ git log 0819dfcb 20620b5b --diff-filter=D --summary | grep delete pero el resultado no era tan limpio.\ndelete mode 100644 vim/.netrwhist De nuevo, la mejor opción volvia a pasar por git diff,\n$ git diff 0819dfcb 20620b5b --name-status | grep \u0026#39;^D\u0026#39; que daba esta otro resultado más limpio y más sencillo de manipular.\nD\tvim/.netrwhist De hecho, el comamdo que finalmente usó mi compañero para el script que estaba desarrollando, fue\n$ git diff 0819dfcb 20620b5b --name-status con el resultado que sigue, donde además de disponer de los archivos, se aclara el tipo de gestión realizada.\nM bash/aliases M bash/rc M bash/specific_aliases M bash/specific_rc M guake/preferences D vim/.netrwhist M vim/rc Aquí puedes consultar que estado representa cada una de las letras mayúsculas que anteceden a los archivos.\n","id":46,"tag":"Git","title":"Consultar con Git los archivos modificados","url":"https://metrosetenta.es/blog/consultar-con-git-los-archivos-modificados/"},{"content":"Cuando estas desarrollando software y te encuentras por primera vez con un problema que tienes que resolver, puedes dedicar unos 20 minutos a navegar por la red, buscando, probando y valorando la información necesaria para conseguir la solución correcta. En ocasiones debes construir dicha solución con porciones y modificaciones de otras propuestas que no se adaptan correctamente al problema concreto que necesitas solucionar.\nSi después de hacer esto, dedicas un poco de tiempo a escribir sobre ello, puedes disponer de la información en caso de que te haga falta en el futuro y, además, ayudar a otras personas que podrían encontrarse con la misma dificultad que te encontraste tú.\nQue esas personas encuentren tu solución, si es realmente buena, es el trabajo de los motores de búsqueda, por tanto, el hecho de que un artículo ofrezca una solución concisa y comprensible a un problema es, posiblemente, la mejor estrategia SEO para un blog sobre tecnología en tanto que, los motores de búsqueda, intenta facilitar información a sus usuarios para resolver una cuestión.\n","id":47,"tag":"SEO ; Blog","title":"Breve pensamiento sobre SEO","url":"https://metrosetenta.es/blog/breve-pensamiento-sobre-seo/"},{"content":"El modo en el que se suele recomendar el uso de las etiquetas en un blog, que es el que he venido adoptando hasta hace poco, está muy enfocado en obtener buenas clasificaciones en los resultados de buscadores. Al retomar el blog este ha sido un aspecto al que quería darle un enfoque distinto, dejando de lado las recomendaciones para una estrategia SEO convencional.\nCon el nuevo enfoque quería facilitar la navegación, a la par que mejorar la experiencia de usuario, y para conseguirlo me he visto obligado a involucrar también a las categorías de mi blog. El principal usuario de mi blog soy yo mismo, pues lo uso para anotar soluciones a problemas que he encontrado y detalles importantes sobre todo lo que aprendo referente a mi profesión, y esto me hace volver frecuentemente a él para realizar consultas.\nTe cuento sobre las categorías. En el blog no había muchas categorías, que suele ser el error más habitual, pero un artículo podía pertenecer a más de una categoría. El contenido del blog parece mayor usando esta práctica, pero lo cierto es que, la experiencia del usuario que está intentando localizar un contenido concreto, y encuentra un mismo artículo una y otra vez, es realmente mala. Por esto decidí que los artículos han de pertenecer a una única categoría.\nAl usar las categorías para acceder a contenido del blog se te presenta un gran número de páginas por las que navegar y encontrar el artículo deseado, lo cual es realmente tedioso con los artículos más antiguos. Es ahora el turno de las etiquetas. Las etiquetas son un modo de afinar un poco más el tiro cuando ofreces al usuario una nube de etiquetas. También me gusta pensar en ellas como un modo de localizar, al final de un artículo, más artículos que traten el mismo tema. Quiero decir que, cuando terminas de leer un artículo sobre, por ejemplo, programación funcional, y quieres localizar más artículos sobre este tema en el mismo blog, una etiqueta es el modo ideal que el autor puede facilitarte.\n","id":48,"tag":"SEO ; Blog","title":"Sobre categorías y etiquetas","url":"https://metrosetenta.es/blog/sobre-categorias-y-etiquetas/"},{"content":"¿Qué te parece si vemos en acción a Deno, el pequeño diplodocus del que hablamos en el artículo anterior? El primer paso, como no puede ser de otro modo, es instalarlo en tu equipo, y para esto dispones de varias opciones que se adaptan a tu sistema operativo o a tus preferencias. Los usuarios de Linux pueden hacerlo facilmente desde la consola, al igual que los de macOS que, además, pueden usar Homebrew. Para Windos existe la posibilidad de usar PoweShell, Chocolatey o Scoop. En este post nos centraremos en Linux. El comando de instalación es sencillo, y únicamente necesitas tener instalado curl:\n$ curl -fsSL https://deno.land/x/install/install.sh | sh Si necesitas instalar una versión específica puedes indicarlo con el parámetro -s. En el ejemplo que sigue verás que lo uso para instalar la versión v0.38.0:\n$ curl -fsSL https://deno.land/x/install/install.sh | sh -s v0.38.0 Por defecto, la aplicación se instala en tu carpeta de usuario, pero puedes indicar el directorio de instalación si lo necesitas.\n$ curl -fsSL https://deno.land/x/install/install.sh | sudo DENO_INSTALL=/usr/local sh Una vez que el script de instalación haya finalizado, te dará indicaciones para ajustar un par de variables de entorno. Puedes hacerlo en la configuración del procesador de comandos para asegurarte de que están disponibles al usar Deno.\n# Ajustes para Denoland export DENO_INSTALL=\u0026#34;/home/metroSetenta/.deno\u0026#34; export PATH=\u0026#34;$DENO_INSTALL/bin:$PATH\u0026#34; Voy a hablarte ahora de como instalar y gestionar múltiples versiones de Deno, y aquí entra en acción asdf-vm, una herramienta para la Interfaz de línea de comandos que permite gestionar versiones de entornos de ejecución. asdf-vm se puede extender mediante plugins y el plugin para Deno, asdf-deno, ya está disponible. Si no has usado anteriormente asdf-vm, aquí tienes toda la información necesaria para hacerlo. Luego sólo tendrás que añadirle el plugin correspondiente para poder gestinar tus versiones de Deno.\n$ asdf plugin-add deno https://github.com/asdf-community/asdf-deno.git Una vez hecho, es sencillo instalar cualquier versión de Deno,\n$ asdf install deno 0.38.0 activar una versión de manera global,\n$ asdf global deno 0.38.0 o hacerlo simplemente de manera local.\n$ asdf local deno 0.38.0 ","id":49,"tag":"JavaScript ; Deno","title":"Instala y gestiona múltiples versiones de Deno","url":"https://metrosetenta.es/blog/instala-y-gestiona-multiples-versiones-de-deno/"},{"content":"Deno se define a sí mismo como un seguro sistema o entorno de ejecución para JavaScript y Typescript. El creador originar de Node.js, Ryan Dahl, fue quien anunción esta nueva herramienta en 2018, así que es inevitable fijarse en el juego del intercambio de sílabas (No-de / De-no), a pesar del divertido dino que usa como logo, que puede despistar. Pero ¿Por qué querría Dahl crear otra vez Node.js, un software que cuenta con un apoyo y una aceptación suficientes para hacerlo exitoso por décadas? Pues parece que alguna espinita se le quedó clavada, vamos a ver cual puede ser.\nDeno no dispone de gestor oficial de paquetes, lo que puede parecer en un primer momento un inconveniente, pero todo cambia cuando descubres lo siguiente. En lugar de usar el sistema de importación CommonJS, Deno usa ES Modules de un modo realmente interesante. Permíteme explicarme mejor. En lugar de paquetes de código publicados a un repositorio, puedes ejecutar ES Modules publicados en cualquier URL de la red. Esto provoca dos sensaciones contradictorias: La primera de ellas es una sensación de grandes posibilidades, porque puedes crear paquetes sin tener que publicarlos en un repositorio como npm, lo puedes publicar en cualquier URL, pero, posteriormente te invade una sensación de inseguridad al ejecutar contenido en tu máquina de cualquier sitio de la red, sea oficial o no. Bien, para esto último déjame decirte ya que, a diferencia de Node.js, en donde un programa tiene los mismos permisos que el usuario, con Deno esto es diferente. Deno integra una sandbox, es decir, un mecanismo de seguridad para disponer de un entorno aislado del resto del sistema operativo, donde es posible ajustar distintos permisos de acceso para los ejecutables. Y, para finalizar, en todo caso, Deno ya ofrece servicio de repositorio a través de URLs en https://deno.land/x/.\nLas características modernas de ECMAScript que usa Deno en toda su API y biblioteca estandar le permiten prescindir de la biblioteca estandar basada en retrollamadas en la que se basa Node.js, más compleja y comprometida. Deno dispone también de características integradas para realizar pruebas, además de ayudas para gestionar la compatibilidad entre navegadores. Al estar escrito con Rust y TypeScript, también ofrece ventajas si te inclinas por desarrollar en este último lenguaje, pero puedes seguir programando con Javascript si lo prefieres.\nNo dejes de visitar su web para conocerlo porque, aunque no va a destronar a su hermano mayor hoy, sí que puede resultar interesante conocer su evolución.\n","id":50,"tag":"JavaScript ; Deno","title":"¿Qué es Deno?","url":"https://metrosetenta.es/blog/que-es-deno/"},{"content":"Al iniciar el proceso de diseño de una arquitectura software, la primera dificultad que debes acometer es definir con sencillez la necesidad que nuestro desarrollo va a solucionar y cómo va a hacerlo. Este paso es realmente importante, y no imaginas la cantidad de ocasiones que se pasa por alto, lo cual provoca dificultades en fases posteriores del desarrollo e, incluso, el fracaso de algunos proyectos. El mejor modo de comenzar a hacerlo es dividir el desafío propuesto en cuatro aspectos fundamentales:\nFuncional: Describe la necesidad técnica que el cliente o el usuario desea solventar. Formal: Describe la estructura de la solución y el modo en el que se ajusta a distintos entornos, sistemas y tecnologías. Económico: Describe cuanto costará contruir, gestionar y mantener dicha solución. Temporal: Describe la duración del desarrollo, o, en el caso de que existiera, la fecha límite de ejecución. Una vez identificados y descritos estos cuatro aspectos, definir el desafío arquitectónico será mucho más sencillo.\n","id":51,"tag":"Fundamentos arquitectura","title":"1 desafio 4 aspectos","url":"https://metrosetenta.es/blog/1-desafio-4-aspectos/"},{"content":"Lo normal es que tu expectativa de lo que vas a encontrar a continuación dependa de tu experiencia en el desarrollo de software. El concepto de arquitectura de software puede llegar a ser muy distinto dependiendo de la persona que lo use: Lo que comprende un desarrollador como arquitectura puede llegar a ser muy distinto de la idea de un probador o un técnico en devops. Esto hace que publicar una definición básica del concepto de arquitectura de software sea ciertamente arriesgado pero, basándome en lo que me gustaría haber encontrado cuando empecé a estudiarla, y amparado en que existe algún punto común, pues para todos implica la definición de una estructura, me atrevo a darte la que sigue:\n\u0026ldquo;La arquitectura de software trata sobre cómo se ajustan las piezas para construir la solución para un negocio o una necesidad técnica que el cliente o el usuario desea resolver.\u0026rdquo;\n","id":52,"tag":"Fundamentos arquitectura","title":"Definicion de arquitecura software","url":"https://metrosetenta.es/blog/definicion-de-arquitecura-software/"},{"content":"El título de esta entrada suena realmente lógico y no merece profundizar más en él, pero ¿Cómo puedes hacerlo? El problema es que en ocasiones, en la carpeta del proyecto, guardas archivos de configuración que si bien no son propios del proyecto, sí que son necesarios, y resulta cómodo tenerlos en dicha ubicación. Desde mi punto de vista, las configuraciones de los distintos IDEs son el caso más común de esto que te comento.\nRefiriéndonos al gestor de versiones Git, lo habitual es que el proyecto disponga de un archivo específico, nombrado .gitignore, donde se indica qué modificaciones deben ser obviadas en la construción de las distintas versiones. Habitualmente están incluidas en esta declaración las bibliotecas de código de terceros, que se suelen instalar con un gestor de dependencias, y los archivos resultado de una compilación, pero ¿Como puedes a hacer un ejercicio por adelantar que IDEs se usarán, como se nombrarán los documentos que contengan la declaración de sus ajustes y dónde se guardarán? Esta responsabilidad parece que, más bien, debe recaer en cada desarrollador.\nGit te ofrece la posibilidad de configurar un documento del tipo .gitignore con caracter global, llamémosle .gitignore_global, de modo que puedes indicarle a Git que, en todos tus proyectos, ignore tus archivos de configuración personales. Si quieres saber que archivo está usando Git como .gitignore_global ejecuta el siguiente comando:\n$ git config --global core.excludesfile Para configurar otro archivo distinto, sólo tienes usar la sentencia anterior añadiendo al final el archivo que quieres usar.\n$ git config --global core.excludesfile /home/metroSetenta/.gitignore_global El contenido del archivo es sencillo, se trata de patrones. Aquí tienes más información para hacerlos tú mismo, pero puedes tomar de base las propuestas en gitignore.io.\nVamos un poco más allá. Lo cierto es que si trabajas en proyectos muy distintos, en ocasiones no usas las mismas reglas o, incluso, es posible que quieras tener reglas para ignorar archivos que sean contradictorias entre dos o más de tus proyectos. Para esto, también dispones de la opción de configurar dichas reglas en un documento específico para cada proyecto, pero que no será agregado a las siguietes versiones de dicho proyecto . Dentro de la carpeta del proyecto en el que deseas configurar estas reglas específicas navega a .git/info/exclude, e indícalas ahí.\n\u0026ldquo;Se responsable con los proyectos en los que trabajas y no versiones archivos ajenos al proyecto, pídele al gestor de versiones que los ignore.\u0026rdquo;\n","id":53,"tag":"Git","title":"No versiones archivos ajenos al proyecto","url":"https://metrosetenta.es/blog/no-versiones-archivos-ajenos-al-proyecto/"},{"content":"Sin duda, Git es una herramienta potentísima para el control de versiones, y conocer bien su funcionamiento nos facilita muchísimo el trabajo a la hora de escribir, probar y corregir código. Algunas de sus funcionalidades, las más avanzadas, son menos usadas y, por ello, tienden a conocerse menos. Algo que me obliga a ir a la documentación de Git de cuando en cuado es la necesidad de modificar el mensaje en varios commits. Recuerdo que la primera vez que lo necesité fue cuando, en un daily (reunión diaria típica de la metodología Scrum) un compañero nos pidió al resto que los mensajes de todos los commits comenzaran con el número de issue (es algo así como un número de ticket en Jira). En ese momento yo estaba terminando un feature con más de 10 commits, y pensé que hacerlo de uno en uno, usando reword en un rebase interactivo, sería muy tedioso. Ahora, si estoy programando algo y aún no tengo ese número de issue, uso un placeholder para recordar que tengo que poner el número de issue en el lugar que ocupa, y una vez que dispongo de dicho número, uso el siguiente comando de Git, filter-branch:\n$ git filter-branch -f --msg-filter \u0026#39;sed \u0026#34;s/ISSUENUMBERHERE/MP-3242/g\u0026#34;\u0026#39; HEAD~3..HEAD Al ejecutar el comando de aquí arriba, usamos el programa sed para sustituir, en los trés últimos commits, el placeholder ISSUENUMNBERHERE por el identificador de issue MP-3242.\n","id":54,"tag":"Git","title":"Modificando el mensaje de varios commits con un único comando","url":"https://metrosetenta.es/blog/modificando-el-mensaje-de-varios-commits-con-un-unico-comando/"},{"content":"Algo que recuerdo tedioso de mi época de probar distintas distribuciones de Linux es configurar los atajos de teclado. I3 es la primera opción a valorar para quienes tocan el ratón lo mínimo e imprescindible, pero Gnome ha avanzado bastante en este aspecto, y, como es el entorno de escritorio que uso actualmente, te voy a comentar como he configurado en él los espacios de trabajo.\nEn mi distribución de Linux, Manjaro, pulsando la tecla Super (habitualmente ilustrada con una ventana, y conocida como tecla Win en Windows) dispones de un buscador en el sistema operativo. Si comienzas a teclear el nombre de la aplicación Add/Remove Software, la verás sugerida y seleccionable en un instante. En esta aplicación dispones de la posibilidad de buscar paquetes de software haciendo click en el icono de la lupa. Ahí, únicamente teclea Workspaces grid y te aparecerán distintas opciones para construir una parrilla con tus escritorios. Yo personalmente estoy usando Gnome shell vsmatrix.\nMe gusta usar una parrilla de 3x3, disponiendo de este modo de 9 escritorios. No suelo usarlos todos, pero esta configuración me permite disponer de mi editor de código, que es dónde más trabajo, en el escritorio del centro, y desde aquí navegar rápidamente a los demás escritorios y volver con la misma facilidad. Suelo usar uno, del resto de escritorios, para colocar los navegadores, en otro los clientes de gestores de bases de datos, en otro mis canales de comunicación, en otro Amazon music o Spotify\u0026hellip;\nEste software es una extensión que puedes manejar con la aplicación Tweaks, pero la configuración de los atajos de teclado para navegar por los escritorios, o mover las ventanas de uno a otro, no son configurables desde aquí o desde Keyboards shortcuts, pero se pueden configurar desde la consola con el comando gsettings. Puede parecer una desventaja, pero lo cierto es esto nos permite hacer un script reutilizable que podemos guardar y usar cada vez que lo necesitemos, ya sea para realizar esta configuración o restaurarla si la hemos modificado involuntariamente y la queremos recuperar. Aquí abajo está el que yo hice para mí:\n#!/bin/bash # A simple shell script to configure workspaces navigation after install tweak extension workspaces grid # Javier Guerrero - 14/Oct/2019 gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-left \u0026#34;[\\\u0026#34;\u0026lt;Control\u0026gt;\u0026lt;Alt\u0026gt;h\\\u0026#34;]\u0026#34; \u0026amp;\u0026amp; gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-down \u0026#34;[\\\u0026#34;\u0026lt;Control\u0026gt;\u0026lt;Alt\u0026gt;j\\\u0026#34;]\u0026#34; \u0026amp;\u0026amp; gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-up \u0026#34;[\\\u0026#34;\u0026lt;Control\u0026gt;\u0026lt;Alt\u0026gt;k\u0026#34;]\\\u0026#34; \u0026amp;\u0026amp; gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-right \u0026#34;[\\\u0026#34;\u0026lt;Control\u0026gt;\u0026lt;Alt\u0026gt;l\\\u0026#34;]\u0026#34; \u0026amp;\u0026amp; gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-left \u0026#34;[\\\u0026#34;\u0026lt;Control\u0026gt;\u0026lt;Super\u0026gt;\u0026lt;Alt\u0026gt;h\\\u0026#34;]\u0026#34; \u0026amp;\u0026amp; gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-down \u0026#34;[\\\u0026#34;\u0026lt;Control\u0026gt;\u0026lt;Super\u0026gt;\u0026lt;Alt\u0026gt;j\\\u0026#34;]\u0026#34; \u0026amp;\u0026amp; gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-up \u0026#34;[\\\u0026#34;\u0026lt;Control\u0026gt;\u0026lt;Super\u0026gt;\u0026lt;Alt\u0026gt;k\\\u0026#34;]\u0026#34; \u0026amp;\u0026amp; gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-right \u0026#34;[\\\u0026#34;\u0026lt;Control\u0026gt;\u0026lt;Super\u0026gt;\u0026lt;Alt\u0026gt;l\\\u0026#34;]\u0026#34; ","id":55,"tag":"Linux ; Equipo","title":"Navegando por la parrilla de los espacios de trabajo","url":"https://metrosetenta.es/blog/navegando-por-la-parrilla-de-los-espacios-de-trabajo/"},{"content":"Pues no estaba equivocado respecto a la instalación de Manjaro, no. Ha sido mucho más rápido que montar Arch y, tras probarlo, tengo que decir que estoy bastante contento con las opciones de configuración y administración que ofrece. Únicamente he tenido una experiencia negativa hasta el momento de escribir esto, y es que al hacer un escaner de las redes wifi ¡No podía ver ninguna red wifi disponible! Así que tocó investigar un poco. La solución pasaba por desactivar los módulos rtw88 y rtwpci, que fueron instalados junto al kernel, y que no funionaban correctamente con mi tarjeta rtl8822be. Para ello los tenía que añadir a la blacklist del kernel, y atendiendo a la documentación de Arch, lo hice añadiendo estas líneas al archivo /etc/modprobe.d/blacklist.conf que yo mismo tuve que crear:\ninstall rtw88 /bin/false install rtwpci /bin/false Luego, intalé git y el compilador propio de la distro:\n$ sudo pacman -S git dkms Después, instalé el paquete linux-header, para lo cual, primero comprobé la versión de mi kernel:\n$ uname -a $ sudo pacman -S linux-headers Luego cloné en la carpeta tmp el repositorio de código que contenía el controlador actualizado para mi tarjeta de red:\n$ cd /tmp $ git clone -b https://aur.archlinux.org/rtlwifi\\_new-extended-dkms.git Y tras ello, compilé e instalé el módulo correcto para mi tarjeta de red:\n$ sudo dkms add ../rtlwifi\\_new sudo dkms build rtlwifi-new/0.6 sudo dkms install rtlwifi-new/0.6 $ sudo modprobe rtl8822be Como último paso, reinicié el gestor de conexiones y\u0026hellip;\n$ sudo systemctl restart NetworkManger ¡Listo, ya podía visualizar y conectarme a las redes inalámbricas!\n","id":56,"tag":"Linux ; Equipo","title":"Manjaro y la conexión wifi","url":"https://metrosetenta.es/blog/manjaro-y-la-conexion-wifi/"},{"content":"Es habitual que las distribuciones Linux ofrezcan, entre sus opciones de descarga, una imagen de disco. Esta imagen de disco la podemos \u0026ldquo;quemar\u0026rdquo; en un CD/DVD, y también la podemos preparar como ejecutable en un pequeño USB portátil. No obstante, debemos tener en cuenta que si la imagen de disco se descargó incorrectamente, o fué contaminada, en el mejor de los casos no podremos instalar el sistema operativo elegido o, incluso, podríamos instalar un sistema operativo con errores. Para evitar esto, solemos disponer de la posibilidad de comprobar la integridad del archivo con un hash.\nUn hash es una función criptográfica que, mediante un algorítmo matemático, toma un bloque de datos y los procesa para devolver una serie de caracteres que siempre son de la misma longitud. También se suele llamar hash al resultado obtenido tras aplicar dicha función criptofráfica. Si usamos esta potente herramienta, dándole como parámetro de entrada la imagen de disco que hemos descargado, obtendremos un hash relacionado a dicha imagen.\nPor supuesto, en el repositorio de descarga solemos disponer, junto al enlace de descarga de la imagen de disco, de su correspondiente hash. Esto quiere decir que los distrubuidores aplicaron el algoritmo matemático a la imagen de disco, y nos facilitan el resultado. Si la imagen de disco que hemos descargado es exactamente igual a la que ellos facilitan, el hash que publican, y el que nosotros obtenemos al aplicar un hash al archivo descargado, deben ser idénticos. Si nuestro archivo contiene errores, o carece de algún contenido, los hash no serán iguales. Este es el modo de comprobar la integridad del archivo descargado.\nPero, una vez descargado el archivo\u0026hellip; ¿Cómo lo hago? Lo primero es conocer el hash correspondiente al archivo que hemos descargado. En este caso muestro una imagen de la página de descargas de Manjaro.\nAbajo del todo, junto a SHA1, puedes comprobar el código hash de la imagen de disco. SHA1 es un tipo de algorítmo para hacer hash (Secure Hash Algorithm). Otro tipo muy usado es MD5.\nAhora sólo resta hacer hash a nuesta imagen de disco descargada, usando el tipo SHA1, y comprobar que el resultado coincide con el que vemos en la publicación. Para obtener el hash de nuestra imagen de disco descargada podemos hacer ejecutar el siguiente comando en nuestro terminal:\n$ sha1sum -c imagen-de-disco-descargada.iso.sha1 ","id":57,"tag":"Linux","title":"Comprobando una imagen de disco","url":"https://metrosetenta.es/blog/comprobando-una-imagen-de-disco/"},{"content":"Lo cierto es que cuando adquirí el nuevo portátil para trastear en casa con él, mi primera idea fué la de instalar Arch Linux con i3-gaps, pero finalmente me he decantado por instalar Manjaro por los siguiente motivos. Con Arch, se aprende muchisimo sobre instalar, mantener y reparar el sistema operativo, pero lo cierto es que queria dedicar mi tiempo a otros aspectos, y con Arch me quedaba por delante instalar los paquetes básicos, configurar el sistema, zona horaria, configuración de red, localización, sistema de inicio\u0026hellip; Por otro lado, me gusta la filosofía rolling release, pero es cierto que en ocasiones puede crear inestabilidad en el sistema al actualizar un paquete.\nDespués de sopesar varias opciones me decante por Manjaro por varios motivos. Es un sistema operativo basado en Arch, pero tiene un instalador que me permite realizar todas las tareas citadas antes de un modo automático o, en el peor de los casos, bastante más rápido. Añade una capa adicional de pruebas a los lanzamientos de actualizaciones de Arch, así que, de este modo, se reduce la posibilidad de volver al sistema inestable sin renunciar a las últimas versiones de las aplicaciones instaladas. Por último, se puede elegir entre varios escritorios, y aunque existe la opción de i3, que es una versión mantenida por la comunidad, me decanté por Gnome por ser oficial y por el la positiva sensación de uso que tiene para mí. Hay que añadir también que con Manjaro no sólo dispongo de acceso a sus propios repositorios, sino que también puedo usar AUR, el repositorio propio de Arch.\n","id":58,"tag":"Linux ; Equipo","title":"¿Por qué Manjaro?","url":"https://metrosetenta.es/blog/por-que-manjaro/"},{"content":"En mi actual trabajo no puedo usar un sistema operativo distinto de Microsoft Windows 10 enterprise, y el portátil que tengo en casa, por ser compartido, no lo puedo trastear todo lo que quisiera. Por este motivo, y por lo que añoro Linux, he adquirido un nuevo portátil, sin sistema operativo instalado, para mis estudios y proyectos. Estas son algunas especificaciones.\nMarca y modelo Asus Vivobook X510qa-br010 15.6/amd A12-9720p/8gb/ssd256gb/sin So\nProcesador Amd® Quad-core A12-9720p Apu (4 Núcleos, 2mb Caché, 2.7ghz Hasta 3.6ghz, 64-bit)\nPantalla 15.6- (39,62cm) Led Retroiluminado / 60hz / Borde Estrecho / Ultra Slim / 200nits / Hd (1366x768/16:9) / Antirreflejos / Ntsc:45% Memoria Ram 8gb (8gb) Ddr4 2400mhz\nAlmacenamiento 256gb Ssd M.2 Sata3\nGráficos Amd® Radeon- R7 Graphics\nSistema Operativo Sin Sistema Operativo\n","id":59,"tag":"Linux ; Equipo","title":"Portátil para estudios y proyectos","url":"https://metrosetenta.es/blog/portatil-para-estudios-y-proyectos/"},{"content":"Ya te comenté en este pequeñísimo artículo que las funciones tratadas como objetos de primera clase es una de las características que permiten programar con Javascript de un modo funcional. Esto nos permite, por ejemplo, pasar funciones como argumentos de otras funciones, y ahí es donde se produce la inyección de funciones que da título a este artículo.\nLa función sort nos permite mostrar un ejemplo de este concepto. A continuación la función sort en acción:\nlet people = [\u0026#34;Leonardo\u0026#34;, \u0026#34;Rocío\u0026#34;, \u0026#34;Athenea\u0026#34;, \u0026#34;Javier\u0026#34;]; console.log(people.sort()); // [ \u0026#34;Athenea\u0026#34;, \u0026#34;Javier\u0026#34;, \u0026#34;Leonardo\u0026#34;, \u0026#34;Rocío\u0026#34; ] Como puedes ver en el ejemplo, en el momento de ordenar strings, atendiendo a su representación ASCII, funciona genial, pero ¿Y si queremos ordenar el siguiente array, que contiene objetos, basándonos en la edad de cada persona?\nlet people = [ { Nombre: \u0026#34;Leonardo\u0026#34;, Edad: 4 }, { Nombre: \u0026#34;Rocío\u0026#34;, Edad: 38 }, { Nombre: \u0026#34;Athenea\u0026#34;, Edad: 7 }, { Nombre: \u0026#34;Javier\u0026#34;, Edad: 40 } ]; console.log(people.sort()); \\* [ { Nombre: \u0026#34;Leonardo\u0026#34;, Edad: 4 }, { Nombre: \u0026#34;Rocío\u0026#34;, Edad: 38 }, { Nombre: \u0026#34;Athenea\u0026#34;, Edad: 7 }, { Nombre: \u0026#34;Javier\u0026#34;, Edad: 40 } ] */ Ahí nuestra función sort no está tan acertada, pero nos permite que le pasemos como parámetro una función que decidirá, en el momento de comparar dos elementos del array, cual es el orden correcto.\nlet people = [ { Nombre: \u0026#34;Leonardo\u0026#34;, Edad: 4 }, { Nombre: \u0026#34;Rocío\u0026#34;, Edad: 38 }, { Nombre: \u0026#34;Athenea\u0026#34;, Edad: 7 }, { Nombre: \u0026#34;Javier\u0026#34;, Edad: 40 } ]; console.log(people.sort((a, b) =\u0026gt; a.Edad - b.Edad)); \\* [ { Nombre: \u0026#34;Leonardo\u0026#34;, Edad: 4 }, { Nombre: \u0026#34;Athenea\u0026#34;, Edad: 7 }, { Nombre: \u0026#34;Rocío\u0026#34;, Edad: 38 }, { Nombre: \u0026#34;Javier\u0026#34;, Edad: 40 } ] */ ","id":60,"tag":"Programación funcional","title":"Inyección de funciones","url":"https://metrosetenta.es/blog/inyeccion-de-funciones/"},{"content":"Pues no, no se trata de un deporte de disco sobre hielo usando escobas, y tampoco es una práctica consistente en sazonar todas las comidas con la misma especia. En el cálculo lambda se usan funciones con un único parámetro. En posts venideros sobre conexión de funciones conoceremos el motivo, pero ahora centrémonos en aprender como superar esta limitación gracias al currying.\nEl amigo Haskell Curry, además del lenguaje Haskell desarrolló este concepto. ¿Cómo podríamos emular una función que suma tres número recibidos como parámetros, igual a la del ejemplo que sigue, usándo exclusivamente funciones con un único parámetro?\ntriSum = (x, y, z) =\u0026gt; x + y + z; triSum(1, 2, 3); //6 Pues la respuesta no parece muy complicada a simple vista:\ntriSum = x =\u0026gt; y =\u0026gt; z =\u0026gt; x + y + z: triSum(1)(2)(3); //6 Vamos a desglosarlo un poco para verlo más claro:\nlet funcFromStep1 = triSum(1); //y =\u0026gt; z =\u0026gt; 1 + y + z let funcFromStep2 = funcFromStep1(2); //z =\u0026gt; 1 + 2 + z let funcFromStep3 = funcFromStep2(3); //6 No se tú, pero yo me quedé embobado la primera vez que vi esto\u0026hellip;\n","id":61,"tag":"Programación funcional","title":"Currying","url":"https://metrosetenta.es/blog/currying/"},{"content":"Buscando un poco en la red, seguro que encuentras algún lugar donde se otorge al cálculo lambda el título de lenguaje de programación mas pequeño que existe. Básicamente se trata de un esquema para definir funciones y una regla de transformación simple mediante la sustitución de variables.\nUna función tiene un aspecto tal que así en cálculo lambda: λx.1+x. La variable entre el carácter λ y el punto es el parámetro de la función, y la expresión de esta es lo que sigue a dicho punto. Para aplicar esta función le facilitamos un argumento, por ejemplo 14, y lo podemos representar con el uso de paréntesis: (λx.1+x)(14). El resultado en este caso sería 15.\n","id":62,"tag":"Programación funcional","title":"Función lambda","url":"https://metrosetenta.es/blog/funcion-lambda/"},{"content":"Un polyfill es un script de código que sirve para emular una característica que un desarrollador necesita en un navegador cuando este no dispone de ella de forma nativa. En su mayoría, los polyfills están escritos en javascript, y nos permiten desarrollar apliaciones web centrados en nuevos estándares, pues suplen la carencia de los navegadores más antiguos en el momento de implementarlos.\nEl uso de polyfills invita a usar una detección de características del navegador, en lugar de comprobar su versión, puesto que con su uso únicamente habría que comprobar si el navegador, sea cual sea, y sea cual sea su versión, dispone de la cualidad que necesitamos en nuestro desarrollo, y de no ser así, usaríamos un polyfill que la emulara.\nEste pequeño polyfill que sigue comprueba si el motor javascript del navegador implementa la función forEach, y en el caso de no ser así, la define para que pueda ser usada en el resto del código, de modo que podremos usarla en todo nuestro desarrollo.\nif(Array.prototype.forEach === undefined) { Array.prototype.forEach = function(callback, element) { if(typeof(callback) !== \u0026#34;function\u0026#34;) { throw new TypeError(callback + \u0026#34; not function!\u0026#34;); } var len = this.length; for(var i = 0; i \u0026lt; len; i++) { callback.call(element, this[i], i, this) } } } Si necesitas una característica reciente, que no está disponible aún en todos los navegadores, un polyfill es una buena solución, pero antes de escribir uno propio, no dudes en buscar en alguna de las bibliotecas de polifylls que ya existen, como, por ejemplo, modernizr, que se centra en facilitar remedios de este tipo para el estandar HTML5.\n","id":63,"tag":"JavaScript","title":"Polyfills","url":"https://metrosetenta.es/blog/polyfills/"},{"content":"Explicado de un modo muy breve, consiste en que javascript, en el momento de compilar el código, prioriza las declaraciones de variables, siendo lo primero a tratar dentro de cada contexto. Es importante tener en cuenta que esto no aplica para las asignaciones, únicamente para la declaración. Estudia el siguiente script:\n/* * Logamos \u0026#39;undefined\u0026#39; por que la declaración de x ha sido alzada * por encima de esta función, pero no su asignación. Observa, * no obstante, que no recibimos un error de referencia a x a pesar * de que la línea dónde se declara y asigna está justo debajo. */ console.log(\u0026#34;x:\u0026#34;, x) var x = \u0026#34;Primera asignación\u0026#34;; //Ahora sí logamos \u0026#39;Primera asignación\u0026#39; console.log(\u0026#34;x:\u0026#34;, x) (function () { /* No logamos \u0026#39;Primera asignación\u0026#39; sino \u0026#39;undefined\u0026#39;, porque la * segunda declaración ha sido elevada al inicio de su contexto, * sobrescribiendo a la primera declaración y asignación. */ console.log(\u0026#34;x:\u0026#34;, x); var x = \u0026#34;Segunda asignación\u0026#34;; // Ahora sí, logamos \u0026#39;Segunda asignación\u0026#39; console.log(\u0026#34;x:\u0026#34;, x); }()); ","id":64,"tag":"Javascript ; Peculiaridades en lenguajes programación","title":"Hoisting de Javascript","url":"https://metrosetenta.es/blog/hoisting-de-javascript/"},{"content":"Con este post quiero inaugurar una sección donde tratar las peculiaridades de los distintos lenguajes de programación. Me refiero con la palabra peculiaridades a aquellos detalles que, en ocasiones, no se tienen presente cuando se está desarrollando, especialmente cuando se manejan distintos lenguajes en poco espacio de tiempo o cuando se comienza a desarrollar con un nuevo lenguaje que no se conoce en profundidad. Esto puede llevar a comportamientos extraños, o que no alcanzamos a comprender, en nuestra aplicación, y por tanto muy difíciles de resolver. Para comenzar, he elegido el hoisting de javascript.\n","id":65,"tag":"Javascript ; Peculiaridades en lenguajes programación","title":"Peculiaridades en los lenguajes de programación","url":"https://metrosetenta.es/blog/peculiaridades-en-los-lenguajes-de-programacion/"},{"content":"Javascript no fué creado como un lenguaje de programación funcional, pero dispone de ciertas características que nos permiten programar en un estilo funcional al usarlo. Te las listo con la intención de escribir un post sobre cada una de ellas y enlazarlo aquí abajo:\nLas funciones son objetos de primera clase Recursión Funciones flecha (Arrow functions) Clausuras (Closures) El operador spread ","id":66,"tag":"JavaScript ; Programación funcional","title":"Características funcionales de Javascript","url":"https://metrosetenta.es/blog/caracteristicas-funcionales-de-javascript/"},{"content":"La programación funcional es un modo distinto de escribir sofware que puede resultar difícil de aprender. La mayoría del software producido actualmente es una secuencia de órdenes ejecutadas de un modo determinado y, cuyo resultado, se obtiene creando y manipulando objetos. En la programación funcional (FP) el resultado se obtiene evaluando expresiones que están compuestas de funciones. Es habitual pasar funciones como parámetros de otras funciones, o devolverlas como resultados; Se opta por la recursión en lugar de hacer bucles, y en el cuerpo de las funciones se evita modificar objetos o el uso de variables globales, de tal manera que el uso de estas no conlleve efectos secundarios, habitualmente referidos en la literatura técnica como side effects.\nEs habitual asegurar que la programación funcional se enfoca en QUÉ debe ser realizado en lugar de CÓMO debe ser realizado.\n","id":67,"tag":"Programación funcional","title":"Entiende esto antes de estudiar programación funcional","url":"https://metrosetenta.es/blog/entiende-esto-antes-de-estudiar-programacion-funcional/"},{"content":"Indent Rainbow es una extensión de Visual Studio Code, de uso general, que sirve para darle color a las tabulaciones. Es muy útil para mejorar la legibilidad del código, especialmente para conocer en que ámbito te estás moviendo o donde comienzan y finalizan ciertos elementos del código.\nA continuación puedes ver el ajuste por defecto de la extensión, pero, como casi todo en Visual Studio Code, es algo configurable a tu gusto.\n\u0026#34;indentRainbow.colors\u0026#34;: [ \u0026#34;rgba(64,64,16,0.3)\u0026#34;, \u0026#34;rgba(32,64,32,0.3)\u0026#34;, \u0026#34;rgba(64,32,64,0.3)\u0026#34;, \u0026#34;rgba(16,48,48,0.3)\u0026#34;, \u0026#34;rgba(128,32,32,0.3)\u0026#34; ] ","id":68,"tag":"VSCode","title":"Tabulación coloreada en Visual Studio Code","url":"https://metrosetenta.es/blog/tabulaci%C3%B3n-coloreada-en-visual-studio-code/"},{"content":"Si escribes javascript seguro que en tu código hay una gran cantidad de paréntesis, llaves y corchetes. Con Bracket Pair Colorizer 2, una genial extensión de Visual Studio Code, dispondrás de la posibilidad de identificarlos rápidamente mediante colores, y tiene un buen número de elementos configurables, como una línea vertical que delimita el ámbito de estos elementos. Es una extensión muy recomendable, así que, ya estás tardando en probarla.\nMi configuración en Visual Studio Code para esta extensión en el momento de escribir este post:\n\u0026#34;bracket-pair-colorizer-2.scopeLineRelativePosition\u0026#34;: false, \u0026#34;bracket-pair-colorizer-2.showBracketsInGutter\u0026#34;: true, \u0026#34;bracket-pair-colorizer-2.showHorizontalScopeLine\u0026#34;: false, \u0026#34;editor.matchBrackets\u0026#34;: false, \u0026#34;bracket-pair-colorizer-2.highlightActiveScope\u0026#34;: true, \u0026#34;bracket-pair-colorizer-2.activeScopeCSS\u0026#34;: [ \u0026#34;borderStyle : solid\u0026#34;, \u0026#34;borderWidth : 1px\u0026#34;, \u0026#34;borderColor : {color}; opacity: 0.5\u0026#34;, \u0026#34;backgroundColor: {color}\u0026#34; ], \u0026#34;bracket-pair-colorizer-2.scopeLineCSS\u0026#34;: [ \u0026#34;borderStyle : solid\u0026#34;, \u0026#34;borderWidth : 2px\u0026#34;, \u0026#34;borderColor : {color}; opacity: 0.6\u0026#34; ], \u0026#34;bracket-pair-colorizer-2.showBracketsInRuler\u0026#34;: true ","id":69,"tag":"VSCode","title":"¿Dónde diablos cerraba este paréntesis?","url":"https://metrosetenta.es/blog/donde-diablos-cerraba-este-parentesis/"},{"content":"If you think you are worth what you know, you are very wrong. Your knowledge today does not have much value beyond a couple of years. Your value is what you can learn and how can you easily adapt to the changes this profession brings so often.\nSi crees que vales lo que sabes, estás muy equivocado. Tu conocimiento no tiene mucho valor más allá de un par de años. Tu valor es lo que puedes aprender y cómo puedes adaptarte fácilmente a los cambios que esta profesión trae con tanta frecuencia.\n- Jose M. Aguilar\n","id":70,"tag":"","title":"El verdadero valor de un desarrollador","url":"https://metrosetenta.es/blog/el-verdadero-valor-de-un-desarrollador/"},{"content":"Es un fallo habitual, en el manejo de errores dentro de Go, realizar comparasiones de strings contra el mensaje del error que quieres reconocer, pero lo cierto es que, el modo más acertado de discernir que error estas manejando, es hacer una comparación de tipos de error dentro de una sentencia case.\n¿Quiero decir entonces que puedo gestionar distintos tipos de error? Claro que sí. Fíjate que, en Go, todo lo que inplemente la interface error es un error. Además, puedes comprobar por tí mismo que es una interface muy sencilla:\ntype error interface { Error() string } Para darte un ejemplo voy a definir un struct, ErrPizzaIsOver, el va a contener un string llamado message:\ntype ErrPizzaIsOver struct { message string } Para que este struct pueda ser usado como error debe implementar la interface que te mostré más arriba, así que voy a implementarla:\nfunc (e *ErrPizzaIsOver) Error() string { return e.message } Por último, voy a crear una función que, recibiendo como parámetro un string, me devuelva un error del tipo ErrPizzaIsOver, y configurado con dicho string como message.\nfunc NewErrPizzaIsOver(message string) *ErrPizzaIsOver { return \u0026amp;ErrPizzaIsOver{ message: message, } } Todo listo, es el momento de hacer uso de nuestro nuevo tipo de error, así que vamos a ver como quedaría todo. Observa que la magia se hace con el patrón switch err.(type).\npackage main import ( \u0026#34;fmt\u0026#34; \u0026#34;os\u0026#34; \u0026#34;strconv\u0026#34; ) type pizza struct { numberOfPieces int } type ErrPizzaIsOver struct { message string } func (e *ErrPizzaIsOver) Error() string { return e.message } func NewErrPizzaIsOver(message string) *ErrPizzaIsOver { return \u0026amp;ErrPizzaIsOver{ message: message, } } func (p *pizza) eatAPiece() error { if !(p.numberOfPieces \u0026gt; 0) { return NewErrPizzaIsOver(\u0026#34;There are no more pieces of pizza\u0026#34;) } else { p.numberOfPieces-- fmt.Println(\u0026#34;Ñam, ñam...\u0026#34;) return nil } } func main() { myPizza := \u0026amp;pizza{8} fmt.Println(\u0026#34;There are \u0026#34; + strconv.FormatUint(uint64(myPizza.numberOfPieces), 10) + \u0026#34; pieces of pizza\u0026#34;) for { err := myPizza.eatAPiece() if err != nil { switch err.(type) { case *ErrPizzaIsOver: fmt.Println(err.Error()) os.Exit(0) default: fmt.Println(\u0026#34;What the f**k just happened?\u0026#34;) } } fmt.Println(\u0026#34;Now there are \u0026#34; + strconv.FormatUint(uint64(myPizza.numberOfPieces), 10) + \u0026#34; pieces of pizza\u0026#34;) } } ","id":71,"tag":"Go ; Bug","title":"Comparación directa de errores en Go","url":"https://metrosetenta.es/blog/comparacion-directa-de-errores-en-go/"},{"content":"Es un fallo habitual, en el manejo de errores dentro de Go, realizar comparasiones de strings contra el mensaje del error que quieres reconocer, pero lo cierto es que, el modo más acertado de discernir que error estas manejando, es hacer una comparación de tipos de error dentro de una sentencia case.\n¿Quiero decir entonces que puedo gestionar distintos tipos de error? Claro que sí. Fíjate que, en Go, todo lo que inplemente la interface error es un error. Además, puedes comprobar por tí mismo que es una interface muy sencilla:\ntype error interface { Error() string } Para darte un ejemplo voy a definir un struct, ErrPizzaIsOver, el va a contener un string llamado message:\ntype ErrPizzaIsOver struct { message string } Para que este struct pueda ser usado como error debe implementar la interface que te mostré más arriba, así que voy a implementarla:\nfunc (e *ErrPizzaIsOver) Error() string { return e.message } Por último, voy a crear una función que, recibiendo como parámetro un string, me devuelva un error del tipo ErrPizzaIsOver, y configurado con dicho string como message.\nfunc NewErrPizzaIsOver(message string) *ErrPizzaIsOver { return \u0026amp;ErrPizzaIsOver{ message: message, } } Todo listo, es el momento de hacer uso de nuestro nuevo tipo de error, así que vamos a ver como quedaría todo. Observa que la magia se hace con el patrón switch err.(type).\npackage main import ( \u0026#34;fmt\u0026#34; \u0026#34;os\u0026#34; \u0026#34;strconv\u0026#34; ) type pizza struct { numberOfPieces int } type ErrPizzaIsOver struct { message string } func (e *ErrPizzaIsOver) Error() string { return e.message } func NewErrPizzaIsOver(message string) *ErrPizzaIsOver { return \u0026amp;ErrPizzaIsOver{ message: message, } } func (p *pizza) eatAPiece() error { if !(p.numberOfPieces \u0026gt; 0) { return NewErrPizzaIsOver(\u0026#34;There are no more pieces of pizza\u0026#34;) } else { p.numberOfPieces-- fmt.Println(\u0026#34;Ñam, ñam...\u0026#34;) return nil } } func main() { myPizza := \u0026amp;pizza{8} fmt.Println(\u0026#34;There are \u0026#34; + strconv.FormatUint(uint64(myPizza.numberOfPieces), 10) + \u0026#34; pieces of pizza\u0026#34;) for { err := myPizza.eatAPiece() if err != nil { switch err.(type) { case *ErrPizzaIsOver: fmt.Println(err.Error()) os.Exit(0) default: fmt.Println(\u0026#34;What the * just happened?\u0026#34;) } } fmt.Println(\u0026#34;Now there are \u0026#34; + strconv.FormatUint(uint64(myPizza.numberOfPieces), 10) + \u0026#34; pieces of pizza\u0026#34;) } } ","id":72,"tag":"Go ; Bug","title":"Comprobación de tipo de error en Go","url":"https://metrosetenta.es/blog/comprobacion-de-tipo-de-error-en-go/"},{"content":"Los canales son la característica que Go nos facilita para comunicar entre sí goroutines y poder sincronizar su ejecución.\nvar c chan string = make(chan string) El tipo canal se representa con la palabra chan y, a continuación, el tipo de los datos que viajaran a través de dicho canal. En el ejemplo de arriba he declarado la variable c, que contendrá un canal para transferir datos de tipo string. En la misma línea de código he usado make para crear dicho canal que, como puedes observar, se asigna a la variable c.\nPara enviar o recibir datos por el canal has de usar el signo \u0026lt;- justo delante o detrás del canal de la manera que sigue.\nc \u0026lt;- \u0026#34;Enviando por el canal\u0026#34; var mensaje := \u0026lt;- c Esta operación es síncrona, por tanto, el emisor esperará hasta que el receptor está preparado para recibir el envio. Si usas un canal con buffer, la operación será asíncrona, y por tanto, éste bloqueo sólo tendrá lugar cuando el buffer esté lleno.\nc := make(chan int, 1) ","id":73,"tag":"Go","title":"Canales en Go","url":"https://metrosetenta.es/blog/canales-en-go/"},{"content":"Go incluye un programa llamado go test que te será de gran utilidad para poner a prueba funciones de tu código. Esto es realmente útil para asegurarte de que todo funciona como debería hacerlo después de añadir características o de realizar cambios importantes en tu desarrollo. Para poder fabricar un ejemplo con el uso de go test, supongamos que has escrito un archivo llamado math.go, y que dicho archivo contiene una función que sirve para calcular el promedio de un conjunto de números:\npackage math func Average(numbers []float64) float64 { total := float64(0) for _, x := range numbers { total += x } return total float64(len(numbers)) Para preparar pruebas para esta función, sólo tienes que escribir un archivo con el mismo nombre que el archivo que contiene la función a probar, pero en lugar de finalizar en .go lo hará en _test.go. El compilador de Go ignora los archivos que finalizan de este modo cuando usas go install o go build. Como queremos fabricar pruebas para la función Average, en nuestro nuevo archivo vamos a crear una función llamada TestAverage. La función probadora debe empezar con la palabra Test para que go test la ejecute. Te muestro el código que habría en math_test.go y te sigo explicando\u0026hellip;\npackage math import \u0026#34;testing\u0026#34; func TestAverage(t *testing.T) { result := Average([]float64{2,4}) if result != 3 { t.Error(\u0026#34;Expected 3, got \u0026#34;, result) } } Después de definir el paquete, que es el mismo que el del archivo que contiene la función que estamos probando, has de importa el paquete testing, porque las funciones probadoras usan el tipo *testing.T como parámetro. Dentro de la función probadora, TestAverage, tienes que usar la función que va a ser probada, que en este caso es la función Average. La idea es sencilla, se trata de que le pases a la función Average unos parámetros que generen unos valores de salida que conozcas de antemano, y así podrás comparar los valores devueltos por la función que estás probando con los que tú ya sabes que debería devolver. En el ejemplo se pasan los valores 2 y 4, cuyo resultado previsto, su promedio, es 3. En el caso de que la función Average no devolviera 3 se usa t.Error, que es similar a fmt.Println, con la finalidad de indicarle al programa go test que se ha detectado un error.\nTodo listo, ahora sólo te resta ejecutar go test, el cual te debería mostrar un resultado similar al que sigue.\n$ go test PASS ok goWorkspace/src/Repository/Project/math 0.029s ","id":74,"tag":"Go ; Testing","title":"Go testing","url":"https://metrosetenta.es/blog/go-testing/"},{"content":"Ya has visto como configurar componentes con props en React, pero ¿cómo puedes definir comportamientos o interacciones con dichos componentes? Para ello necesitas que los componentes puedan definir su estado, y con las props es imposible, pues no pueden ser modificadas por el componente, sólo por su componente padre. Para esto existe this.state, donde los componentes pueden disponer de datos privados modificables a traves de la función this.setState().\nYa sabes que función usar para ajustar this.state, pero ¿Cómo podrías definir un estado inicial del componente? Bien, pues para eso disponemos del constructor de clase. En la función render comprobamos el estado del componente para decidir como va a ser mostrado, y ahora viene la magia: cuando modificamos el estado de un componente, automáticamente se volverán a renderizar todos sus componentes hijos y el propio componente. Esto, además, es bastante ágil gracias al DOM virtual de React.\nclass Dashboard extends Component { constructor() { super(...arguments); this.state = { showAdvancedFeatures: false } } render(){ let advancedFeatures; if(this.state.showAdvancedFeatures){ advancedFeatures = ( \u0026lt;AvancedFetaures/\u0026gt; ) } return ( \u0026lt;div className=\u0026#34;dashboard\u0026#34;\u0026gt; \u0026lt;BasicFeatures/\u0026gt; {advancedFeatures} \u0026lt;/div\u0026gt; ); } } ","id":75,"tag":"React","title":"State en React","url":"https://metrosetenta.es/blog/state-en-react/"},{"content":"React es una biblioteca de JavaScript que se basa en la fabricación y combinación de componentes para construir interfaces de usuario. Cada componente se define por separado en un archivo javascript, y tiene un aspecto similar a este que sigue, el cual se encontraría en el archivo listaCompra.js:\nimport React, { Component } from \u0026#39;react\u0026#39;; import Articulo from \u0026#39;./Articulo\u0026#39;; class ListaCompra extends Component { render() { return ( \u0026lt;ul\u0026gt; \u0026lt;Articulo cantidad=\u0026#34;1\u0026#34;\u0026gt;Pan\u0026lt;/Articulo\u0026gt; \u0026lt;Articulo cantidad=\u0026#34;6\u0026#34;\u0026gt;Leche\u0026lt;/Articulo\u0026gt; \u0026lt;Articulo cantidad=\u0026#34;2\u0026#34;\u0026gt;Huevos\u0026lt;/Articulo\u0026gt; \u0026lt;/ul\u0026gt; ); } } Las propiedades, que veremos en el código escritas como props, se usan para configurar componentes, y son pasadas desde los componentes padres a los componentes hijos. Es importante recordar que el componente hijo no puede modificarlas, el propietario es el componente padre.\nEn el ejemplo anterior, el componente ListaCompra usa otro componente que aún no hemos escrito, el componente Articulo. En el JSX que devuelve su método render las props son pasadas al componente hijo como etiquetas de atributos similares a las de HTML. En nuestro caso se está pasando la propiedad cantidad. El contenido entre las etiquetas de apertura y cierre también se puede usar como propiedad del componente hijo. En ListaCompra se trata del nombre del artículo.\nimport React, { Component } from \u0026#39;react\u0026#39;; class Articulo extends Component { render() { return ( \u0026lt;li\u0026gt; {this.props.cantidad} × {this.props.children} \u0026lt;/li\u0026gt; ); } } ","id":76,"tag":"React","title":"Props en React","url":"https://metrosetenta.es/blog/props-en-react/"},{"content":"Otro recurso importante que vas a necesitar en Vim es un buscador de textos. Ante el hecho de que el proyecto que permitía el uso de El surfero de plata en vim, ag.vim, ha quedado obsoleto, te podrías decantar por ack.vim. Con ack.vim puedes hacer uso de ack, que no es ni más ni menos que un grep optimizado para programadores.\nInstalar ack es bastante sencillo en distribuciones Linux deribadas de Debian.\n$ sudo apt-get install ack-grep Si eres usuario de Debian la pega es que, como el paquete ack ya existe, ack es empaquetado como ack-grep. Esto supone teclear más al usar el comando en consola, pero lo puedes solucionar usando las desviaciones de la siguiente manera:\n$ sudo dpkg-divert --local --divert /usr/bin/ack --rename --add /usr/bin/ack-grep Listo, ya dispones de la herramienta ack. Ahora, para poder usarla en tu editor Vim, sólo añádela como un Plugin de un modo similar a como hicíste con fzf aquí.\n\u0026#34; ¡Cualquier URL de git es admitida por vim-plug! Plug \u0026#39;https://github.com/mileszs/ack.vim\u0026#39; Luego en Vim, ejecuata el comando PlugInstall ack.vim. Está bien familiarizarse con los comandos de vim-plug, así que échales un vistazo aquí.\n¿Cómo se usa ack en Vim? Sencillo\u0026hellip;\n:Ack [options] {pattern} [{directories}] Y aquí están los atajos disponibles con esta herramienta.\n","id":77,"tag":"Vim","title":"Buscador de texto en Vim","url":"https://metrosetenta.es/blog/buscador-de-texto-en-vim/"},{"content":"fzf se define a sí mismo como un buscador difuso de línea de comandos para propósitos generales. Más detalladamente, se trata de un filtro para líneas de comandos Unix, que puedes aplicar a listas, archivos, procesos, históricos de comandos, etcétera.\nLo puedes instalar en tu carpeta home clonando su repositorio en GitHub de la siguiente manera:\n$ git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf Luego sólo tienes que ejecutar el script de instalación:\n$ ~/.fzf/install Puedes probar este potente filtro en emulador de terminal accediendo a un directorio que contenga varios archivos y ejecutando el comando fzf. Luego prueba a introducir criterios de búsqueda y obseva como fzf los aplica a los nombre de los archivos, de un modo interactivo, para ofrecerte aquellos que contienen coincidencias con el texto que estás facilitando.\nAhora viene lo mejor, y es que fzf puede ser usado como un conectable de Vim. Si usas el gestor de conectables vim-plug, que aprendimos a instalar aquí, es muy sencillo preparar nuestro buscador de archivos, sólo habría que añadir las siguiente línea a los ajustes de vim-plug en el archivo de configuración de Vim:\nPlug \u0026#39;junegunn/fzf\u0026#39;, { \u0026#39;dir\u0026#39;: \u0026#39;~/.fzf\u0026#39;, \u0026#39;do\u0026#39;: \u0026#39;./install --all\u0026#39; } Una vez que abras Vim dispondrás del comando FZF en él, pero para ejecutarlo de un modo mucho más rápido puedes asignarle una combinación de teclas, por ejemplo Ctrl+p, en el archivo mismo archivo de configuración.\nnnoremap \u0026lt;c-p\u0026gt; :FZF \u0026lt;cr\u0026gt; ","id":78,"tag":"Vim","title":"Búsqueda de archivos en vim","url":"https://metrosetenta.es/blog/busqueda-de-archivos-en-vim/"},{"content":"vim-plug es un gestor de paquetes para Vim con características muy interesantes. Lo tienes disponible aquí, donde puedes encontrar toda la información necesaria para usarlo. Su instalación en sistemas Unix se puede realizar con un sencilo comando:\n$ curl -fLo ~/.local/share/nvim/site/autoload/plug.vim --create-dirs \\\\ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim Una vez instalado sólo tienes que ajustarlo en el archivo de configuración de Vim. Aqui abajo tienes un ejemplo con alguna información:\n\u0026#34; Inicia la configuración usando el comando call plug#begin(), \u0026#34; con el cual puedes especificar el directorio donde se colocarán \u0026#34; los conectables que queremos usar en nuestro editor. \u0026#34; En el caso concreto de Vim puedes usarlo así. call plug#begin(\u0026#39;~/.vim/plugged\u0026#39;) \u0026#34; A continuación se solicitarán los conectables necesarios. Hay muchos \u0026#34; modos de hacerlo, por ejemplo, usando una dirección URL de Github. Plug \u0026#39;https://github.com/junegunn/vim-github-dashboard.git\u0026#39; \u0026#34; Finalmente cierra el archivo de configuración con el \u0026#34; comando call plug#end(). call plug#end() Para probarlo abre Vim y ejecuta el comando PlugInstall. Verás un panel lateral donde se iniciará la instalación de los conectables indicados en el archivo de configuración de Vim.\n","id":79,"tag":"Vim","title":"Cómo instalar vim-plug para Vim","url":"https://metrosetenta.es/blog/como-instalar-vim-plug-para-vim/"},{"content":"Estoy convencido de que tienes un estilo personal para organizar tu código, pero cuando trabajas con Go, es conveniente que te adaptes al estilo de su wokspace. El workspace de Go es una carpeta que se compone, a su vez, de otras tres carpetas: bin, pkg y src. Mi workspace, o espacio de trabajo, para los proyectos escritos en Go es ~/Documents/projects/go, por tanto, ahí creé la carpeta src, en la cual guardo los distintos trabajos escritos en este lenguaje.\n... ~/Documents/projects/go/source/project1 ~/Documents/projects/go/source/project2 ... Cuando elijas cual será tu workspace es fundamental que configures Go para que conozca cual es su ubicación. Para esto, únicamente tienes que apuntar la variable de entorno $GOPATH a dicha dirección. En mi caso:\n$ export GOPATH=$HOME/Documents/projects/go En el workspace habrá una carpeta que contenga binarios, así que no olvides añadirla a tu $PATH:\n$ export PATH=$PATH:$GOPATH/bin Por último, es recomendable que las añadas al archivo de configuración de tu terminal para, de este modo, no tener que definirlas repetidamente al iniciarlo.\n","id":80,"tag":"Go","title":"El workspace de Go","url":"https://metrosetenta.es/blog/el-workspace-de-go/"},{"content":"En entradas anteriores te comenté el origen de los errores de software y realicé una pequeña y divertida clasificación. Hoy sigo con la temática bichos para recomendarte una aproximación interesante al modo de gestionar aquellos errores que, en ocasiones, puedan aparecer en tu código. Hay cuatro preguntas fundamentales que deberías hacerte a ti mismo para definir tu estrategia en lo referente a la gestión de cada casuística de error en tu desarrollo:\n1. ¿Voy a mostrar estos errores? Si bien es cierto que en un entorno de desarrollo esto es más que necesario hacerlo, en producción, el hecho de mostrar los errores de nuestra aplicación con toda la información que pueden facilitar es, cuando menos, una invitación a hackearla. Añade a esto que tu desarrollo parecerá mal diseñado y poco profesional a ojos de los usuarios y clientes. Es fundamental, por tanto, que puedas manejar la visibilidad de las notificaciones de error de tu aplicación según el entorno en el que se esté ejecutando, y que nunca se muestren en producción.\n2. ¿Voy a registrar estos errores? Anotar las notificaciones de error en un registro donde poder consultarlas más tarde es un modo excepcional para rastrear posteriormente sus causas. También disponemos de la posibilidad de, por ejemplo mediante syslog, realizar esta gestión a través del sistema operativo.\n3. ¿Voy a ignorar estos errores? Pueden darse errores que no resulten críticos para tu aplicación, como puede ser el intento de lectura de un archivo de configuración inexistente. En este caso, la función de lectura podría lanzar un error crítico que detuviera la ejecución de tu aplicación, sin que el usuario haya recibido ningún tipo de información sobre dicha interrupción. En este caso puede ser interesante ignorar el error para preservar la ejecución.\n4. ¿Voy a actuar frente a estos errores? Seguimos con el caso anterior. Al ignorar el error has evitado un cierre inesperado de la aplicación. Con el fin de facilitar un poco más de información a tu usuario, una vez echo esto, hay que comprobar si disponemos del archivo y podemos hacer uso de él. En el caso que comentamos, no es así, pero ahora podemos informar al usuario de que no ha sido posible disponer del archivo de configuración, informar de posibles causas y soluciones y, a continuación, cerrar nosotros mismos la aplicación de un modo elegante.\nLa combinación de respuestas frente a estas cuatro preguntas te ayudarán a determinar, de un modo sencillo, tu estrategia de gestión para cada casuística de error.\n","id":81,"tag":"Bug","title":"Cuentos de bichos: Estrategia de gestión de errores","url":"https://metrosetenta.es/blog/cuentos-de-bichos-estrategia-de-gestion-de-errores/"},{"content":"Heisenbug Fisonomía Toma su nombre del físico especializado en mecánica cuántica Werner Heisenberg, quien dedujo que el mero hecho de observar un sistema de una manera determinada altera el estado de éste. Cuando se usan herramientas durante el proceso de depuración para localizar y eliminar bichos, se producen pequeñas diferencias respecto al entorno de producción, es decir, con respecto al entorno final en el cual deberá funcionar nuestro dispositivo de software. El Heisenbug es especialista en aprovechar cualquiera de estas leves diferencias para mostrar comportamientos distintos que confundan al programador o para simplemente desaparecer.\nHabilidad principal Su principal fortaleza consiste en la capacidad de mutar o desaparecer cuando se siente amenazado por un depurador.\nCapacidad de destrucción Es especialmente destructivo con respecto a los compromisos de entrega de software, pues puede elevar muchísimo los tiempos de depuración. Se conocen casos de programadores que, víctimas de la desesperación, han propuesto depurar en el entorno de producción para localizar y destruir a este esquivo bicho.\nBohrbug Fisonomía Debe su nombre al modelo atómico que desarrolló el físico Danés Niels Bohr para explicar, entre otros hechos, la estabilidad de la materia. El Bohrbug puede atormentar amargamente al cerebro lógico de un desarrollador, pues tan lógico seso no comprenderá como dicho bug sigue mostrándose una y otra vez, impasible, ante las innumerables correcciones realizadas en el código con el ánimo de destruirlo.\nHabilidad principal Es conocido por su capacidad de permanecer inalterable ante cualquier acción de depuración.\nCapacidad de destrucción Como suele presentarse en etapas tempranas, y se detecta con facilidad en pruebas y depuraciones, a lo que ataca principalmente es al orgullo y a la paciencia de los programadores.\nMandelbug Fisonomía El conjunto fractal descubierto por Benoit Mandelbrot, un monstruo matemático de gran complejidad, inspiró el nombre de este bicho. Su modo de operar consiste en cimentar su existencia en causas tan complejas que sea difícil comprenderlas y atacarlas. Debido a esto, su comportamiento parece caótico, pues tras cada solución aplicada en el código, únicamente se conseguirá que el bicho actúe de un modo distinto, pero no quedará eliminado.\nHabilidad principal Es capaz de formarse a sí mismo a partir de una combinación de pequeños detalles en muchísimas porciones de código aparentemente inconexas. Dar con la combinación que lo sustenta puede llegar a ser una ardua tarea de ingeniería inversa.\nCapacidad de destrucción No es un bicho que se muestre en las últimas fases del desarrollo, así que se detecta a tiempo para depurarlo, pero es ahí donde radica su máximo poder. Destruir un Mandelbug puede ocasionar que se deba corregir muchas porciones de código, creando otros tipos de bugs distintos y alterando la arquitectura y la lógica de la aplicación. Puede, por tanto, herir gravemente e incluso malograr un proyecto a la mitad de su desarrollo.\nSchroedinbug Fisonomía Schrödinger describió una paradoja según la cual, teniendo un gato en una caja, no podemos saber si está vivo o muerto hasta abrir dicha caja, y por lo tanto se considera que se encuentra vivo y muerto a la vez hasta que la abramos. Esta paradoja aplica a la perfección a los Schrodinbugs, pues dichos bichos no se manifiestan hasta que alguien, leyendo el código o usando el programa de un modo poco habitual, descubre que nunca debería haber funcionado. ¡Desde ese momento, la caja queda abierta, y en el programa se muestra una y otra vez el bug que parecía no haber existido nunca!\nHabilidad principal Su capacidad de permanecer invisible el mayor tiempo posible y su omnipresencia una vez determinada la certeza de sus existencia.\nCapacidad de destrucción Depende de la parte que ataque de nuestra aplicación, pero el principal peligro que acarrea este tipo de bichos es la dificultad de una detección prematura, lo cual lo hace muy peligroso.\nStotle Fisonomía Es más que un simple bicho, es la idea de bicho atormentando la mente de un desarrollador que ha sido engañado, confundido. Se trata de introducir, sin ser conscientes, datos incorrectos en la entrada del programa. Al percibir que la salida no es correcta, y estando convencidos de que la entrada si lo era, comenzamos a buscar un bicho que no existe, y que ocupará durante un buen rato nuestro tiempo y nuestra mente. Es como si teclearas en una calculadora la multiplicación de dos por tres, cuando realmente quisiste teclear la suma de estos números. Al ver el resultado de seis en lugar de cinco dudarás del correcto funcionamiento del artilugio, e intentarás arreglar algo que no estaba roto. Su nombre deriva de Aristóteles (Aristotle) porque del mismo modo que Aristóteles no era cuestionado antiguamente, y se asumía que debía estar en lo cierto, el programador no cuestiona la entrada de datos, asumiendo que hay un bicho en el programa.\nHabilidad principal Hacer creer a los programadores que existe.\nCapacidad de destrucción Dado que no es más que una idea de bug, no existe, no es peligroso para el proyecto en sí. No obstante, puede desquiciar a algún desarrollador.\nBugs de fase lunar Fisonomía Son aquellos bichos que se muestran por los motivos más aleatorios o esotéricos que se puedan imaginar. Son fallos en el programa que únicamente suceden cuando la lluvia cae sobre los cristales de las ventanas de la oficina, cuando la chica rubia de recursos humanos pasa por delante de la puerta del despacho donde trabaja el equipo de desarrollo, cuando el aire acondicionado está a veinticuatro grados\u0026hellip;\nHabilidad principal No pertenecen al mundo lógico y racional del desarrollo de software.\nCapacidad de destrucción Mientras no exista dentro del endémico grupo de probadores o depuradores una especialización en exorcismos de dispositivos de software, o algo similar, estos bichos harán estragos allá donde quieran pulular.\nFantasmas en el código Fisonomía Estos bichitos suelen ocultarse en rutinas o subprogramas que se usan en raras ocasiones y, a diferencia del Schroedinbug, no es necesario detectarlos para que se materialicen. Son muy difíciles de descubrir en las fases de desarrollo o pruebas.\nHabilidad principal Se mostrarán motu proprio en el peor momento posible, ya sea cuando estemos presentando el proyecto finalizado a nuestro cliente o cuando lo hayamos puesto en producción.\nCapacidad de destrucción Debido a su habilidad para ocultarse y aparecerse en el momento más inconveniente, pueden herir principalmente la imagen del equipo de desarrollo.\n","id":82,"tag":"Bug","title":"Cuentos de bichos: Bestiario","url":"https://metrosetenta.es/blog/cuentos-de-bichos-bestiario/"},{"content":" La polilla, una de esas pequeñas mariposas nocturnas que se sienten atraídas por la luz y cuya larva destruye la materia donde anida, es un lepidóptero. En fin, que es un bicho. En telegrafía, y en las primeras compañías telefónicas, era habitual usar la expresión \u0026ldquo;bichos en el cable de teléfono\u0026rdquo; para referirse al ruido y las interferencias en la comunicación. Si bien es cierto que la palabra inglesa «bug» ya fue usada para indicar un defecto industrial, y que el mismísimo Thomas Edison dispuso de ella con esta finalidad, es probable que fuera Grace Murray Hopper quien la aplicó por vez primera al ámbito de la informática. Ésta licenciada en física trabajaba como programadora en el Mark II, uno de esos primeros ordenadores que estaba formado por componentes electrónicos y electromecánicos, cuando investigando la causa de un fallo en el mastodóntico computador de IBM, halló una polilla bloqueando el relé 70 del panel F. El hecho se documentó de modo metódico, y el insecto quedó inmortalizado en una foto junto a un texto que rezaba \u0026ldquo;primera vez que se encuentra (en un ordenador) un «bug» de verdad\u0026rdquo;. Así comenzó la leyenda del primer bug informático conocido.\nEn la historia del sofware han sido muchos, y de muy diversa índole, los bichos que han querido alcanzar la fama que ostenta en el mundo de la ingeniería informática la polilla del relé 70. Los bichos han procurado realizar incursiones en los desarrollos de software desde la primera línea escrita de código, no discriminan ninguna posibilidad. Procuran infectar todo tipo de proyectos, tanto aquellos en los cuales apenas tienen el potencial de provocar pequeños inconvenientes, como eso proyectos susceptibles de costar tres billones de dolares a una empresa de automoción; o como aquel caso, en el que uno de esos malévolos bichos pudo haber desencadenado la tercera guerra mundial: En 1983 el sistema de alerta temprana de la Unión Soviética había detectado el lanzamiento de cinco misiles balísticos, el «bug» que se había colado dentro de aquel sistema hizo que éste confundiera el reflejo del sol sobre unas nubes con unos amenazantes proyectiles. El oficial soviético que se encontraba al mando en ese momento dedujo fríamente que, siendo real el ataque, el número de venablos a cohete superaría cinco con creces. De no ser por su acertada decisión de no reaccionar ante la señal de alerta, el ficticio ataque habría recibido una represalia difícil de explicar a la comunidad internacional.\nPara realizar estas correrías los «bugs» aprovechan cualquier resquicio: falta de conocimientos, poca experiencia, descuidos, momentos de baja concentración\u0026hellip; Si bien es cierto que hay quien define que la expresión \u0026ldquo;sofware libre de «bugs»\u0026rdquo; es un oxímoron, y que desarrollar sin cometer ningún error que les abra la puerta a estos pequeños enemigos es utópico, hay métodos para combatirlos y reducir su presencia lo máximo posible. Llegados a este punto, es obligatorio nombrar a aquellos que defienden el uso de la programación funcional como modo de evitar los estados mutables (especialmente cuando el proyecto tiende a una explosión combinatoria), reduciendo drásticamente la presencia de «bugs», pero lo que realmente viene a la cabeza al pensar en un modo de desarrollar evitando bugs son los modelos de desarrollo. Uno de los primeros modelos que se nombra cuando se toca este tema es el desarrollo guiado por pruebas (TDD por sus siglas en inglés), en el cual se describen las pruebas de que el código funciona sin errores antes que el propio código. Las técnicas y principios del TDD fueron combinadas posteriormente con los análisis y diseños propios de la programación orientación a objetos (OOP) y el diseño guiado por dominios (DDD) para dar lugar al desarrollo guiado por comportamientos (BDD), el cual es, con casi toda seguridad, el más extremo y completo método de desarrollo de software en lo que a evitar «bugs» se refiere. Este modelo de desarrollo exige un fuerte apoyo en herramientas como, por ejemplo, Cucumber, lo cual puede conllevar un gasto económico extra que, sumado al inevitable aumento del tiempo de desarrollo, hace pensar que no es apto para todos los proyectos.\nAunque hay proyectos que exigen un aumento del nivel de atención a la gestión de posibles «bugs», éste siempre debe ser, por defecto, lo más elevado posible. A modo de símil, es obvio que no es necesario el mismo nivel de asepsia en el entorno en el se cura una rozadura que en el que se opera a corazón abierto; no obstante, en el caso más laxo de los dos, es indiscutible que también se toman unas precauciones mínimas de higiene. No es necesario usar el mismo modelo de desarrollo para añadir un módulo personalizado a un blog en Worpress y para poner en funcionamiento la transitada tienda web de una empresa de ropa deportiva, la cual conlleva un elevado número de transacciones económicas y no es un proyecto tan inocuo como el primero, pero el nivel mínimo de prevención de «bugs», desde el cual partiremos en ambos casos, ha de ser suficientemente elevado; el error imperdonable, y que nunca se ha de cometer, es rebajar nuestra cota de intolerancia a los «bugs» en pos de la productividad. Una buena conclusión a todo lo expuesto sería la que sigue: En el momento de iniciar un proyecto debemos determinar cuanto es necesario aumentar nuestro estándar de intransigencia a los «bugs» para evitar mariposas en el código.\n","id":83,"tag":"Bug","title":"Cuentos de bichos: Mariposas en el código","url":"https://metrosetenta.es/blog/cuentos-de-bichos-mariposas-en-el-codigo/"},{"content":"En su libro “Advanced PHP programming”, George Schlossnagle hace la siguiente afirmación:\nEn mi empresa, el código producido para los clientes no se considera completo hasta que toda su interfaz externa de programación de la aplicación (API) y cualquier idiosincrasia interna están totalmente documentadas.\nEsta declaración de Schlossnagle es una buena señal de lo importante que puede llegar a ser la gestión de la documentación del código fuente dentro de un proyecto de desarrollo de software.\nAntes de proseguir, habría que discernir entre la documentación del proyecto y la documentación del código.\nLa primera puede contener requerimientos, casos de uso, diagramas y otros tipos de documentos cuya finalidad es definir el producto que se desea obtener y el modo de hacerlo. Sin embargo, la documentación del código, que es la que se trata en este breve texto, forma parte del producto final como se puede deducir de la frase de Schlossnagle.\nAdemás, este mismo autor divide la documentación del código en dos tipos: Los comentarios que los desarrolladores escriben junto a sus líneas de código explicando cómo funciona y los documentos donde se detalla que es lo que hace nuestro código. Haciendo un símil con la documentación de un aparato electrónico, el primer tipo descrito representaría el manual de reparaciones para los empleados del soporte técnico o datasheet, y el segundo tipo coincidiría con las instrucciones de uso para el usuario.\nUn ingeniero en Electrónica, con toda seguridad, es capaz de desarticular un aparato electrónico y, descifrando el modo en el que se ha diseñado que sus componentes interactúen, entender cómo consigue realizar la función para la que dicho aparato fué fabricado. A esta acción de deducir como fue fabricado un producto y qué lo hace funcionar se le llama ingeniería inversa, y es un proceso difícil y muy laborioso. Nuestro ingeniero también sería capaz de realizar modificaciones en el artilugio para mejorarlo o personalizarlo según nuestras necesidades, pero si le facilitamos un datasheet, una documentación técnica, el tiempo que necesitará para hacerlo disminuiría obstensiblemente.\nSi en nuestros desarrollos de software nos aseguramos de que todo el equipo gestiona el primer tipo de documentación de código que mencionábamos, a saber, la documentación técnica sobre cómo funciona, vamos a obtener beneficios de rendimiento, pues las revisiones de código y la depuración de errores se realizarán de un modo ágil. Estos comentarios dentro del mismo código son equiparables al mencionado datasheet de un producto electrónico, y nos ayudarán a recordar rápidamente el modo en el que habíamos ideado un código antiguo si necesitamos ojearlo más tarde para hacer mejoras en él. Definitivamente, facilita la compresión del código sin necesidad de hacer una durísima ingeniería inversa, independientemente de que el código fuera escrito por nosotros o por otro desarrollador.\nPara ejecutar un desarrollo de sofware de calidad, especialmente cuando lo queremos dotar de una API externa, también es indispensable una documentación donde se pueda acceder a la información sobre qué trabajo realiza cada elemento, y sobre qué es lo que necesita para realizarlo; es decir, necesitamos poder comprender el uso y el funcionamiento de los componentes programados sin necesidad de ojear su código fuente. Gestionar la documentación API, el manual de instrucciones de uso, es también una ayuda en el momento del desarrollo: en ocasiones, documentando clases de código recién escritas, he descubierto que la lógica usada no era buena, y he podido rehacer mi trabajo a tiempo para mejorarlo. El hecho de que una tecnología como Java incorpore el sistema de documentación automática JavaDoc, y que dicho sistema haya sido imitado para otros lenguajes de programación, nos muestra la importancia de esta documentación tanto para el desarrollo como para el uso de nuestro producto final.\nImaginemos ahora que adquirimos un robot aspirador automático, uno de esos aparatos que pasean solos por nuestra casa recogiendo la suciedad del suelo mientras nosotros nos podemos dedicar a cualquier otra tarea. Seguro que el pequeño barrendero electrónico dispone de una gran cantidad de parámetros para poder configurar la tarea de limpieza: programar la hora de inicio, la intensidad, la eficiencia, la hora de apagado, etcétera. ¿Cuál sería tu impresión si, al sacarlo de su caja nuevecito y listo para estrenar, no pudieras localizar en el aparato ningún botón o interruptor y comprobaras, además, que no dispone de manual de instrucciones? Recibir un producto software con una API externa sin documentar es algo muy parecido a que te regalen un enorme puck de hockey con la promesa de que limpiará tu hogar.\n","id":84,"tag":"Código profesional","title":"Sin documentos no hay hockey","url":"https://metrosetenta.es/blog/sin-documentos-no-hay-hockey/"},{"content":"Pues eso, que me gusta tabular blandito. Seguro que coincides conmigo en que sangrar el código, es decir, comenzar ciertos renglones más a la derecha que otros, es un modo más que efectivo de organizar y facilitar su lectura. Tanto es así, que esta técnica forma parte de la sintaxis del lenguaje de programación Python.\nLa tecla tabulador de las antiguas máquinas de escribir, al ser pulsada, introducía automáticamente una cantidad determinada de espacios. Actualmente, con el uso de las computadoras, en prácticamente todos los editores de texto podemos elegir entre tabular blando o duro. La primera opción imita el funcionamiento de las antiguas máquinas de escribir: introducir una cantidad determinada de espacios. Esto quiere decir que tabular en cuatro caracteres es lo mismo que pulsar la barra de espacio cuatro veces. En el segundo caso, con la tabulación dura, el espacio sangrado funciona como un bloque indivisible de cuatro espacios. Aunque visualmente nos van a resultar idénticos voy a mostrate a continuación que no lo son y, por este motivo, la elección del tipo de tabulación es importante en los desarrollos de software.\nUn código sangrado con tabulación dura dispone de la ventaja de poder ser leído de un modo más flexible. Aunque originalmente fuera escrito con tabulaciones de hasta cuatro caracteres de longitud, si prefieres que tengan el tamaño de ocho, pues lo ajustas en la configuración de tu editor de texto y listo. Será el propio editor quien se encargue de convertir todas las tabulaciones duras para que se vean con una longitud de ocho caracteres. Las tabulaciones blandas, como realmente son espacios, pues no se verán afectadas.\n¿Qué por qué me gusta tabular blandito? Pues porque en los desarrollos de software se combina habitualmente tabulaciones y espacios, y mediante la tabulación blanda, el look and feel del código permanece inalterado independientemente del editor usado por cada desarrollador y sus preferencias.\n","id":85,"tag":"Código profesional","title":"Tabular blandito","url":"https://metrosetenta.es/blog/tabular-blandito/"},{"content":"Te presento una técnica bastante extendida entre los programadores anglosajones de lenguaje C, y que se podría traducir como código andamio. Consiste en definir, mediante una directiva del preprocesador, una constante durante el código fuente. En el caso que nos ocupa se le suele nombrar DEBUG y el valor puede ser, por ejemplo, 1.\n#define DEBUG 1 A partir de ahora, puedes crear tus propios puntos de testeo del siguiente modo.\n#ifdef DEBUG print(\u0026#34;Valor de variable_testeada = \u0026#34;); print(variable_testeada); #endif Puedes usar la siguiente directiva para desactivar los condicionales anteriores en aquellas partes del código que ya estén testeadas y corregidas.\n#undef DEBUG Y, por último, una vez testeado y corregido todo el código, pues quitamos el andamio. Es decir, eliminamos #define DEBUG 1 y en los archivos objeto no quedará ni rastro.\n","id":86,"tag":"C","title":"Código andamio","url":"https://metrosetenta.es/blog/codigo-andamio/"},{"content":" Piensa en tu placa Arduino ejecutando alegremente y ad libitum el bloque Loop que le ordenaste. En un momento dado necesitas que lo deje todo y realice una acción concreta. Por ejemplo, un láser que al ser interrumpido activa una alarma. Bien, pues para conseguir esto disponemos de un tipo de función avanzada que se llama ISP (Rutina de interrupción de servicio).\nVayamos por partes. Lo primero que necesitamos es adjuntar un interruptor a nuestro código. Para ello usamos la función attachInterrupt(interruptor, función, modo). En arduino Uno podemos usar los pines 2 y 3 para conectar el hardware que ordenará la ejecución de nuestra ISP. En el primer parámetro esta función, el parámetro interruptor, debemos aclarar de que interruptor estamos hablando, por tanto escribe 0 si tu láser está conectado en el pin 2, o escribe 1 si lo está en el pin 3.\nEl parámetro función espera que le indiquemos la función que debe ejecutarse cuando el interruptor hardware (nuestro laser) así lo indique. Para nuestro ejemplo habremos preparado la función activarAlarma(), la cual habremos definido en otro momento.\nVamos con el parámetro modo. Podemos elegir que activarAlarma() se ejecute mientras no recibimos señal en nuestro pin (LOW), cuando la señal cambie de bajo a alto (RISING), cuando cambie en el sentido contrario (FALLING), o simplemente cuando cambie, independientemente de la dirección (CHANGE). Visto todo esto, nos queda así la función: attachInterrupt(0, activarAlarma(), RISING); Si más adelante en tu código necesitas desactivar este interruptor de servicio, puedes usar la función detachInterrupt(interruptor), que sólo necesita como parámetro el pin donde está conectado nuestro interruptor hardware. En nuestro caso quedaría así:\ndetachInterrupt(0); ¡y alarma desactivada!\n","id":87,"tag":"Arduino","title":"Interruptores hardware en Arduino","url":"https://metrosetenta.es/blog/interruptores-hardware-en-arduino/"},{"content":"Cuando recibimos los diferentes niveles de intensidad eléctrica de un sensor en uno de nuestros pines analógicos, el Analogic to digital converter (modificador de analógico a digital) de nuestro microcontrolador transforma esa intensidad en un dato digital almacenado en 10 bits. Por tanto, tenemos una escala de valores posibles desde 0 hasta 1023, donde 0 equivale a 0 voltios y 1023 equivale a 5 voltios (o el valor máximo establecido con la función analogReference()).\nAl igual que tu paleta de pádel, los sensores suelen disponer de un punto dulce. Imagina un sensor de temperatura que nunca baja de una lectura de 20, haga el frio que haga, y que cuando se encuentra en el infierno no pasa casi nunca del valor 900. Ahí es donde nos interesa asegurarnos de que todos los valores obtenidos estarán en el punto dulce de nuestro sensor, y para ello usaremos una línea de código como la que sigue:\nconstrain(valorDelSensor, 20, 900); Con esta función nos aseguraremos de que todos los valores devueltos por el sensor estarán dentro de ese rango, pues una lectura ocasional de 18 quedará en 20 y una lectura ocasional de 901 quedará en 900. Es muy útil para, más tarde, mapear los valores de nuestro sensor a un pin digital y mostrarlos a través de, por ejemplo, una pantalla LCD.\n","id":88,"tag":"Arduino","title":"Función constrain() para arduino","url":"https://metrosetenta.es/blog/funci%C3%B3n-constrain-para-arduino/"},{"content":"Al usar una etiqueta para crear un enlace en HTML y hacerlo funcionar como un botón, serás capaz de observar que el área donde el usuario puede cliquear coincide con la altura y ancho del texto del enlace. Esto se debe a que esta etiqueta se visualiza en línea de forma predeterminada, pero es posible modificarla para darle un diseño más atractivo de cara al usuario cambiando el tipo de visualización, en el código CSS del enlace, al tipo bloque:\na {display: block} A menos que especifiques un ancho específico con la propiedad width, la transformación del enlace en un elemento de tipo bloque hace que éste abarque todo el ancho del elemento en el que se encuentra contenido. Esta modificación lo hace idóneo para los enlaces ubicados en una barra lateral o para los enlaces de un menú desplegable.\nPara terminar, como la conversión que hemos hecho al enlace sólo afecta a su comportamiento y su ancho, termina añadiendo un buen relleno con la propiedad padding. Haciendo esto consigues que la altura del botón sea más adecuada a su contenido y el elemento respirará, es decir, no dará una sensación claustrofóbica respecto al texto visible en su interior.\nRealiza pruebas y combina estas ideas, seguro que te ayudarán a encontrar un estilo propio. Yo te añado aquí abajo una idea para que veas como puedes mejorar fácilmente el aspecto de este elemento.\n\u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;a href=\u0026#34;./\u0026#34;\u0026gt;Para pulsar\u0026lt;/a\u0026gt; \u0026lt;br/\u0026gt;\u0026lt;br/\u0026gt; \u0026lt;a style=\u0026#34;color: white; display: block; padding: 6px; width: 70px; border: 1px solid black; box-shadow: 3px 3px 1px #888888; text-decoration:none; background-color: #088;\u0026#34; href=\u0026#34;./\u0026#34;\u0026gt; Para pulsar \u0026lt;/a\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; ","id":89,"tag":"UI/UX","title":"Usando la etiqueta de enlace como botón","url":"https://metrosetenta.es/blog/usando-la-etiqueta-de-enlace-como-boton/"},{"content":"Vamos a abordar juntos otro par de párrafos sobre SQL injection. En esta ocasión te escribo sobre una variante de esta técnica que se basa en la posibilidad de ejecutar varias consultas, usando el estándar SQL, separadas entre sí con el signo de puntuación punto y coma (;).\nCon una pequeña y rápida prueba, un hacker puede comprobar si nuestro formulario es vulnerable a SQL injection, y si debe usar una comilla sencilla (‘) o comillas dobles (“). Una vez hecho esto únicamente ha de separar el valor legítimo del código malicioso usando dicha comilla, y con el punto y coma finalizar la consulta legítima para iniciar una nueva consulta con la función que el hacker desee realizar sobre la base de datos. Parece difícil, pero cuando veas un ejemplo verás que es realmente sencillo.\nEl valor led zeppelín daría lugar a una consulta del tipo que sigue.\nSELECT * FROM discografía WHERE autor = \u0026#39;led zeppelin\u0026#39; Ahora vamos a ver el resultado introduciendo el valor led zeppelin’; GRANT ALL ON *.* TO ‘hacker’@’%\nSELECT * FROM discografía WHERE autor = \u0026#39;led zeppelin\u0026#39;; GRANT ALL ON *.* TO \u0026#39;hacker\u0026#39;@\u0026#39;%\u0026#39; La extensión de MySQL para PHP no permite realizar múltiples consultas de modo predeterminado, pero la nueva extensión posee la función mysql_multi_query(). La recomendación obvia es que no hagas uso de esta función si deseas preservar tu aplicación de este tipo de ataques. Deberás ser más cuidadoso aún si usas SQLite que, por la facilidad que otorga para el manejo de bases de datos desde PHP, atrajo la atención de muchos desarrolladores en un momento dado. SQLite permite el uso de múltiples consultas, especialmente con comandos INSERT, aunque es más restrictivo con comandos SELECT. No dejes de consultar su documentación en lo relativo a estos aspectos en http://sqlite.org o en http://es.php.net/sqlite.\n","id":90,"tag":"Seguridad ; SQL","title":"SQL injection múltiple","url":"https://metrosetenta.es/blog/sql-injection-multiple/"},{"content":" PEAR se define a sí mismo, al inicio de su página web (http://pear.php.net), como un marco y un sistema de distribución de componentes PHP reutilizables. PEAR son las siglas de PHP Extension and Application Repository, y su logotipo, aprovechando el juego de palabras, es una simpática pera. En alguna ocasión te escribiré acerca de PEAR en este blog (si no lo he hecho ya), y por este motivo hoy te lo presento de un modo liviano.\nCuando programas una aplicación web en PHP puedes tomar la decisión de escribir todas y cada una de las líneas de código que la compondrán, o puedes reutilizar, allí donde te sea útil, líneas de código que otros desarrolladores ya han realizado anteriormente. Te puedes ahorrar un gran número de pulsaciones sobre tu teclado si decides usar el paquete de código para autentificación de usuarios, o el de gestión de correo electrónico, o el de manejo de las características AJAX… pero ¿todo son beneficios?.\nPEAR está muy bien documentado, lo que quiere decir que además de manuales para preparar y usar los paquetes disponibles, puedes ver la cantidad de veces que han sido descargados, los bugs reportados, versiones, etcétera, pero ahora vienen las desventajas. Cuando decides que un paquete te viene al dedillo, resulta que este hace uso de otro paquete. El segundo paquete hace uso de seis paquetes más y, finalmente, todo termina en que debes añadir a tu aplicación una estimablemente elevada cantidad de código ajeno (en la web de PEAR ya se puede leer “Total Lines of Code: 8,306,287” aunque no las necesitarás todas). La comunidad es realmente buena, y dispone de una división denominada The PEAR Quality Assurance Initiative, que asegura la calidad del código, pero aun así deberías estar atento a muchas actualizaciones y enmiendas de bugs para cada paquete de código usado. Resumiendo, te crearías voluntariamente una dependencia de la comunidad de PEAR, que por otro lado parece muy activa, y de su ritmo y estilo de desarrollo. ¿Qué hacer entonces?.\nLa respuesta a esta última pregunta sólo la tienes tú. Si vas a corregir la seguridad de una pequeña y antigua web que hiciste hace unos meses, probablemente lo mejor será añadir un poco de código propio y nada más. Si emprendes una faraónica tarea de desarrollo, no dejes de echar un vistazo a los paquetes, de sopesar si serán útiles e, incluso, valorar si merece la pena adaptarlos a tu estilo o completarlos. Se puede aprender mucho revisando el código de otras personas y, por supuesto, colaborando en una comunidad de desarrolladores como PEAR.\n","id":91,"tag":"PHP","title":"¿Es PEAR la pera?","url":"https://metrosetenta.es/blog/es-pear-la-pera/"},{"content":"Estoy convencido de que si lo piensas detenidamente coincidirás conmigo en que, usualmente, la finalidad de nuestras aplicaciones es la de servir a nuestros usuarios de interfaz para el manejo de extensas bases de datos. Estas bases de datos están diseñadas para facilitar la consulta y el transporte de información hacia el usuario y, en sentido opuesto, para recibir y almacenar información entregada por el mismo. Cada vez que un usuario consulta o envía información a la base de datos de tu aplicación, está participando en la construcción de un código que ejecutará una acción en dicha base de datos. Ahora que hemos dicho esto, pregúntate ¿podría un usuario ilegítimo aprovechar esta pequeña participación para desvirtuar el código y hackear tu base de datos?.\nLa respuesta obviamente es sí, y un método para llegar a conseguirlo es aprovechar esa pequeña participación que le has otorgado a tus usuarios para inyectar código SQL, es decir, a través de una técnica denominada SQL injection. Funciona de un modo sencillo que te paso a ilustrar. Imagina una base de datos que almacena información de animales. Tus usuarios pueden consultarla a través de un formulario web donde deben indicar la especie y, posteriormente, nosotros vamos a recoger esa petición con el código $especie = $_POST[‘especie’]. Una vez que disponemos de la especie que le interesa al usuario, lo usamos para generar la siguiente consulta a la base de datos:\nconsulta = \u0026#34;SELECT * FROM animales WHERE especie = \u0026#34; + especie; Si introducimos la palabra mamífero en el formulario de esta aplicación, se traducirá en la siguiente consulta:\nconsulta = \u0026#34;SELECT * FROM animales WHERE especie = \u0026#34; + mamífero; Hasta aquí el funcionamiento es el esperado, pero ¿y si introducimos la cadena mamífero’ OR 1=1? Volvemos a traducir la consulta resultante:\nconsulta = \u0026#34;SELECT * FROM animales WHERE especie = \u0026#34; + mamífero + \u0026#34; OR 1 = 1\u0026#34;; Ahora, recibiremos la información de todos los animales contenidos en la base de datos, pues usando la comilla sencilla, hemos desvirtuado el código de la consulta, y el condicionante 1=1 que hemos conseguido inyectar se cumple siempre. Este es el fundamento de SQL injection.\n","id":92,"tag":"Seguridad ; SQL","title":"El fundamento de SQL injection","url":"https://metrosetenta.es/blog/el-fundamento-de-sql-injection/"},{"content":" Te cuento más cosas a tener en cuenta cuando procesas información recibida de tus usuarios. En primer lugar quiero que sepas que es conveniente que chequees la longitud de los valores recibidos para prevenir ataques de denegación de servicio o de desbordamiento de buffer. En PHP se puede usar la función strlen() para comprobar la longitud del dato recibido antes de procesarlo.\nIf (strlen($edad) \u0026gt; 3 ) exit ($edad . \u0026#34; es un valor inválido para el campo edad\u0026#34;;) Y ahora hablemos del formato. Cuando comprobamos el tipo de variable y su longitud puede parecer que tenemos todo el trabajo hecho, pero no es del todo cierto. Una fecha de nacimiento y un correo electrónico pueden estar contenidos en una variable del tipo cadena de caracteres, pero tienen aspectos bien distintos, formatos diferentes. La fecha puede estar separada por barras, usar dos caracteres para indicar el día en cifras, tres para indicar el mes en letras y dos para indicar el año en cifras; algo así como 12/jun/78. El correo electrónico contiene dos secciones bien diferencias por el signo @ y finaliza con un punto y una extensión del tipo com, es, tv, org, etc. Otro ejemplo: metroSetenta@gmail.com. En el momento en que nuestro código debe interactuar con el de otras aplicaciones como, por ejemplo, gestores de correos, bases de datos o sistemas subyacentes, el formato usado es esencial para la prevención de errores y brechas de seguridad.\nHay cientos de códigos en la red para validar el tipo, la longitud y el formato de valores recibidos, y es interesante leer algunos y elegir el más adecuado para nuestro estilo de programación, pero, una vez hecho esto, no dejes de modificarlo para completar el código que has elegido y adaptarlo a tu estilo de desarrollo. También puedes escribir desde cero tu propio código de validación una vez estudiado lo que otros ya han hecho anteriormente.\n","id":93,"tag":"Seguridad ; PHP","title":"Longitud y formato también importan","url":"https://metrosetenta.es/blog/longitud-y-formato-tambien-importan/"},{"content":" Este es uno de esos pasos que ya te conté que tienes que dar para conseguir el correcto y seguro funcionamiento de tu aplicación. No es necesario tener un nivel de formación en informática a la altura de poder generar errores del tipo buffer overflow, porque si tu aplicación espera un valor numérico y un usuario maligno introduce texto, lo mejor que puede pasar es que tu programa no funcione correctamente. Se trata, pues, de una gran brecha potencial en la seguridad de tu aplicación. Los tipo de datos, a grandes rasgos se pueden dividir en tres: Cadenas de texto, números y booleanos.\nLas cadenas de texto, en casi todos los lenguajes informáticos, se nombran como strings y, muchos de ellos, valoran como una cadena de texto vacía los campos que el usuario dejó sin completar. Un modo de chequearlas en PHP es con el comando is_string(), que puedes combinar con is_empty() si te interesa filtrar los valores vacíos.\nPara los números, el método is_numeric() es el primero que se le viene a uno a la cabeza, que nos devolverá el TRUE al valorar integers, floats, el número cero, e incluso con números que técnicamente son un string. Podemos ser más precisos y usar métodos como is_integer() o is_long(), o incluso comprobar que nos devuelve el método gettype() y actuar en consecuencia. Valora la posibilidad de hacer casting (convertir al formato que necesitas), porque no crea una buena impresión mostrar un mensaje de error cuando, por ejemplo, esperas un entero del tipo 45 y el usuario ha introducido el valor 45,00.\nFinalmente los booleanos. En PHP es muy importante usar is_bool(), porque el string “false” se evalua como no vacio, y en un contexto en el que lo usemos como booleano su valor será true. ¿Imaginas las posibilidades de obtener true en ciertos contextos, simplemente añadiéndole unas comillas a false para que nuestro equipo valore el dato “false”?\nEso no es todo, amigos, hay que tener una visión muy clara en los lenguajes de programación del modo en el que estos interpretan variables que contienen valores vacíos y aquellas que no contienen valores (Null). Por defecto, ninguna de ellas aportan información a gestionar por nuestra aplicación, por tanto, y como ya te expliqué en la entrada anterior, es mejor no contemplarlas ni gestionarlas.\n","id":94,"tag":"Seguridad","title":"Comprobar el tipo de datos recibidos","url":"https://metrosetenta.es/blog/comprobar-el-tipo-de-datos-recibidos/"},{"content":" En entradas anteriores hice alusión al modo en el que un usuario ilegítimo de tu aplicación web puede hacer tentativas muy básicas de hacking del estilo que sigue:\nhttp://servidor/aplicacion?administrador=TRUE Seguro que esto te hace reflexionar sobre la importancia de no admitir y gestionar variables inesperadas, así que te muestro a continuación un pequeño código para excluir automáticamente valores inapropiados de tus scripts, pudiendo así asumir con certeza que el entorno global está saneado, incluso aunque el atacante remplace el código de tu web para enviar valores no esperados. La idea consiste en listar las variables esperadas por nuestro código en un array, y posteriormente usarlo para chequear las variables recibidas. ¡Es como una lista de invitados a una sala de fiestas pija!. Aunque este ejemplo está en PHP, como casi siempre, te recuerdo que la idea es fácilmente transportable a cualquier lenguaje de programación.\n$grupoVariablesEsperadas = array (\u0026#34;variable1\u0026#34;, \u0026#34;variable2\u0026#34;, \u0026#34;variable3\u0026#34;); foreach ($grupoVariablesEsperadas) { if (!empty($POST[$variable)) { ${variable} = $POST[$variable]; } else { ${variable} = NULL; } } ","id":95,"tag":"Seguridad ; PHP","title":"Tu aplicación contra la gestión de variables inesperadas","url":"https://metrosetenta.es/blog/tu-aplicacion-contra-la-gestion-de-variables-inesperadas/"},{"content":" Son muchos los lenguajes de programación en los cuales no es necesario declarar las variables antes de que estas sean usadas. Si escribes tus códigos en un lenguaje que resulte flexible en este aspecto que te explico, y dispones de la posibilidad de configurarlo de modo que sea obligatorio declarar las variables antes de usarlas, ¡es mejor que no dejes de hacerlo!. Te muestro un código en PHP a modo de ejemplo:\nif ($tipo_usuario_logado == administrador) { $administrador = TRUE; } La variable $administrador se autodeclara con su primer uso, y a partir de ahora nuestro código mostrará condicionales de este tipo:\nif ($administrador) { // Muestra opciones propias del administrador } ¿Que ocurriría si un hacker usara un campo de introducción de datos de nuestra aplicación PHP, que estuviera mal diseñado en lo referente a la seguridad, para introducir una porción de código como el siguiente?:\n$administrador = TRUE; Pues eso es lo que ocurriría exactamente, que la variable sería recibida por nuestra aplicación, y a continuación la declararía y le daría el valor TRUE. A partir de este momento mostraría las características de la aplicación reservadas para los administradores y todas nuestras vergüenzas quedarían expuestas. ¡Observa que incluso podría, en el caso de que estén activas las variables globales, usar maliciosamente la URL de nuestra aplicación con esta finalidad!\nhttp://servidor/aplicación?administrador=TRUE Por todo lo expuesto, es conveniente usar la instrucción error_reporting() en el caso anterior para capturar errores con variables no inicializadas y poder manejar esos errores según nuestra necesidad.\nSi has pensado que sería mucho más fácil manipular la variable $tipo_usuario_logado, la cual damos por hecho que ya está declarada en nuestra aplicación, he de decirte que hay un pequeño hacker en tu interior. Es cierto, y por este motivo es importante que en cada interpretación del código que haga el servidor asignes el valor de esta variable desde, por ejemplo, una consulta a la base de datos de tus usuarios, o que lo realices usando los datos de sección que previamente has almacenado en el servidor. Sólo de esta manera, el gran especialista de seguridad que crece en ti se asegurará de mantener controlado a tu travieso hacker interior.\n","id":96,"tag":"Seguridad","title":"Declaración de variables y seguridad","url":"https://metrosetenta.es/blog/declaracion-de-variables-y-seguridad/"},{"content":" Son muchísimas las ocasiones en las que nuestras aplicaciones solicitan a los usuarios algún tipo de información: Nombre, correo electrónico, texto de opinión, nueva contraseña… Usualmente lo hacemos a través de formularios que contienen distintos campos a rellenar, campos que nuestras aplicaciones van a recibir y posteriormente van a procesar; por tanto, estos campos, que son manipulables por los usuarios, representan una vía a través de la cual se puede amenazar la seguridad de nuestras aplicaciones. Entonces ¿que es lo más básico a tener en cuenta al usar estos campos de entradas de datos?.\nLos meta caracteres son caracteres que pueden tener un significado diferente en función de la parte de tu sistema que lo esté procesando. Si tu aplicación espera recibir caracteres en una codificación que usa un único byte para almacenar cada carácter, pero el usuario introduce datos en una codificación que use dos bytes por carácter, tu aplicación los dividirá y procesará byte por byte, y aquí nos pueden hacer trampas para introducir un código inesperado, un código que no es lo que parece. Algunos meta caracteres peligroso pueden ser ‘ y “ y \\ y | y \\x00 y \\xff y \\x13…\nDeberías chequear los formatos y los tipos de datos recibidos antes de procesarlos. Si allí donde tu aplicación espera recibir un texto pequeño es obsequiada con un archivo de imagen, es muy probable que tu apreciada creación tienda al error en su gestión.\nPermitir sólo la cantidad de datos necesaria es de vital importancia. Si te interesa la seguridad informática empieza a familiarizarte con el término buffer overflow, pues es realmente recurrente en lo referente a ataques de seguridad y está relacionado con esto que te paso a explicar. Un desbordamiento de búfer ocurre cuando la cantidad de datos introducida por el usuario es mayor que la cantidad de memoria asignada para almacenarla (búfer). Esto puede ocasionar que en tu código se sobrescriban variables, que se generen errores incontrolados, que una instrucción sobrescriba a otra, etc.\nPiensa en las interfaces ocultas como en capas de tu aplicación que, aunque no estén visibles para los usuarios ilegítimos, pueden ser intuidas por estos. Un ejemplo muy básico puede ser el de una aplicación web que use la variable $_GET[‘template’] para permitir o denegar la inclusión de scripts en PHP. Seguro que el más novato de los atacantes prueba cosas del estilo http://aplicaionweb.php?template=test o http://aplicacionweb.php?template=debug o http://aplicacionweb.php?template=admin.\nTu aplicación procesa las instrucciones que tu has programado, y procesa también los datos recibidos a través de las entradas de las formularios. Entonces ¿es posible enviar a la aplicación, a través de estas entradas, instrucciones que sean procesadas y con fines maliciosos?. La respuesta a esta pregunta me parece ridículamente obvia después de haberla planteado. Los términos con los que hay que familiarizarse en este aspecto son Cross-site y scripting desde Shell remota, pues son los métodos más conocidos de introducción de instrucciones inesperadas en las entradas.\n","id":97,"tag":"Seguridad","title":"Cinco detalles a cuidar al recibir datos de tus usuarios","url":"https://metrosetenta.es/blog/cinco-detalles-a-cuidar-al-recibir-datos-de-tus-usuarios/"},{"content":" La estética MAYA es un concepto Estudio sobre la belleza. Fue propuesto por Raymond Loewy, y se fundamenta en una sencilla idea: Dentro de los conceptos estéticos ya aceptados, todos tendemos a preferir aquellos que son más modernos. Entre otras cosas, esto implica que los conceptos estéticos no son usualmente bienvenidos en el momento de nacer, sino que requieren un proceso de maduración y aceptación paulatina. Es por este motivo que, al diseñar tu aplicación, el uso de muchas innovaciones estéticas simultáneas ayudará a desconcertar a tus usuarios. Por otro lado, si carece de toda novedad en su diseño, tu aplicación no supondrá ningún estímulo para los usuarios. El concepto MAYA (Most advanced, yet aceptable) te anima como diseñador a buscar el equilibrio entre lo moderno y lo que resulta familiar para tus usuarios, y es sencillo de comprender que resulte usualmente efectivo. Si, eso es, escribí usualmente efectivo, no te extrañes. Es obvio que si vas a realizar la web de una empresa de innovaciones tecnológicas este concepto no aplica por completo. Igualmente, si eres el encargado de ensalzar las cualidades del legendario Commodore 64 en una web de lo más vintage, debes olvidarte de MAYA y aplicar otras ideas, pero permíteme finalizar diciéndote que, salvo casos muy específicos como estos, el uso de conceptos estéticos modernos, con la seguridad de que son comprendidos y aceptados por los usuarios, es una apuesta segura para incrementar las posibilidades de éxito de tus aplicaciones.\n","id":98,"tag":"UI/UX","title":"La estética MAYA","url":"https://metrosetenta.es/blog/la-estetica-maya/"},{"content":" Es posible que después de leer lo que sigue no vuelvas a teclear con tranquilidad el número de tu tarjeta de crédito en ninguna página web, pero hoy te quiero desvelar que la seguridad absoluta no existe en la informática contemporánea. Esto es así hasta el punto de que los expertos en seguridad informática hablan de la gestión del riesgo, y no de su eliminación completa. ¿Por que?.\nNo importa si programas en Java o en PHP, incluso da igual si te has decantado por hacerlo con Ruby on rails o con el Net framework de Microsoft, porque indiferentemente al lenguaje y entorno de programación que uses, finalmente todo se traduce en ceros y unos. Si, así es, todo se reduce a impulsos eléctricos gestionados por un CPU, y el pequeño cerebro de nuestra computadora no sabrá distinguir si realmente todos y cada uno de los binarios que procesa cumplen con las sanas intenciones del legítimo programador de un software en ejecución o, por el contrario, se trata de un añadido malintencionado que aprovecha la más mínima vulnerabilidad de cualquiera de los procesos que corren en el sistema. Entonces ¿es imposible crear un programa perfectamente seguro, sin vulnerabilidades?.\nDesarrollo en un sistema pequeño, donde dispongamos de todo el control, es posible prevenir defectos de seguridad, pero los sistemas operativos modernos gestionan muchos procesos simultáneos que suponen un enorme flujo de megabytes. Además, las aplicaciones en línea tienen el añadido de implicar a un mayor número de equipos y aplicaciones de terceros, por lo tanto complican aún más esta difícil ecuación sobre seguridad. ¿Nos hemos rendido entonces?.\nNo, nunca. El ritmo de detección y reparación de cualquier fisura de seguridad (bug) es tan trepidante que los modos más cotizados de aprovechar una vulnerabilidad son las explotaciones de día cero (0 day exploits) y, en su mayoría, estas no suelen tener una vida muy prolongada. Hay que añadir a esto el compromiso de cualquier desarrollador o administrador de sistemas para mantener libre de bugs sus programas y sistemas, y de este modo evitar comprometer a otros sistemas en la red. ¡Tu reputación será tan buena como la gestión que realizas de la seguridad en tus aplicaciones o sistemas, por lo tanto, no la descuides nunca!.\n","id":99,"tag":"Seguridad","title":"Seguridad informática absoluta y gestión del riesgo","url":"https://metrosetenta.es/blog/seguridad-informatica-absoluta-y-gestion-del-riesgo/"},{"content":" Tan sencillo como reza el título. Cuando ofreces una interfaz gráfica a un usuario, éste se forja una opinión sobre su aspecto y hace una rápida interpretación del modo en el que funciona. El camino que se sigue para desarrollar el diseño de una aplicación informática es muy parecido al usado en sus proyectos por un arquitecto de antes del año 1900: Abordar el problema de la funcionalidad y, desde esta base, solventar posteriormente el asunto de la emotividad.\nSegún esto, primero debes asegurarte de que el programa funciona como lo has concebido, que es fiable y que está libre de errores de programación. En el punto intermedio debes trabajar para que tu aplicación resulte fácil de usar, es decir, para que el usuario esté lo más acertado posible en su interpretación inicial del funcionamiento. Casi terminando, una vez resuelto este trecho, que muchas empresas de desarrollo no consiguen solventar, puedes centrarte en que el uso de la aplicación suponga una experiencia agradable para el usuario. Finalmente, la panacea del diseño, ¿serías capaz de conseguir que tu aplicación resulte significativa para cada persona?. Unas pistas: iGoogle, pestaña diseño en Twitter, temas de hotmail, avatares\u0026hellip;\nAhora te hago dos sugerencias. En primer lugar, prueba a trabajar en el sentido contrario, es decir, comienza desde el enfoque de la experiencia para finalizar trabajando sobre la funcionalidad de tu aplicación. ¡Ya no nos encontramos en el siglo dieciocho!. En segundo lugar, dale una lecturita a algún escrito sobre el arquitecto Frank Lloyd Wright. Él afirmaba que la forma y la función debían ser una unidad, y que es así como se puede observar en la naturaleza. Sea como fuere, y en lo referente al diseño y la funcionalidad, es de extrema utilidad para abordar el inicio de una nueva aplicación, o para trabajar sobre la reestructuración de una aplicación más antigua, tener un criterio establecido sobre el mejor enfoque general y ser capaz de usar distintos y variados enfoques puntuales.\n","id":100,"tag":"UI/UX","title":"El usuario evalua e interpreta los diseños","url":"https://metrosetenta.es/blog/el-usuario-evalua-e-interpreta-los-dise%C3%B1os/"},{"content":" En ocasiones los datos perseguidos por un hacker se encuentran repartidos en más de un servidor. Esto le obligará a rastrear la ubicación de las distintas partes y a obtener la información necesaria de cada servidor para poder acceder a su objetivo. Los programas que usan los hackers para automatizár esas acciones son los llamados web crawlers, y se usan para desentrañar toda la arquitectura de sitios web.\nUna vez que el hacker dispone de toda la información básica necesaria, realiza una búsqueda de información sobre las posibles vulnerabilidades de sus objetivos. Generalmente se tratan de errores de software, y por este motivo se les denominan bugs. Tienes que saber que existen aplicaciones, genéricamente llamadas bugs trackers, que se usan para el seguimiento y gestión de estos bugs. Es facil encontrar en la red bugs trackers enfocados a facilitar el hacking, e igualmente, es fácil encontrar programas diseñados para explotar los bugs de diferentes aplicaciones (exploits), especialmente de servidores.\nEl hacker estudiará los servidores a través de un proxy, de un modo poco agresivo y en intervalos de tiempo controlados para burlar un posible firewall. Por último, un estudio concienzudo de todo el código visible podría facilitarle pistas sobre nombres de directorios, posibles estructuras SQL usadas para las consultas a bases de datos, nombres de campos, variables, etc. Para esto, es de gran ayuda un capturador web, o como también se le denomina, un web snake.\nSeguro que entiendes, después de todo esto, lo importante que es realizar auditorías de seguridad al servidor web, realizar auditorías a las bases de datos que manejan nuestras aplicaciones web, y escribir cuidadosamente el código que pudiera ser visible.\n","id":101,"tag":"Seguridad","title":"Crawlers, Bugs y capturadores web","url":"https://metrosetenta.es/blog/crawlers-bugs-y-capturadores-web/"},{"content":"Ya sabes que tu user’s agent puede usar el protocolo HTTP para hacer una solicitud a un servidor (request), y que éste nos facilitará una respuesta adecuada a dicha solicitud (response). A continuación te presentaré los métodos que usa tu user´s agent para realizar diferentes solicitudes al servidor, pero antes debes conocer un detalle, existen actualmente cuatro versiones del protocolo HTTP, y en las más antiguas no están disponible todos los métodos te paso a presentar.\nGET: Se usa para solicitar datos al servidor, y debido a que usa la URL, no debes tenerlo en cuenta para programar el envío de solicitudes que conlleven la ejecución de acciones, pues un hacker podría manipular con facilidad, y de un modo malicioso, los parámetros enviados a tu aplicación en el servidor. Un ejemplo de este método: GET /iconos/logo.gif HTTP/1.1\nHEAD: Este método funciona de un modo similar a GET, pero con la salvedad de que facilita únicamente meta-información, es decir, datos sobre la cabecera HTML, sobre la respuesta del servidor y sobre el mismo servidor. Muy usado por hackers para obtener información acerca de las propiedades del servidor, y para probarlo puedes teclear lo siguiente es una línea de comandos:\n$ telnet www.cortinasdeducha.com 80 Una vez conectado hacemos una solicitud HTTP como esta que sigue, y pulsamos intro un par de veces:\nHEAD / HTTP/1.0. Finalmente, entre los datos que recibiremos se encuentra una información como la que sigue:\nServer: Apache/2.2.22 (Unix) modsl/2.2.22 OpenSSL/0.9.8e-fips-rhel5 modauthpassthrough/2.1 modbwlimited/1.4 FrontPage/5.0.2.2635 modperl/2.0.5 Perl/v5.8 POST: También es similar a GET, pero con estas salvedades: No usa la URL, estando así menos expuesto a ataques web que el método GET, y normalmente solicita una acción en el servidor mediante CGI, por tanto, deberá aportar los parámetros para realizarla\nPUT: Es el mejor método para solicitar al servidor que almacene datos, puesto que POST utiliza un mensaje que el servidor debe decodificar, pero el método PUT establece directamente una conexión socket con el servidor. Como punto negativo, debes saber que los servidores de hosting compartido no tienen habilitado este método. DELETE: Borra el recurso especificado.\nTRACE: Es usado para realizar comprobaciones y diagnósticos, pues solicita un mensaje de tipo loopback que en la sesión de datos únicamente contiene una réplica de la solicitud realizada.\nOPTIONS: Es muy útil para un hacker, que podrá usarlo para obtener información sobre las funcionalidades de un servidor web, ya que informa sobre los métodos http que este soporta para una URL especifica.\nCONNECT: Se utiliza con proxy para saber si éste nos permite el acceso a un host determinado bajo condiciones especiales como un flujo de datos encriptados, ya que tiene la característica de cambiar de forma dinámica a modo túnel (SSL tunneling).\n","id":102,"tag":"Seguridad","title":"Métodos de los protocolos web y hacking","url":"https://metrosetenta.es/blog/metodos-de-los-protocolos-web-y-hacking/"},{"content":" Hay algo que debes de tener siempre presente si quieres responsabilizarte de la seguridad de tus aplicaciones, o de la seguridad de las aplicaciones de terceros: debes superar, o igualar al menos, los conocimientos de cualquier hacker potencial de dichas aplicaciones. Centrándonos en la web, es básico conocer el protocolo de comunicación que esta usa, pues un hacker lo dominará perfectamente. World wide web es una de la partes más activas de internet, y hace uso de dos protocolos: HTTP y HTTPS.\nEl protocolo de transferencia de hipertexto (HTTP) funciona de un modo sencillo basado en peticiones y respuestas. El agente de usuario encargado de hacer la petición (usualmente un navegador web) solicita un recurso a una computadora que es la encargada de almacenarlo y proveerlo, es decir, al servidor. Después de valorar la petición del cliente, dicho servidor prepara y devuelve la respuesta, que puede consistir en una página web, un documento informático, datos obtenidos al ejecutar un programa o una consulta a una base de datos, etc.\nEstas transacciones constan de un encabezado que estará seguido por una línea en blanco y por los datos principales. En el encabezado se hace referencia a los datos principales, y por este motivo se le conoce como metadatos. El servidor coloca los metadatos en las variables de entorno de CGI, usando el prefijo HTTP_ para distinguirlas del resto.\nEl protocolo seguro de transferencia de hipertexto (HTTPS) es similar a HTTP, pero en esta ocasión crea un canal cifrado mediante SSL/TLS. HTTPS utiliza por defecto el puerto 443, en lugar del puerto 80 propio de HTTP. La finalidad de este protocolo es evitar ataques man-in-the-middle y eavesdropping, mediante los cuales un hacker puede obtener acceso a cuentas de un sitio web o información confidencial.\n","id":103,"tag":"Seguridad","title":"Protocolos web y seguridad","url":"https://metrosetenta.es/blog/protocolos-web-y-seguridad/"},{"content":" Las siglas CGI (Common Gateway Interface) significan Interfaz de entrada común, y definen un estándar usado para que los usuarios web puedan intercambiar datos con una aplicación alojada en un servidor web. A continuación un buen ejemplo de aplicación que usa el estándar CGI:\nEl usuario está buscando en su navegador web una farmacia cercana, y para ello introduce los datos de su domicilio en un formulario y pulsa el botón enviar. La aplicación CGI (que así la llaman por usar este estándar) que se encuentra alojada en el servidor web recibe la solicitud de fulanito, luego hace una consulta a una base de datos basándose en ella y envía a fulanito una web con los resultados perfectamente expuestos y ordenados.\nPuedes escribir aplicaciones CGI si desarrollas en C, C++, Java, Visualbasic, C#, Perl\u0026hellip; ¡casi en cualquier lenguaje de programación!. Y ahora viene lo interesante para la seguridad informática: las variables de entorno de una aplicación CGI. A continuación las puedes ver expuestas tal y cual las numera Wikipedia. Es posible conocer el puerto de acceso o el protocolo usado gracias a ellas, y las tres últimas contienen información del servidor, que es lo primero que un hacker buscará al realizar un ataque web.\nVariables de entorno que se intercambian de cliente a CGI:\nQUERY_STRING: Es la cadena de entrada del CGI cuando se utiliza el método GET sustituyendo algunos símbolos especiales por otros. Cada elemento se envía como una pareja Variable=Valor. Si se utiliza el método POST esta variable de entorno está vacía.\nCONTENT_TYPE: Tipo MIME de los datos enviados al CGI mediante POST. Con GET está vacía. Un valor típico para esta variable es: Application/X-www-form-urlencoded.\nCONTENT_LENGTH: Longitud en bytes de los datos enviados al CGI utilizando el método POST. Con GET está vacía.\nPATH_INFO: Información adicional de la ruta (el \u0026ldquo;path\u0026rdquo;) tal y como llega al servidor en el URL.\nREQUEST_METHOD: Nombre del método (GET o POST) utilizado para invocar al CGI.\nSCRIPT_NAME: Nombre del CGI invocado.\nSERVER_PORT: Puerto por el que el servidor recibe la conexión.\nSERVER_PROTOCOL: Nombre y versión del protocolo en uso. (Ej.: HTTP/1.0 o 1.1)\nVariables de entorno que se intercambian de servidor a CGI:\nSERVER_SOFTWARE: Nombre y versión del software servidor de www.\nSERVER_NAME: Nombre del servidor.\nGATEWAY_INTERFACE: Nombre y versión de la interfaz de comunicación entre servidor y aplicaciones CGI/1.12.\n","id":104,"tag":"Seguridad","title":"Variables de entorno y CGI","url":"https://metrosetenta.es/blog/variables-de-entorno-y-cgi/"},{"content":"Son muchas las herramientas a disposición de un hacker para explotar vulnerabilidades a tu aplicación web, por esto, son muchas las posibilidades que tiene de realizar un ataque exitoso con un mínimo de conocimientos. Toma notas, porque esto es lo más básico que debes considerar para ir empezando a trabajar la seguridad de tus aplicaciones web:\nFiltra los caracteres peligrosos de cualquier dato ingresado por los usuarios de tu aplicación, y no olvides hacer lo mismo con los campos ocultos de formularios si los sueles usar.\nRealiza una validación de los datos mencionados anteriormente, comprueba que es correcta la longitud, o el tipo de datos, o que son valores correctos\u0026hellip; Por ejemplo, un modo de filtrar un texto en PHP, para comprobar que sólo se trata de números y letras, es así:\ntextoLimpio = preg_replace(\u0026#39;(\\[^A-Za-z0-9\\])\u0026#39;, \u0026#39;\u0026#39;, textoALimpiar) Si usas parámetros en las direcciones URL de tu aplicación revisa a conciencia que no sea posible ingresar parámetros peligrosos. Igualmente comprueba que sea imposible ver los listados de directorios.\nActualiza el programa servidor constantemente e instala los parches necesarios para corregir los bugs descubiertos que puedan presentar oportunidades para uso malicioso.\n","id":105,"tag":"Seguridad ; PHP","title":"Lo más básico contra ataques web","url":"https://metrosetenta.es/blog/lo-mas-basico-contra-ataques-web/"},{"content":"Hay un modo sencillo y rápido para detectar posibles errores en el diseño de tus aplicaciones: ”si no puedes reproducir tu diseño en la realidad palpable, algo debe estar mal”. Observa como el uso de las sombras, en las ventanas de la imagen más a la izquierda, resulta desconcertante. Prueba a tomar dos folios e intenta reproducir con ellos la posición de las ventanas indicadas.\nComprueba cómo la imagen que se encuentra más a la derecha reproduce con mayor acierto las sombras proyectadas, evitando el desconcierto del modelo anterior y clarificando cual es la ventana más cercana y cual es la que se encuentra al fondo.\nEsto es especialmente útil para valorar el uso de sombras, brillos y luces de tu diseño, y para incluirlos correctamente.\n","id":106,"tag":"UI/UX","title":"Diseños reproducibles","url":"https://metrosetenta.es/blog/disenos-reproducibles/"},{"content":" Conocer la forma en la que el cerebro percibe e interpreta sombras, colores, formas, etc. es una poderosa herramienta de diseño. En el momento de tomar decisiones relacionadas con el diseño, debes ser capaz de incluir y valorar compresiones intuitivas (percived afforance). Te aclaro de que se trata con un ejemplo: una señal octogonal de color rojo practicamente no necesita la palabra STOP en el centro, pues su forma y color característico son suficiente para que el usuario pueda intuir el significado. Observa, por otro lado, lo desconcertante que puede ser una señal de stop de color azul y cuadrada.\nAl ver esto, entenderás rápidamente que en el momento de incluir un botón en tu aplicación, es preferible optar por formas rectangulares o redondas y desechar alardes de creatividad mal interpretada que puedan dar lugar, por ejemplo, a un botón con forma de pentágono. La manera en la que nuestro cerebro interpreta una interfaz gráfica es más bien del modo: ”Si parece un botón, debe funcionar como un botón”.\n","id":107,"tag":"UI/UX","title":"Compresiones intuitivas","url":"https://metrosetenta.es/blog/compresiones-intuitivas/"},{"content":" Antes de abarcar otras cuestiones relacionadas con el diseño, necesitas planificar la experiencia que va a tener el usuario a través de tu aplicación. Esto es algo que raramente se planifica y, sin embargo, es esencial para el éxito de cualquier web o aplicación de escritorio. Hasta tal punto esto es así, que los usuarios casi siempre optan por las webs o las aplicaciones que les seducen frente a otras más rápidas, robustas, seguras o con mayores posibilidades. Una cuidada plantificación de la experiencia, por parte de los desarrolladores, es el primer paso para conseguir seducir al usuario.\nPara conseguir la experiencia positiva que arriba te comento, hay que pensar en factores como la usabilidad y la motivación. Cuando evitas frustraciones a tu usuario, eliminando posibles retenes en el uso de tu aplicacción, estas potenciando la usabilidad de esta. Pero recuerda algo muy importante: \u0026ldquo;usabilidad\u0026rdquo; no es sinónimo a \u0026ldquo;provoca deseo de uso\u0026rdquo;. Para esto segundo tienes que trabajar con la motivación del usuario, que es un elemento realmente importante. Piensa que puedes diseñar el formulario de obtención de nombre y correo electrónico más horrible y engorroso de la historia de la informática, pero si el usuario obtiene 1000€ por completarlo, la motivación cubrirá con toda seguridad las deficiencias de usabilidad.\nPermíteme darte una idea más antes de finalizar. El mayor éxito que puedes obtener en el diseño de la experiencia de tu aplicación es conseguir que esta resulte significativa y emotiva al usuario. Pero, si cada usuario es distinto ¿como vas a adivinar que le emotiva o tiene significado para él?. Piensa ahora en como puedes personalizar la barra superior de navegadores web para poner, por ejemplo, la foto de tu hijo recién nacido; o piensa en como puedes establecer tu color favorito como el color predominante de tu correo electrónico. ¿Sueles dejar como fondo de tu teléfono móvil el que tiene como predeterminado?. Estos son anzuelos lanzados directa e intencionadamente para captar al usuario a través de su sensibilidad.\n","id":108,"tag":"UI/UX","title":"Planificar la experiencia","url":"https://metrosetenta.es/blog/planificar-la-experiencia/"},{"content":" Por fin has terminado de programar, pero notas que aún falta algo. La aplicación está funcionando correctamente, las soluciones en el código son elegantes y los posibles errores están controlados. La interfaz que interactua con el usuario es agradable de usar, intuitiva y manejable; pero algo no va bien. El número de interesados es bajo, no se registran nuevos usuarios o no descargan tu aplicación. Los usuarios que se han registrado no la usan con frecuencia o migran rápidamente a otras aplicaciones similares, y por supuesto no obtienes de ellos sus recomendaciones para otros usuarios potenciales y, no obtienes un buen feedback. Entonces ¿que es lo que está fallando?.\nHay una faceta del desarrollo de aplicaciones informáticas que está realmente abandonada: conseguir que tus aplicaciones sean atractivas. Los desarrolladores informáticos obviamos muchos de los componentes necesarios para causar en el usuario una experiencia positiva que, posteriormente, se traduzca en el éxito de nuestras aplicaciones. Debemos procurar, a través de un diseño claro y sugerente, que el usuario se sienta cómodo.\n","id":109,"tag":"UI/UX","title":"Aplicaciones atractivas","url":"https://metrosetenta.es/blog/aplicaciones-atractivas/"}]