Mapas interactivos en HTML5 con SnapSVG

HTML5 ha llegado aquí y está para quedarse y puede usarse en prácticamente cualquier sitio. Además según la encuesta del blog HTML5 era uno de los temas en los que estabais más interesados. Hoy vamos a ver como se puede hacer un mapa interactivo fácilmente, compatible con PCs, tabletas y móviles y veremos como los podemos animar.

Haz click en la provincia de Valladolid múltiples veces

SnapSVG

Aquí entra en juego SnapSVG. Se trata de una librería para JavaScript financiada y acogida por Adobe. Es una mejora de la ya popular librería para tratar SVG conocida como RaphaëlJS (ambas librerías son del mismo autor). Sin embargo, SnapSVG aporta muchas mejoras respecto a RaphaëlJS. La fundamental es que SnapSVG permite cargar archivos SVG ya existentes.

snapsvg

Mapas en SVG

Actualmente es fácil encontrar mapas en SVG de cualquier territorio. Sin embargo para que sea fácil trabajar con ellos hay que procurar que estén preparados para interactuar con ellos. Es necesario que las etiquetas <path> posean un atributo id y sea fácilmente reconocible. En el caso del mapa de España que hay al principio, el mapa está muy bien organizado. Las provincias empiezan por pr, los enclaves por en y las islas por is. Así que Valladolid es pr_valladolid y Menorca es is_menorca. Encontrar mapas así ya puede ser más difícil pero no imposible.

Primeros pasos

En nuestro HTML creamos una etiqueta <svg> con un id, por ejemplo id=papel. Ya está. Ahora pasamos al JavaScript.

Primero necesitamos obtener un papel (Paper en la documentación), con la función Snap y un selector CSS obtenemos el papel que ya hemos creado.

Ahora ya podemos usar todo el poder de SnapSVG, pero si queremos trabajar con un SVG ya existente el procedimiento es un poco distinto.

Atributos

Podemos alterar los atributos de estilo de SVG. Para quién no los conozca, funcionan igual que las propiedades CSS pero se aplican de manera distinta. Con SnapSVG podemos cambiar esos atributos en tiempo de ejecución. Por ejemplo, el relleno (propiedad fill).

Figuras simples

Podemos añadir figuras simples de manera muy sencilla

Eventos y animaciones

Ahora viene la parte interesante, eventos y animaciones. SnapSVG soporta varios tipos de evento en cada elemento. Veamos el click simple aunque existe doble click, ratón por encima, táctil (aunque click funciona en pantallas táctiles).

Podemos animar los elementos especificando las propiedades que cambian y su tiempo

SnapSVG es muy potente y permite realizar muchas más operaciones, como elementos arrastrables, grupos, patrones, filtros y más. El objetivo, según Adobe, es ser el jQuery de los documentos SVG.

snapsvg-game

Escalar imagen automáticamente

viewBox

SVG es un formato vectorial así que podemos aumentar el tamaño sin tener que preocuparnos por los píxeles. Sin embargo si simplemente cambias el tamaño del elemento <svg> vía CSS verás que no funciona. Es necesario especificar un atributo viewBox y mantenerlo constante. Básicamente viewBox da las dimensiones reales del lienzo donde se dibuja el SVG. Si cambian width y height y viewBox también entonces la imagen no se escala, simplemente se amplía el área del lienzo. Algunos mapas en SVG no ofrecen viewBox. En ese caso espeficicamos como viewBox el tamaño original del fichero SVG. En el caso de querer ocupar toda la pantalla.

Cordova y Android

SnapSVG se puede usar en Apache Cordova. Sin embargo yo he tenido problemas de rendimiento con la configuración por defecto en Android. Para solventar este problema he tenido que:

Solo así conseguí un rendimiento decente dentro de Cordova.

Ethereum y SmartContracts

En estos últimos años han surgido toda una marea tecnológica siguiendo los principios de la cadena de bloques (blockchain en inglés) popularizada por Bitcoin. En un principio se extendieron las criptodivisas usando esta tecnología, las llamadas altcoins. Algunas se han vuelto muy famosas como Litecoin, Dogecoin, Ripple, Feathercoin, StartCoin, ReddCoin, Dash o incluso un intento de criptodivisa española, la PesetaCoin.

Si revisamos la lista de criptodivisas por capitalización de mercado en CoinMarketCap.com veremos que en el puesto número aparece una que no he mencionado, se trata de Ethereum. Pero no adelantemos acontecimientos.

CoinMarketCap

Hemos dicho que la tecnología de la cadena de bloques se ha usado para diseñar criptodivisas. Sin embergo, recientemente ha aparecido una nueva aplicación de esta tecnología. Los contratos inteligentes (o Smart Contracts).

¿Qué son los contratos inteligentes?

Podemos definir los contratos inteligentes como un tipo de aplicación informática que se encargan de ejecutar una cierta acción si se cumple la condición especificada. Podemos pensar en ellos como un contrato con cláusulas específicas según la casuística. Los contratos inteligentes además serían fácilmente verificables y a su vez seguros. La idea es que dadas unas condiciones, se ejecuten las acciones especificadas, sin ninguna excepción. El concepto de los contratos inteligentes surgió de manos de Nick Szabo en la década de los noventa. Y ahora ya tenemos la primera implementación de aquellas ideas en Ethereum. Un ejemplo muy sencillo de contrato inteligente es una apuesta con un amigo en un partido de fútbol, cada uno apuesta por un equipo y deposita el dinero en el contrato. Cuando el partido haya finalizado el contrato ejecutará la cláusula correspondiente y enviará al dinero al afortunado.

¿Qué es Ethereum?

Si piensas en el Bitcoin como una hoja de cálculo global, piensa en Ethereum como un sistema operativo global

EthereumFrontier

Ethereum es una implementación de los smart contracts basada en la cadena de bloques. Es descentralizado, como Bitcoin. Los aplicaciones (los contratos inteligentes) en Ethereum se ejecutan sin nisiquiera la posibilidad de caída de la red, censura, fraude o intervención de terceras partes. Los contratos inteligentes simplemente se ejecutan, es imposible que no se ejecuten. Esa es la gran ventaja de Ethereum respecto al Internet como lo conocíamos antes.

Las aplicaciones en Ethereum se suben a la cadena de bloques y se ejecutan bajo demanda, con una potencia no muy elevada (piensa en un smartphone de 1999) pero con una cantidad de memoria y una capacidad de almacenamiento permanente ilimitados. Eso no significa que cualquiera pueda hacer lo que quiera con un programa, pues los contratos pueden estar diseñados para ignorar las peticiones hechas desde usuarios desconocidos. En último término, el objetivo de Ethereum es proveer una computación 100% determinista.

EthereumLogo

¿Cómo funciona?

Usar Ethereum no es gratis, el sistema operativo global necesita combustible. Ese combustible es Ether, aunque en muchos sitios se le llama directamente Ethereum por estar ligado a la plataforma. Ether es una criptodivisa al estilo Bitcoin, pero se puede gastar directamente en ejecutar contratos inteligentes en Ethereum. Al igual que en Bitcoin, en Ethereum hay mineros, que ejecutan los contratos para comprobar que todos obtienen el mismo resultado. Esos mineros reciben su recompensa en Ether que pueden usar o vender en sitios como ShapeShift.

Además necesitaremos un cliente para subir y pedir la ejecución de los contratos inteligentes. Hay muchos, voy a hablar de los cuatro más importantes.:

  • Eth: el cliente en C++
  • Geth: el cliente en Go (recomendado)
  • Web3.js: una unión entre el navegador y Ethereum usando la interfaz RPC de otro cliente Ethereum
  • Mist: se trata de un navegador basado en Electrum (o sea, Chromium) que integra las funciones de Ethereum. Podemos interactuar con las DApps directamente si usamos este navegador. Veremos que son las DApps más adelante.

Desde Geth podemos sincronizarnos con la red Ethereum, minar para ganar Ether, ejecutar contratos en la red y subirlos.

Podemos ver como se ejecuta un contrato inteligente en acción en EtherDice, un simple juego de apuestas con dado.

Esta orden se introduce dentro de Geth. Básicamente está realizando un traspaso de fondos desde nuestra cuenta principal (eth.accounts[0], aunque se puede especificar otra si nos sabemos la dirección), el valor de la transacción que es la cantidad de Ether a traspasar. Ether tiene muchos submúltiplos, en este caso usa el Wei. 1 ether = 1000000000000000000 wei. Se especifica la dirección de destino y además el máximo de gas que estaríamos dispuesto a perder en la ejecución (no es posible cuanto va a costar una ejecución). Este valor máximo es el producto del gas por el precio del gas y representa el tope de weis que puede consumir el contrato antes de que se cancele. Con contratos muy probados valdría cualquier valor, pero si estás desarrollando un contrato de vendrá muy bien para que una programación errónea no liquide todos tus fondos antes de tiempo.

Bien, este ejemplo es muy sencillo. De manera más genérica usaríamos la función eth.contract

Siendo la ABI la definición de la interfaz para poder interactuar con el contrato y la dirección es donde reside el contrato en sí. Luego llamamos a la función greet dentro del contrato, puede aceptar parámetros de entrada. Todo esto esta muy bien pero no hemos visto como son realmente los contratos todavía. Un ejemplo muy bueno es Etheria

Etheria

Solidity y la máquina virtual

Los contratos se ejecutan en una máquina virtual llamada EVM (Ethereum Virtual Machine). Esta máquina virtual es Turing completa pero para evitar un colapso (bucles infinitos) tiene en cuenta el gas. Las operaciones en la EVM son lentas, porque cada contrato es ejecutado simultaneamente en el resto de nodos de la red, siendo el resultado final un resultado de consenso de la red. Se han diseñado varios lenguajes que compilan a EVM, pero sin duda el más popular es Solidity.

Este sería un ejemplo de Greeter en Solidity. No voy a explicar la programación en Solidity, ni como se inician los contratos. Si hay demanda popular explicaré como se suben los programas y se inicializan.

DApps

Decentralized Apps, con la tecnología de Ethereum ha surgido un nuevo concepto. Aplicaciones web que se separan del concepto tradicional de cliente-servidor y se ejecutan de manera descentralizada. Estas aplicaciones, aunque siguen necesitando Internet pueden funcionar sin un servidor central si nuestro ordenador dispone de un nodo de Ethereum. Esto es precisamente lo que hace el navegador Mist. Otro aprovechamiento más tradicional de las DApps es dejar un servidor central que corra como nodo de Ethereum y tenga una IP asignada. Sin embargo este servidor central puede ser muy ligero, pues solo sirve de puerta de entrada a la red Ethereum. Este aprovechamiento funcionaría en navegadores tradicionales siempre que los gastos de la red corran a cuenta del administrador de la app. Un ejemplo de DApp que requiere usar el navegador Mist es EthereumWall, la aplicación usa nuestros fondos para su funcionamiento y aunque tiene un servidor central estático para entregar los archivos HTML y el JavaScript, esto no sería necesario pues la lógica la hace la red Ethereum con nuestro nodo local en Mist.

Mist

Conclusión

¿Qué os parecen los contratos inteligentes? ¿Qué os parece la plataforma Ethereum? ¿Tendrá futuro o es una moda pasajera? ¿Crees que puede revolucionar la manera de pensar la web? Comenta, quiero saber tu opinión.

Para más información no dudes en consultar el sitio oficial de Ethereum y el libro oficial

Si crees que lo merece puedes enviarme: BTC(1A2j8CwiFEhQ4Uycsjhr3gQPbJxFk1LRmM), LTC(LXkefu8xYwyD7CcxWRfwHhSRTdk6Sp38Kt), DOGE(D7fvbHocEGS7PeexBV23ktWjgVL1y9RnoK), ReddCoin(RsHAsr6PVs8y4f5pGLS2cApcGpgw15TwUJ)

¿Cómo programar en C (en 2016)?

Este artículo es una traducción del artículo How to C in 2016. Todo el contenido aparece originalmente en aquel artículo, yo solo me he limitado a traducirlo.

c

La primera regla de C es no escribir en C si puedes evitarlo.

Si te ves obligado a escribir en C, deberías seguir las reglas modernas.

C ha estado con nosotros desde principios de los 70. La gente a “aprendido C” en numerosos puntos de su evolución, pero el conocimiento normalmente se para después de aprender. Así pues todo el mundo piensa diferente sobre C según el año en que empezaron a aprenderlo.

Es importante no quedarse paralizado en las “cosas que aprendí en los 80/90” cuando programas en C.

Esta página asume que estás en una plataforma moderna, con estándares modernos y no tienes que mantener una compatibilidad con sistemas antiguos muy elevada. No debemos estar atados a estándares anticuados solo porque algunas compañías rechacen actualizar sistemas con más de 20 años de antigüedad.

Preliminar

Standard C99 (C99 significa “Estándar C de 1999”; C11 significa “Estándar C de 2011”, así que C11 > C99)

  • clang, por defecto
    • C99 es la implementación de C por defecto en clang, no necesita opciones extra
    • Sin embargo esta implementación no es realmente estándar. Si quieres forzar el estándar, usa -std=c99
    • Si quieres usar C11, debes especificar -std=c11
    • clang compila el código fuente más rápidamente que gcc
  • gcc necesita que especifiques -std=c99 o -std=c11
    • gcc compila más lentamente pero a veces genera ejecutables más rápidos
    • gcc-5 establece por defecto -std=gnu11, así que debes seguir especificando una versión estándar c99 o c11.

Optimizaciones

  • -O2, -O3
    • generalmente querrás -O2, pero algunas veces querrás -O3. Prueba tu código con ambos niveles (y entre distintos compiladores) y mantente con los ejecutables más eficientes y rápidos.
  • -Os
    • -Os ayuda si te preocupa la eficiencia de la caché (que debería)

Advertencias

  • -Wall -Wextra -pedantic
    • las nuevas versiones de los compiladores tienen -Wpedantic, pero todavía aceptan el antiguo -pedantic por cuestiones de compatibilidad.
    • durante las pruebas deberías añadir -Werror y -Wshadow en todas tus plataformas
    • puede ser peliagudo enviar a producción con -Werror porque cada plataforma y cada compilador y cada librería pueden emitir distintas advertencias. Probablemente no querrás terminar la compilación entera de un usuario porque su versión de GCC en una plataforma que nunca habías visto se queja de manera nueva y sorprendente.
    • algunas opciones más sofisticadas son -Wstrict-overflow -fno-strict-aliasing
    • especifica -fno-strict-aliasing o estate seguro de que solo accedes a los objetos con el tipo que tuvieron en su definición. Como mucho código en C ya existente se salta lo último es mucho más seguro usar -fno-strict-aliasing particularmente si no controlas todo el código que debes compilar.
    • ahora mismo, clang reporta alguna sintaxis válida como advertencia, así que debes añadir -Wno-missing-field-initializers
    • GCC resolvió este problema después de GCC 4.7

Compilando

  • Unidades de compilación
    • La manera más común de compilar proyectos en C es generar un fichero objeto de cada fichero fuente y unirlo todos al final. Este procedimiento es muy bueno para el desarrollo incremental, pero no lo es para el rendimiento y la optimización. El compilador no puede detectar optimizaciones entre archivos con este método.
  • LTO – Link Time Optimization
    • LTO arregla el problema de las unidades de compilación generando además una representación intermedia que puede ser sujeta de optimizaciones entre archivos. Este sistema ralentiza el tiempo de enlazado significativamente pero make -j puede ayudar.
    • clang LTO (guía)
    • gcc LTO
    • Ahora mismo, 2016, clang y gcc soportan LTO simplemente añadiendo -flto en las opciones tanto de compilación como de enlazado.
    • LTO todavía necesita asentarse. A veces, si tu programa tiene código que no usas directamente pero alguna librería sí, LTO puede borrarlo, porque detecta que en tu código no se hace nunca una llamada a esa función.

Arquitectura

  • -march=native
    • Le da al compilador permiso para usar todas las características de tu CPU
    • otra vez, compara el funcionamiento con los distintos tipos de optimización y que no tengan efectos secundarios.
  • msse2 y -msse4.2 pueden ser útiles si necesitas características que no están disponibles en el sistema desde el que compilas.

Escribiendo código

Tipos

Si te encuentras escribiendo char o int o short o long o unsigned, lo estás haciendo mal.

Para los programas modernos deberías incluir #include <stdint.h> y usar los tipos estándar.

Los tipos estándar comunes son:

  • int8_t, int16_t, int32_t, int64_t – enteros con signo
  • uint8_t, uint16_t, uint32_t, uint64_t – enteros sin signo
  • float – coma flotante de 32 bits
  • double – coma flotante de 64 bits

Te darás cuenta que ya no tenemos char. char está malinterpretado en C.

Los desarrolladores han abusado de char para representar un byte incluso cuando hacen operaciones sin signo. Es mucho más limpio usar uint8_t para representar un único byte sin signo y uint8_t * para representar una secuencia de bytes sin signo.

Una excepción a nunca-char

El único uso aceptable de char en 2016 es si una API ya existente necesita char (por ejemplo, strncat, printf,…) o si estás inicializando una cadena de texto de solo lectura (const char *hello = "hello";) porque el tipo de C para cadenas de texto sigue siendo char *

Además, en C11 tenemos soporte Unicode nativo y el tipo para cadenas UTF-8 sigue siendo char * incluso para secuencias multibyte como const char *abcgrr = u8"abc?";.

El signo

A estas alturas de la película no deberías escribir unsigned nunca en tu código. Podemos escribir sin usar la fea convención de C para tipos multi-palabra que restan legibilidad. ¿Quién quiere escribir unsigned long long int cuando puede escribir uint64_t? Los tipos de <stdint.h> son más explícitos, más exactos en su significado y son más compactos en su escritura y su legibilidad.

Pero podrías decir, “¡Necesito hacer cast a punteros a long para realizar aritmética de punteros sucia!”

Podrías decirlo. Pero estás equivocado.

El tipo correcto para aritmética de punteros es uintptr_t definido en <stddef.h>.

En vez de:

Usa:

Además:

Tipos dependientes del sistema

Sigues argumentando, “¡en una plataforma de 32 bits quiero longs de 32 bits y en una de 64 bits quiero longs de 64 bits!”

Si nos saltamos la idea de que estás introduciendo deliberadamente código que dificulta la comprensión del código al tener tamaños distintos dependiendo de la plataforma, aún no tendrías necesidad de usar long.

En estas situaciones debes usar intptr_t que se define según la plataforma en que te encuentres.

En plataformas de 32 bits, intptr_t es int32_t.

En plataformas de 64 bits, intptr_t es int64_t.

intprt_t también tiene una versión sin signo uintptr_t.

Para almacenar diferencias entre punteros, tenemos el ptrdiff_t.

Máxima capacidad

¿Quieres tener el entero con mayor capacidad de tu sistema?

La gente tiene a usar el más grande que conozca, en este caso uint64_t nos podrá almacenar el número más grande. Pero hay una manera más correcta de garantizar que podrá contener cualquier otro valor que se esté utilizando en el programa.

El contenedor más seguro para cualquier entero es intmax_t (también uintmax_t). Puedes asignar cualquier entero con signo a intmax_t sin pérdida de precisión. Puedes asignar cualquier entero sin signo a uintmax_t sin pérdida de precisión.

Ese otro tipo

Otro tipo que depende del sistema y es usado comúnmente es size_t.

size_t se define como “un entero capaz de contener el mayor tamaño de memoria disponible”.

En el lado práctico, size_t es el tipo que devuelve el operador sizeof.

En cualquier caso, la definición de size_t es prácticamente la misma que la de uintptr_t en todas las plataformas modernas.

También existe ssize_t que es size_t con signo y que devuelve -1 en caso de error. (Nota: ssize_t es POSIX así que no se aplica esto en Windows).

Así que, ¿debería usar sisze_t para aceptar tamaños dependientes del sistema en mis funciones? Sí, cualquier función que acepte un número de bytes puede usar size_t.

También lo puedes usar en malloc, y ssize_t es usado en read() y write() (solo en sistemas POSIX).

Mostrando tipos

Nunca debes hacer cast para mostrar el valor de los tipos. Usa siempre los especificadores adecuados.

Estos incluyen, pero no están limitados a:

  • size_t%zu
  • ssize_t%zd
  • ptrdiff_t%td
  • valor del puntero – %p (muestra el valor en hexadecimanl, haz cast a (void *) primero)
  • los tipos de 64 bits deben usar las macros PRIu64 (sin signo) y PRId64 (con signo)
    • es imposible especificar un valor correcto multiplataforma sin la ayuda de estas macros
  • intptr_t"%" PRIdPTR
  • uintptr_t"%" PRIuPTR
  • intmax_t"%" PRIdMAX
  • uintmax_t"%" PRIuMAX

Recordar que PRI* son macros, y las macros se tienen que expandir, no pueden estar dentro de una cadena de texto. No puedes hacer:

deberías usar:

Tienes que poner el símbolo ‘%’ dentro de la cadena de texto, pero el especificador fuera.

C99 permite declaraciones de variables en cualquier sitio

Así que no hagas esto:

Aunque si tienes un bucle muy exigente (un tight loop) las declaraciones a mitad de camino pueden ralentizar el bucle.

C99 permite a los bucles for declarar los contadores en la misma línea

Así que no hagas esto

Haz esto:

La mayoría de compiladores soportan #pragma once

Así que no hagas esto:

haz esto:

#pragma once le dice al compilador que solo incluya el archivo de cabecera una vez y no necesitas escribir esas tres líneas para evitarlo manualmente. Este pragma esta soportado por todos los compiladores modernos en todas las plataformas y está recomendado por encima de nombrar manualmente las cláusulas.

Para más detalles, observa la lista de compiladores que lo soportan en pragma once

C permite la inicialización estática de arrays ya asignados memoria

Así que no hagas:

Haz esto:

C permite la inicialización estática de structs ya asignados en memoria

Así que no hagas esto:

Haz esto:

NOTA IMPORTANTE: Si tu estructura tiene padding (relleno extra para coincidir con el alineamiento del procesador, todas por defecto en GCC, __attribute__((__packed__)) para desactivar este comportamiento), el método de {0} no llenará de ceros los bits de padding. Si necesitases rellenar todo de ceros, incluido los bits de padding, deberás seguir usando memset(&localThing, 0, sizeof(localThing)).

Si necesitas reinicializar un struct puedes declarar un struct global a cero para asignar posteriormente.

C99 permite arrays de longitud variable (VLA)

Así que no hagas esto:

Haz esto:

NOTA IMPORTANTE: Los VLA suelen situarse en el stack, junto a los arrays normales. Así que si no haces arrays de 3 millones de elementos normalmente, tampoco los hagas con esta sintaxis. Estos no son listas escalables tipo Python o Ruby. Si especificas una longitud muy grande en tiempo de ejecución tu programa podría empezar a hacer cosas raras. Los VLA están bien para situaciones pequeñas, de un solo uso y no se puede confiar en que escalen correctamente.

Hay gente que considera la sintaxis de VLA un antipatrón puesto que puede cerrar tu programa fácilmente.

NOTA: Debes estar seguro que arrayLength tiene un tamaño adecuado (menos de un par de KB se te darán para VLA). No puede asignar arrays enormes pero en casos concretos, es mucho más sencillo usar las capacidades de C99 VLA en vez de pringarse con malloc/free.

NOTA DOBLE: como puedes ver no hay ninguna verificación de entrada al usar VLA, así que cuida mucho el uso de las VLA.

C99 permite indicar parámetros de punteros que no se solapan

Mira la palabra reservada restrict (a veces, __restrict)

Tipos de los parámetros

Si una función acepta arbitrariamente datos y longitud, no restrinjas el tipo del parámetro.

Así que no hagas:

Haz esto:

Los tipos de entrada definen la interfaz de tu código, no lo que tu código hace con esos parámetros. La interfaz del código dice “aceptar un array de bytes y una longitud”, así que no quieres restringirles usar solo uint8_t. Quizá tus usuarios quieran pasar char * o algo más inesperado.

Al declarar el tipo de entrada como void * y haciendo cast dentro de tu función, los usuarios ya no tienen que pensar en abstracciones dentro de tu librería.

Algunos lectores afirman que podría haber problemas de alineamiento con este ejemplo, pero como estamos accediendo a los bytes uno por uno no hay problema en realidad. Si por el contrario tuviéramos tipos más grandes tendríamos que vigilar posibles problemas de alineamiento, mirar Unaligned Memory Access

Parámetros de devolución

C99 nos da el poder de usar <stdbool.h> que define true como 1 y false como 0.

Para valores de éxito/error, las funciones deben devolver true o false, nunca un entero especificando manualmente 1 y 0 (o peor, 1 y -1 (¿o era 0 éxito y 1 error? ¿o era 0 éxito y -1 error?))

Si una función modifica el valor de un parámetro de entrada, no lo devuelvas, usa dobles punteros.

Así que no hagas:

Haz esto:

O incluso mejor:

Formato

El estilo del código es muy importante.

Si tu proyecto tiene una guía de formato de 50 páginas, nadie te ayudará, pero si tu código tampoco se puede leer, nadie querrá ayudarte.

La solución es usar siempre un programa para formatear el código.

El único formateador de código usable en el 2016 es clang-format. clang-format tiene los mejores ajustes por defecto y sigue en desarrollo activo.

Aquí está el script que uso para formatear mi código:

Luego lo llamo

La opción -i indica que sobrescriba los archivos con los cambios que realice, en vez de generar nuevos archivos o crear copias.

Si tienes muchos archivos, puedes hacer la operación en paralelo

Y ahora el contenido del script cleanup-tidy aquí.

clang-tidy es una herramienta de refactorización basada en reglas. Las opciones de arriba activan dos arreglos:

  • readability-braces-around-statements – fuerza a que todos los if/while/for tengan el cuerpo rodeado por llaves.
    • ha sido un error que C permitiese las llaves opcionales. Son causa de muchos errores, sobre todo al mantener el código con el tiempo, así que aunque el compilador te lo acepte, no dejes que ocurra.
  • misc-macro-parentheses – añade automáticamente paréntesis alrededor de los parámetros usados en una macro.

clang-tidy es genial cuando funciona, pero para código complejo puede trabarse. Además, clang-tidy no formatea, así que necesitarás llamar a clang-format para formatear y alinear las nuevas llaves y demás cosas.

Legibilidad

Comentarios

Comentarios con sentido, dentro del código, no muy extensos.

Estructura de archivos

Intenta no tener archivos de más de 1000 líneas (1500 como mucho)

Otros detalles

Nunca uses malloc

Usa siempre calloc. No hay penalización de rendimiento por tener la memoria limpia, llena de ceros.

Los lectores han informado de un par de cosas:

  • calloc sí tiene un impacto en el rendimiento en asignaciones enormes
  • calloc sí tiene un impacto en el rendimiento en plataformas extrañas (sistemas empotrados, videoconsolas, hardware de 30 años de antigüedad, …)
  • una buena razón para no usar malloc() es que no puede comprobar si hay un desbordamiento y es un potencial fallo de seguridad

Todos son buenos puntos, razón por la que siempre debes probar el funcionamiento en todos los sistemas que puedas.

Una ventaja de usar calloc() directamente es que, al contrario que malloc(), calloc() puede comprobar un desbordamiento porque suma todo el tamaño necesario antes de que lo pida.

Algunas referencias al uso de calloc() se pueden encontrar aquí:

Sigo recomendando usar siempre calloc() para la mayoría de escenarios en 2016.

Nunca uses memset (si puedes evitarlo)

Nunca hagas memset(ptr, 0, len) cuando puedes inicializar una estructura (o un array) con {0}.

Generics en C11

C11 ha añadido los Generics. Funcionan como un switch, que distingue entre los tipos y dependiendo del valor que se le de devuelve una u otra cosa. Por ejemplo:

Kovel 1.0, diseña modelos en 3D usando vóxeles

Hoy me he decidido y finalmente he decidido publicar la primera versión pública de Kovel. Estuve trabajando en esta aplicación a finales de 2015 y no he hecho muchos cambios últimamente por lo que voy a publicarlo antes de que ¡se me olvide!

¿Qué es Kovel?

Kovel es una aplicación para Linux, Haiku y Windows para diseñar modelos en 3D usando el concepto de los vóxeles. ¿Qué es un vóxel? Se ha definido un vóxel como un píxel con volumen, es decir, el equivalente a un píxel en entornos tridimensionales. Los vóxeles nunca existieron (los gráficos 3D no funcionan a través de vóxeles, son siempre vectoriales) y son simplemente un concepto artístico, muy sencillo de usar.

Kovel-1

KovelRotate

¿Cómo funciona?

Es muy sencillo. Al crear un nuevo archivo seleccionaremos el tamaño de la rejilla. Por defecto la rejilla está puesta en 5. Esto quiere decir que el modelo tendrá una dimensión máxima de 5x5x5. Ahora seleccionamos el material. En esta versión solo hay colores puros como materiales, en futuras versiones habrá texturas también. Ahora simplemente hacemos click en los elementos de la rejilla. Vemos como se pone un vóxel en la posición que hemos indicado en la rejilla. Para subir y bajar de piso usamos los botones Up y Down. Podemos rotar y hacer zoom al modelos para centrarnos en determinadas áreas. En cualquier momento podemos deshacer. Los modelos se guardan como ficheros KVL. Es un formato que he tenido que inventar, es compacto y a la vez muy fácil de manipular. Está basado en BSON, la implementación binaria de JSON hecha por la gente de MongoDB. Pero además podemos exportar nuestras creaciones al formato Collada DAE (se puede abrir con Blender, Maya, etc).

BlenderKovel

¿Dónde puedo obtenerlo?

Todo el código fuente está en GitHub y se compila usando CMake. Pero además hay disponible un PPA para usuarios de Ubuntu. Lamentablemente por temas de dependencias con CMake, solo está disponible en Wily (15.10) y Xenial (16.04), aunque si os descargais el DEB manualmente quizá os funcione también en Trusty (14.04) y Jessie (Debian 8). Los usuarios de Windows tienen un ejecutable también para 64 bits (no he compilado para 32 todavía) pero requiere las DLL de wxWidgets 3.0. Los usuarios de Haiku tendrán que conformarse de momento con el código fuente. Todas las descargas están en la página oficial de Kovel (incluidas las DLL).

KovelHaiku

¿Algo más?

Sí, aparte de Kovel, la aplicación gráfica, también existe kovelcli, la interfaz de línea de comandos. Permite realizar la conversión de KVL a Collada DAE de manera automática.

Finalmente, doy las gracias a todos los que vayan a probar Kovel, un simple comentario con sugerencias o de agradecimiento si os ha servido vale mucho para mí. ¡Felices vóxeles!

Bienvenido 2016, bienvenido kaizen

¡Feliz año! ¡Feliz 2016! Ya os he felicitado, ahora vamos a lo serio.

2016 Imagen de Marcela

¿Cómo mejorar el blog?

Cada vez me interesa más este blog, cada vez le tengo más cariño, pero creo que no se está aprovechando su potencial. Así que, y siguiendo las pautas de la mejora continua (KAIZEN), os voy a pedir unas cosillas:

  • Rellenar la encuesta que se encuentra más abajo
  • Compartir el blog en redes sociales
  • Suscribirte por correo
  • (y ya si donas por PayPal, ChangeTip o Flattr, eres un fiera)

El objetivo es que el blog crezca, no en visitas, lo cual me importa pero no tanto como en la comunidad, una comunidad activa alrededor del blog.